16
16
# You should have received a copy of the GNU General Public License along with
17
17
# this program. If not, see <http://www.gnu.org/licenses/>.
18
18
# -----------------------------------------------------------------------------
22
20
This class implements a Gtk.TextView but with many other features
23
21
like hyperlink and other stuff special for GTG
39
37
from GTG.gtk.editor import taskviewserial
40
38
from GTG.tools import urlregex
42
separators = [' ', ',', '\n', '\t', '!', '?', ';', '\0','(',')']
40
separators = [' ', ',', '\n', '\t', '!', '?', ';', '\0', '(', ')']
43
41
#those separators are only separators if followed by a space. Else, they
44
42
#are part of the word
45
specials_separators = ['.','/']
43
specials_separators = ['.', '/']
51
49
class TaskView(Gtk.TextView):
52
50
__gtype_name__ = 'HyperTextView'
53
__gsignals__ = {'anchor-clicked': (GObject.SignalFlags.RUN_LAST, \
51
__gsignals__ = {'anchor-clicked': (GObject.SignalFlags.RUN_LAST,
54
52
None, (str, str, int))}
55
53
__gproperties__ = {
56
'link': (GObject.TYPE_PYOBJECT, 'link color',\
54
'link': (GObject.TYPE_PYOBJECT, 'link color',
57
55
'link color of TextView', GObject.PARAM_READWRITE),
58
'failedlink': (GObject.TYPE_PYOBJECT, 'failed link color',\
56
'failedlink': (GObject.TYPE_PYOBJECT, 'failed link color',
59
57
'failed link color of TextView', GObject.PARAM_READWRITE),
60
'active': (GObject.TYPE_PYOBJECT, 'active color', \
58
'active': (GObject.TYPE_PYOBJECT, 'active color',
61
59
'active color of TextView', GObject.PARAM_READWRITE),
62
'hover': (GObject.TYPE_PYOBJECT, 'link:hover color', \
60
'hover': (GObject.TYPE_PYOBJECT, 'link:hover color',
63
61
'link:hover color of TextView', GObject.PARAM_READWRITE),
64
'tag': (GObject.TYPE_PYOBJECT, 'tag color', \
62
'tag': (GObject.TYPE_PYOBJECT, 'tag color',
65
63
'tag color of TextView', GObject.PARAM_READWRITE),
66
'done': (GObject.TYPE_PYOBJECT, 'link color', \
64
'done': (GObject.TYPE_PYOBJECT, 'link color',
67
65
'link color of TextView', GObject.PARAM_READWRITE),
68
'indent': (GObject.TYPE_PYOBJECT, 'indent color', \
66
'indent': (GObject.TYPE_PYOBJECT, 'indent color',
69
67
'indent color of TextView', GObject.PARAM_READWRITE),
87
85
self.buff = self.get_buffer()
88
86
self.req = requester
90
self.link = {'background': 'white', 'foreground': '#007bff', \
91
'underline': Pango.Underline.SINGLE, \
92
'strikethrough': False}
93
self.failedlink = {'background': 'white', 'foreground': '#ff5454', \
94
'underline': Pango.Underline.NONE, \
95
'strikethrough': False}
96
self.done = {'background': 'white', 'foreground': 'gray',\
88
self.link = {'background': 'white', 'foreground': '#007bff',
89
'underline': Pango.Underline.SINGLE,
90
'strikethrough': False}
91
self.failedlink = {'background': 'white', 'foreground': '#ff5454',
92
'underline': Pango.Underline.NONE,
93
'strikethrough': False}
94
self.done = {'background': 'white', 'foreground': 'gray',
97
95
'strikethrough': True}
98
self.active = {'background': 'light gray', 'foreground': '#ff1e00',\
96
self.active = {'background': 'light gray', 'foreground': '#ff1e00',
99
97
'underline': Pango.Underline.SINGLE}
100
98
self.hover = {'background': 'light gray'}
101
99
self.tag = {'background': "#FFea00", 'foreground': 'black'}
107
105
# but set in self.modified)
108
106
self.table = self.buff.get_tag_table()
110
self.title_tag = self.buff.create_tag("title", foreground="#007bff", \
108
self.title_tag = self.buff.create_tag("title", foreground="#007bff",
111
109
scale=1.6, underline=1)
112
110
self.title_tag.set_property("pixels-above-lines", 10)
113
111
self.title_tag.set_property("pixels-below-lines", 10)
126
124
self.connect('motion-notify-event', self._motion)
127
self.connect('focus-out-event', lambda w, \
128
e: self.table.foreach(self.__tag_reset, e.window))
129
self.insert_sigid = self.buff.connect('insert-text', \
125
self.connect('focus-out-event',
126
lambda w, e: self.table.foreach(self.__tag_reset, e.window))
127
self.insert_sigid = self.buff.connect('insert-text',
130
128
self._insert_at_cursor)
131
self.delete_sigid = self.buff.connect("delete-range", self._delete_range)
132
self.connect('copy-clipboard', self.copy_clipboard,"copy")
133
self.connect('cut-clipboard', self.copy_clipboard,"cut")
129
self.delete_sigid = self.buff.connect("delete-range",
131
self.connect('copy-clipboard', self.copy_clipboard, "copy")
132
self.connect('cut-clipboard', self.copy_clipboard, "cut")
134
133
self.connect('paste-clipboard', self.paste_clipboard)
136
135
self.connect('drag-data-received', self.drag_receive)
158
157
self.get_subtasks = None
159
158
self.remove_subtask =None
160
159
self.__refresh_cb = None # refresh the editor window
161
self.open_task = None # open another task
160
self.open_task = None # open another task
162
161
self.new_subtask_callback = None # create a subtask
163
162
self.save_task = None #This will save the task without refreshing all
187
186
#editable means that the user can edit the taskview
188
187
#this is initially set at False and then to True once the editor window
190
#this is used to avoid saving the task when the window is still not displayed
189
#this is used to avoid saving the task when the window is still
191
191
def set_editable(self, boule):
192
192
self.editable = boule
374
376
tex = buff.get_text(i_s, i_e, True)
376
378
self.req.get_task(subtask).set_title(tex)
377
texttag = self.create_anchor_tag(buff, subtask, text=tex, typ="subtask")
379
texttag = self.create_anchor_tag(buff, subtask, text=tex,
378
381
texttag.is_subtask = True
379
382
texttag.child = subtask
380
383
#This one is for marks
385
388
buff.delete_mark(e)
387
390
def create_indent_tag(self, buff, level):
388
tag = buff.create_tag(None, **self.get_property('indent'))#pylint: disable-msg=W0142
391
#pylint: disable-msg=W0142
392
tag = buff.create_tag(None, **self.get_property('indent'))
389
393
tag.is_indent = True
390
394
tag.indent_level = level
412
416
if hasattr(tt, 'is_tag'):
414
418
firstline.forward_to_line_end()
415
#Now we should check if the current char is a separator or not
416
#Currently, we insert a space
419
# Now we should check if the current char is
421
# Currently, we insert a space
417
422
self.insert_text(" ", firstline)
418
#Now we check if this newline is empty (it contains only " " and ",")
423
# Now we check if this newline is empty
424
# (it contains only " " and ",")
420
426
# endline = firstline.copy()
421
427
# if not endline.ends_line():
431
437
self.insert_text("\n", firstline)
432
438
firstline = self.buff.get_iter_at_line(1)
433
439
line_mark = self.buff.create_mark("firstline", firstline, False)
434
#self.tv.insert_at_mark(buf, line_mark,"\n")
440
#self.tv.insert_at_mark(buf, line_mark, "\n")
435
441
ntags = len(tag_list)
436
442
for t in tag_list:
437
443
ntags = ntags - 1
438
444
self.insert_at_mark(self.buff, line_mark, t)
440
self.insert_at_mark(self.buff, line_mark,",")
446
self.insert_at_mark(self.buff, line_mark, ",")
441
447
self.buff.delete_mark(line_mark)
442
448
self.modified(full=True)
493
499
stripped = title.strip(' \n\t')
496
### PRIVATE FUNCTIONS ##########################################################
502
### PRIVATE FUNCTIONS #####################################################
499
503
#This function is called so frequently that we should optimize it more.
500
504
def modified(self, buff=None, full=False, refresheditor=True):
501
505
"""Called when the buffer has been modified.
541
545
#subt_list = self.get_subtasks()
542
546
#First, we remove the olds tags
544
549
def subfunc(texttag, data=None): #pylint: disable-msg=W0613
545
550
if hasattr(texttag, 'is_subtask'):
546
551
tag_list.append(texttag)
547
553
table.foreach(subfunc, None)
548
554
start, end = buff.get_bounds()
549
555
for t in tag_list:
586
592
#First, we remove the olds tags
588
594
table = buff.get_tag_table()
589
596
def subfunc(texttag, data=None):
590
597
if hasattr(texttag, 'is_anchor'):
591
598
tag_list.append(texttag)
592
600
table.foreach(subfunc, None)
593
601
for t in tag_list:
594
602
buff.remove_tag(t, start, end)
609
617
# For short URL we must add http:// prefix
610
618
if text == "www":
611
619
url = "http://" + url
612
texttag = self.create_anchor_tag(buff, url, text=None, typ="http")
620
texttag = self.create_anchor_tag(buff, url, text=None,
614
623
it.forward_chars(m.end())
615
624
buff.apply_tag(texttag, prev, it)
625
634
nbr = url.split("#")[1]
627
636
if url.startswith("bug #") or url.startswith("lp #"):
628
topoint = "https://launchpad.net/bugs/%s" %nbr
637
topoint = "https://launchpad.net/bugs/%s" % nbr
629
638
elif url.startswith("bgo #"):
630
topoint = "http://bugzilla.gnome.org/show_bug.cgi?id=%s" %nbr
639
topoint = "http://bugzilla.gnome.org/" + \
640
"show_bug.cgi?id=%s" % nbr
631
641
elif url.startswith("bko #"):
632
topoint = "https://bugs.kde.org/show_bug.cgi?id=%s" %nbr
642
topoint = "https://bugs.kde.org/show_bug.cgi?id=%s" \
633
644
elif url.startswith("fdo #"):
634
topoint = "http://bugs.freedesktop.org/show_bug.cgi?id=%s" %nbr
645
topoint = "http://bugs.freedesktop.org/" + \
646
"show_bug.cgi?id=%s" % nbr
636
texttag = self.create_anchor_tag(buff,\
648
texttag = self.create_anchor_tag(buff,
637
649
topoint, text=None, typ="http")
638
650
buff.apply_tag(texttag, prev, it)
662
674
mark1 = buff.get_mark(tagname)
664
676
offset1 = buff.get_iter_at_mark(mark1).get_offset()
665
if start.get_offset() <= offset1 <= end.get_offset():
677
if start.get_offset() <= offset1 <= \
666
679
buff.delete_mark_by_name(tagname)
667
680
mark2 = buff.get_mark("/%s"%tagname)
669
682
offset2 = buff.get_iter_at_mark(mark2).get_offset()
670
if start.get_offset() <= offset2 <= end.get_offset():
683
if start.get_offset() <= offset2 <= \
671
685
buff.delete_mark_by_name("/%s"%tagname)
672
686
it.forward_char()
674
688
# Set iterators for word
675
689
word_start = start.copy()
676
word_end = start.copy()
690
word_end = start.copy()
678
692
# Set iterators for char
679
693
char_start = start.copy()
680
char_end = start.copy()
694
char_end = start.copy()
681
695
char_end.forward_char()
684
698
# Iterate over characters of the line to get words
685
699
while char_end.compare(end) <= 0:
686
700
do_word_check = False
687
my_char = buff.get_text(char_start, char_end, True)
701
my_char = buff.get_text(char_start, char_end, True)
688
702
if my_char not in separators:
689
703
last_char = my_char
690
704
word_end = char_end.copy()
710
724
#and it shouldn't start with @@ (bug 531553)
711
725
if len(my_word) > 1 and my_word[0] == '@' \
712
726
and not my_word[1] == '@':
713
#self.apply_tag_tag(buff, my_word, word_start, word_end)
727
#self.apply_tag_tag(buff, my_word, word_start,
714
729
#We will add mark where tag should be applied
715
730
buff.create_mark(my_word, word_start, True)
716
731
buff.create_mark("/%s"%my_word, word_end, False)
722
737
# We set new word boundaries
723
738
word_start = char_end.copy()
724
word_end = char_end.copy()
739
word_end = char_end.copy()
726
741
# Stop loop if we are at the end
727
742
if char_end.compare(end) == 0:
801
818
#now we really delete the selected stuffs
802
819
selec = self.buff.get_selection_bounds()
804
# print "deleted text is ##%s##" %self.buff.get_text(selec[0], selec[1])#(start, end)
821
# print "deleted text is ##%s##" %self.buff.get_text(selec[0],
822
# selec[1])#(start, end)
805
823
# self.buff.disconnect(self.delete_sigid)
806
824
# self.disconnect(self.backspace_sigid)
807
825
# self.buff.stop_emission("delete-range")
811
829
# end.forward_char()
812
830
# self.buff.backspace(end, False, True)
813
# self.delete_sigid = self.buff.connect("delete-range", self._delete_range)
831
# self.delete_sigid = self.buff.connect("delete-range",
832
# self._delete_range)
814
833
# self.backspace_sigid = self.connect("backspace", self.backspace)
815
834
#We return false so the parent still get the signal
818
#Apply the title and return an iterator after that title.buff.get_iter_at_mar
819
837
def _apply_title(self, buff, refresheditor=True):
820
start = buff.get_start_iter()
821
end = buff.get_end_iter()
839
Apply the title and return an iterator after that
840
title.buff.get_iter_at_mar
842
start = buff.get_start_iter()
843
end = buff.get_end_iter()
823
845
linecount = buff.get_line_count()
825
847
# Apply the title tag on the first line
831
853
# Applying title on the first line
832
854
title_end = buff.get_iter_at_line(line_nbr-1)
833
855
title_end.forward_to_line_end()
834
stripped = buff.get_text(title_start, title_end, True).strip('\n\t ')
856
stripped = buff.get_text(title_start, title_end, True)
857
stripped = stripped.strip('\n\t ')
835
858
# Here we ignore lines that are blank
836
859
# Title is the first written line
837
860
while line_nbr <= linecount and not stripped:
839
title_end = buff.get_iter_at_line(line_nbr-1)
862
title_end = buff.get_iter_at_line(line_nbr-1)
840
863
title_end.forward_to_line_end()
841
stripped = buff.get_text(title_start, title_end, True).strip('\n\t ')
864
stripped = buff.get_text(title_start, title_end, True)
865
stripped = stripped.strip('\n\t ')
842
866
# Or to all the buffer if there is only one line
844
868
title_end = end.copy()
849
873
self.refresh(buff.get_text(title_start, title_end, True).strip('\n\t'))
854
876
def __newsubtask(self, buff, title, line_nbr, level=1):
855
877
anchor = self.new_subtask_callback(title)
856
878
end_i = self.write_subtask(buff, line_nbr, anchor, level=level)
878
900
#be in the subtask title
879
901
start_i = buff.get_iter_at_line(line_nbr)
880
902
start_i.forward_to_line_end()
881
buff.insert(start_i,"\n")
903
buff.insert(start_i, "\n")
882
904
#Ok, now we can start working
883
905
start_i = buff.get_iter_at_line(line_nbr)
884
end_i = start_i.copy()
906
end_i = start_i.copy()
885
907
#We go back at the end of the previous line
886
908
# start_i.backward_char()
887
909
# #But only if this is not the title.
889
911
# if start_i.has_tag(self.title_tag):
890
912
# start_i.forward_char()
891
913
# insert_enter = False
892
start = buff.create_mark("start", start_i, True)
914
start = buff.create_mark("start", start_i, True)
893
915
end_i.forward_line()
894
end = buff.create_mark("end", end_i, False)
916
end = buff.create_mark("end", end_i, False)
895
917
buff.delete(start_i, end_i)
896
918
start_i = buff.get_iter_at_mark(start)
897
919
self.insert_indent(buff, start_i, level, enter=insert_enter)
939
962
if line == self.buff.get_line_count():
940
963
itera.forward_to_line_end()
941
964
mark = self.buff.create_mark(None, itera, True)
942
self.buff.insert(itera,"\n")
965
self.buff.insert(itera, "\n")
943
966
itera = self.buff.get_iter_at_mark(mark)
944
967
self.buff.delete_mark(mark)
950
973
if itera.starts_line():
951
974
mark = self.buff.create_mark(None, itera, True)
952
self.buff.insert(itera,"\n")
975
self.buff.insert(itera, "\n")
953
976
itera = self.buff.get_iter_at_mark(mark)
954
977
self.buff.delete_mark(mark)
980
1003
#It will be later replaced by the good one with right gravity
981
1004
temp_mark = self.buff.create_mark("temp", start_i, True)
983
end = buff.create_mark("end", start_i, False)
1006
end = buff.create_mark("end", start_i, False)
985
buff.insert(start_i,"\n")
1008
buff.insert(start_i, "\n")
987
1010
#Moving the end of subtask mark to the position of the temp mark
997
1020
#This is normally not needed and purely defensive
998
1021
if itera.get_line() <= 0:
999
1022
itera = buff.get_iter_at_line(1)
1000
start = buff.create_mark("start", itera, True)
1023
start = buff.create_mark("start", itera, True)
1001
1024
indentation = ""
1002
1025
#adding two spaces by level
1010
1033
self.__apply_tag_to_mark(start, end, tag=indenttag)
1014
1036
def __apply_tag_to_mark(self, start, end, tag=None, name=None):
1015
1037
start_i = self.buff.get_iter_at_mark(start)
1016
1038
end_i = self.buff.get_iter_at_mark(end)
1031
1053
buff.insert(ite, text)
1034
1055
def _get_indent_level(self, itera):
1035
line_nbr = itera.get_line()
1056
line_nbr = itera.get_line()
1036
1057
start_line = itera.copy()
1037
1058
start_line.set_line(line_nbr)
1038
1059
tags = start_line.get_tags()
1050
1071
#First, we analyse the selection to put in our own
1051
1072
#GTG clipboard a selection with description of subtasks
1052
bounds = self.buff.get_selection_bounds()
1073
bounds = self.buff.get_selection_bounds()
1055
start, stop = self.buff.get_selection_bounds()
1076
start, stop = self.buff.get_selection_bounds()
1057
1078
self.clipboard.copy(start, stop, bullet=self.bullet1)
1109
1130
#First, we will get the actual indentation value
1110
1131
#The nbr just before the \n
1111
line_nbr = itera.get_line()
1132
line_nbr = itera.get_line()
1112
1133
start_line = itera.copy()
1113
1134
start_line.set_line(line_nbr)
1114
end_line = itera.copy()
1135
end_line = itera.copy()
1115
1136
tags = start_line.get_tags()
1116
1137
subtask_nbr = None
1117
1138
current_indent = self._get_indent_level(itera)
1160
1181
#the "-" might be after a space
1161
1182
#Python 2.5 should allow both tests in one
1162
1183
if current_indent == 0:
1163
if (line.startswith('-') or line.startswith(' -')) and line.lstrip(' -').strip() != "":
1184
if (line.startswith('-') or line.startswith(' -')) \
1185
and line.lstrip(' -').strip() != "":
1164
1186
line = line.lstrip(' -')
1165
end_i = self.__newsubtask(self.buff, line, line_nbr)
1187
end_i = self.__newsubtask(self.buff, line,
1166
1189
#Here, we should increment indent level
1167
1190
#If we inserted enter in the middle of a line
1168
1191
if restofline and restofline.strip() != "":
1169
1192
#it means we have two subtask to create
1170
1193
if self.buff.get_line_count() > line_nbr+1:
1171
1194
#but don't merge with the next line
1172
itera = self.buff.get_iter_at_line(line_nbr+1)
1173
self.buff.insert(itera,"\n\n")
1174
self.__newsubtask(self.buff, restofline,\
1195
itera = self.buff.get_iter_at_line(
1197
self.buff.insert(itera, "\n\n")
1198
self.__newsubtask(self.buff, restofline,
1177
self.insert_indent(self.buff, end_i, 1, enter=True)
1201
self.insert_indent(self.buff, end_i, 1,
1178
1203
tv.emit_stop_by_name('insert-text')
1180
self.buff.insert(itera,"\n")
1205
self.buff.insert(itera, "\n")
1181
1206
tv.emit_stop_by_name('insert-text')
1183
1208
#Then, if indent > 0, we increment it
1195
1220
#we first put the subtask one line below
1196
1221
itera2 = self.buff.get_iter_at_line(line_nbr)
1197
self.buff.insert(itera2,"\n")
1222
self.buff.insert(itera2, "\n")
1198
1223
#and increment the new white line
1199
1224
itera2 = self.buff.get_iter_at_line(line_nbr)
1200
self.insert_indent(self.buff, itera2, current_indent, enter=False)
1225
self.insert_indent(self.buff, itera2,
1226
current_indent, enter=False)
1201
1227
elif current_indent == 1:
1202
self.insert_indent(self.buff, itera, current_indent)
1228
self.insert_indent(self.buff, itera,
1203
1230
#we stop the signal in all cases
1204
1231
tv.emit_stop_by_name('insert-text')
1205
1232
#Then we close the tag tag
1207
1234
insert_mark = self.buff.get_mark("insert_point")
1208
1235
insert_iter = self.buff.get_iter_at_mark(insert_mark)
1209
self.buff.move_mark_by_name("/%s"%closed_tag, insert_iter)
1236
self.buff.move_mark_by_name("/%s" % closed_tag,
1210
1238
self.buff.delete_mark(insert_mark)
1211
1239
if cutting_subtask:
1212
cursor = self.buff.get_iter_at_mark(self.buff.get_insert())
1240
cursor = self.buff.get_iter_at_mark(
1241
self.buff.get_insert())
1213
1242
endl = cursor.copy()
1214
1243
if not endl.ends_line():
1215
1244
endl.forward_to_line_end()
1225
1254
if itera.starts_line():
1226
1255
#we are at the start of an existing subtask
1227
1256
#we simply move that subtask down
1228
self.buff.insert(itera,"\n")
1257
self.buff.insert(itera, "\n")
1229
1258
itera2 = self.buff.get_iter_at_line(line_nbr)
1230
1259
self.buff.insert(itera2, tex)
1231
1260
itera3 = self.buff.get_iter_at_line(line_nbr)
1233
1262
self.buff.place_cursor(itera3)
1234
1263
tv.emit_stop_by_name('insert-text')
1236
#self.__newsubtask(self.buff, tex, line_nbr, level=current_indent)
1265
#self.__newsubtask(self.buff, tex, line_nbr,
1266
# level=current_indent)
1237
1267
anchor = self.new_subtask_callback(tex)
1238
1268
self.buff.create_mark(anchor, itera, True)
1239
1269
self.buff.create_mark("/%s"%anchor, itera, False)
1240
self.insert_sigid = self.buff.connect('insert-text', self._insert_at_cursor)
1270
self.insert_sigid = self.buff.connect('insert-text',
1271
self._insert_at_cursor)
1241
1272
self.connect('key_press_event', self._keypress)
1242
1273
self.modified_sigid = self.buff.connect("changed", self.modified)
1244
1275
def _keypress(self, widget, event):
1245
1276
# Check for Ctrl-Return/Enter
1246
if event.get_state() & Gdk.ModifierType.CONTROL_MASK and event.keyval in (Gdk.KEY_Return, Gdk.KEY_KP_Enter):
1277
if event.get_state() & Gdk.ModifierType.CONTROL_MASK and \
1278
event.keyval in (Gdk.KEY_Return, Gdk.KEY_KP_Enter):
1247
1279
buff = self.buff
1248
1280
cursor_mark = buff.get_insert()
1249
1281
cursor_iter = buff.get_iter_at_mark(cursor_mark)
1250
1282
local_start = cursor_iter.copy()
1252
1284
for tag in local_start.get_tags():
1256
1288
if typ == "subtask":
1257
1289
self.open_task(anchor)
1281
1313
self.buff.disconnect(self.delete_sigid)
1282
1314
#print "deintdent-delete: %s" %self.buff.get_text(startline, itera)
1283
1315
self.buff.delete(startline, itera)
1284
self.delete_sigid = self.buff.connect("delete-range", \
1286
1316
#For the day when we will have different indent levels
1287
1317
#newiter = self.buff.get_iter_at_mark(tempm)
1288
1318
#self.buff.delete_mark(tempm)
1289
1319
#self.insert_indent(self.buff, newiter, newlevel, enter=False)
1320
self.delete_sigid = self.buff.connect("delete-range",
1291
1323
def backspace(self, tv):
1292
1324
self.buff.disconnect(self.insert_sigid)
1301
1333
#we stopped the signal, don't forget to erase
1302
1334
#the selection if one
1303
1335
self.buff.delete_selection(True, True)
1304
self.insert_sigid = self.buff.connect('insert-text', \
1336
self.insert_sigid = self.buff.connect('insert-text',
1305
1337
self._insert_at_cursor)
1307
1339
#The mouse is moving. We must change it to a hand when hovering over a link
1321
1353
tag_table = self.buff.get_tag_table()
1322
1354
tag_table.foreach(self.__tag_reset, window)
1324
#We clicked on a link
1325
def _tag_event(self, tag, view, ev, _iter, text, anchor, typ): #pylint: disable-msg=W0613
1356
def _tag_event(self, tag, view, ev, _iter, text, anchor, typ):
1358
We clicked on a link
1360
#pylint: disable-msg=W0613
1326
1361
_type = ev.type
1327
1362
if _type == Gdk.EventType.MOTION_NOTIFY:
1333
1368
if typ == "subtask":
1334
1369
self.open_task(anchor)
1335
1370
elif typ == "http":
1336
if button == 1 and self.check_link(anchor) and self.buff.get_has_selection() == False:
1371
if button == 1 and self.check_link(anchor) and \
1372
not self.buff.get_has_selection():
1337
1373
openurl(anchor)
1339
1375
print "Unknown link type for %s" %anchor
1340
1376
self.emit('anchor-clicked', text, anchor, button)
1341
self.__set_anchor(ev.window, tag, cursor, self.get_property('hover'))
1377
self.__set_anchor(ev.window, tag, cursor,
1378
self.get_property('hover'))
1342
1379
elif button in [1, 2]:
1343
self.__set_anchor(ev.window, tag, cursor, self.get_property('active'))
1380
self.__set_anchor(ev.window, tag, cursor,
1381
self.get_property('active'))
1345
1383
def __tag_reset(self, tag, window):
1346
1384
if hasattr(tag, 'is_anchor'):
1353
1391
linktype = 'link'
1355
1393
linktype = 'failedlink'
1356
self.__set_anchor(window, tag, editing_cursor, self.get_property(linktype))
1394
self.__set_anchor(window, tag, editing_cursor,
1395
self.get_property(linktype))
1358
1397
def __set_anchor(self, window, tag, cursor, prop):
1359
1398
window.set_cursor(cursor)