186
186
#this is initially set at False and then to True once the editor window
188
188
#this is used to avoid saving the task when the window is still not displayed
189
def set_editable(self,boule):
189
def set_editable(self, boule):
190
190
self.editable = boule
191
192
def get_editable(self):
192
193
return self.editable
194
#This function is called to refresh the editor
195
#This function is called to refresh the editor
195
196
#Specially when we change the title
196
def refresh(self,title) :
197
if self.__refresh_cb :
197
def refresh(self, title):
198
if self.__refresh_cb:
198
199
self.__refresh_cb(title)
200
def refresh_callback(self,funct) :
201
def refresh_callback(self, funct):
201
202
self.__refresh_cb = funct
202
204
#This callback is called to add a new tag
203
def set_add_tag_callback(self,funct) :
205
def set_add_tag_callback(self, funct):
204
206
self.add_tag_callback = funct
206
208
#This callback is called to add a new tag
207
def set_remove_tag_callback(self,funct) :
209
def set_remove_tag_callback(self, funct):
208
210
self.remove_tag_callback = funct
210
212
#This callback is called to have the list of tags of a task
211
def set_get_tagslist_callback(self,funct) :
213
def set_get_tagslist_callback(self, funct):
212
214
self.get_tagslist = funct
214
216
#This callback is called to create a new subtask
215
def set_subtask_callback(self,funct) :
217
def set_subtask_callback(self, funct):
216
218
self.new_subtask_callback = funct
218
220
#This callback is called to open another task
219
def open_task_callback(self,funct) :
221
def open_task_callback(self, funct):
220
222
self.open_task = funct
222
224
#This was historically a callback but it returns the title
223
def get_subtasktitle(self,tid):
225
def get_subtasktitle(self, tid):
224
226
task = self.req.get_task(tid)
226
228
return task.get_title()
267
269
self.buff.deserialize(self.buff, self.mime_type, _iter, text)
270
if reconnect_insert :
271
273
self.insert_sigid = self.buff.connect('insert-text', self._insert_at_cursor)
272
if reconnect_modified :
273
self.modified_sigid = self.buff.connect("changed" , self.modified)
274
if reconnect_modified:
275
self.modified_sigid = self.buff.connect("changed", self.modified)
275
277
#This insert raw text without deserializing
276
def insert_text(self,text, _iter=None) :
278
def insert_text(self, text, _iter=None):
278
280
_iter = self.buff.get_end_iter()
279
self.buff.insert(_iter,text)
281
self.buff.insert(_iter, text)
281
283
#We cannot get an insert in the title
282
def get_insert(self) :
284
def get_insert(self):
283
285
mark = self.buff.get_insert()
284
286
itera = self.buff.get_iter_at_mark(mark)
285
if itera.get_line() == 0 :
287
if itera.get_line() == 0:
286
288
itera.forward_line()
289
def insert_with_anchor(self, text, anchor=None, _iter=None,typ=None):
291
def insert_with_anchor(self, text, anchor=None, _iter=None, typ=None):
290
292
b = self.get_buffer()
291
293
if _iter is None:
292
294
_iter = b.get_end_iter()
293
295
if anchor is None:
295
tag = self.create_anchor_tag(b,anchor,text,typ=typ)
297
tag = self.create_anchor_tag(b, anchor, text, typ=typ)
296
298
b.insert_with_tags(_iter, text, tag)
298
300
def check_link(self, url):
327
329
tag = b.create_tag(None, **self.get_property(linktype)) #pylint: disable-msg=W0142
328
330
tag.set_data('is_anchor', True)
329
tag.set_data('link',anchor)
331
tag.set_data('type',typ)
332
tag.connect('event', self._tag_event, text, anchor,typ)
331
tag.set_data('link', anchor)
333
tag.set_data('type', typ)
334
tag.connect('event', self._tag_event, text, anchor, typ)
333
335
self.__tags.append(tag)
336
338
#Apply the tag tag to a set of TextMarks (not Iter)
337
def apply_tag_tag(self,buff,tag,s,e) :
339
def apply_tag_tag(self, buff, tag, s, e):
338
340
ss = buff.get_iter_at_mark(s)
339
341
ee = buff.get_iter_at_mark(e)
340
342
#If the tag is already applied, we do nothing
341
343
t_list = ss.get_tags()
345
if t.get_data('is_tag') and t.get_data('tagname') == tag :
347
if t.get_data('is_tag') and t.get_data('tagname') == tag:
347
if ss.begins_tag(t) and ee.ends_tag(t) :
349
if ss.begins_tag(t) and ee.ends_tag(t):
350
352
texttag = buff.create_tag(None,**self.get_property('tag'))#pylint: disable-msg=W0142
351
353
texttag.set_data('is_tag', True)
352
texttag.set_data('tagname',tag)
354
texttag.set_data('tagname', tag)
353
355
#This one is for marks
355
self.__apply_tag_to_mark(s,e,tag=texttag)
357
self.__apply_tag_to_mark(s, e, tag=texttag)
357
359
#Apply the tag tag to a set of TextMarks (not Iter)
358
360
#Also change the subtask title if needed
359
def apply_subtask_tag(self,buff,subtask,s,e) :
361
def apply_subtask_tag(self, buff, subtask, s, e):
360
362
i_s = buff.get_iter_at_mark(s)
361
363
i_e = buff.get_iter_at_mark(e)
362
tex = buff.get_text(i_s,i_e)
364
tex = buff.get_text(i_s, i_e)
363
365
#we don't accept \n in a subtask title
366
while i_e.get_char() != "\n" :
368
while i_e.get_char() != "\n":
367
369
i_e.forward_char()
368
buff.move_mark(e,i_e)
369
tex = buff.get_text(i_s,i_e)
370
buff.move_mark(e, i_e)
371
tex = buff.get_text(i_s, i_e)
371
373
self.req.get_task(subtask).set_title(tex)
372
texttag = self.create_anchor_tag(buff,subtask,text=tex,typ="subtask")
374
texttag = self.create_anchor_tag(buff, subtask, text=tex, typ="subtask")
373
375
texttag.set_data('is_subtask', True)
374
texttag.set_data('child',subtask)
376
texttag.set_data('child', subtask)
375
377
#This one is for marks
376
self.__apply_tag_to_mark(s,e,tag=texttag)
378
self.__apply_tag_to_mark(s, e, tag=texttag)
378
380
self.remove_subtask(subtask)
379
381
buff.delete_mark(s)
380
382
buff.delete_mark(e)
382
def create_indent_tag(self,buff,level) :
384
def create_indent_tag(self, buff, level):
383
385
tag = buff.create_tag(None, **self.get_property('indent'))#pylint: disable-msg=W0142
384
tag.set_data('is_indent',True)
385
tag.set_data('indent_level',level)
386
tag.set_data('is_indent', True)
387
tag.set_data('indent_level', level)
388
390
#Insert a list of subtasks at the end of the buffer
389
def insert_subtasks(self,st_list) :
391
def insert_subtasks(self, st_list):
391
393
line_nbr = self.buff.get_end_iter().get_line()
392
394
#Warning, we have to take the next line !
393
self.write_subtask(self.buff,line_nbr+1,tid)
395
self.write_subtask(self.buff, line_nbr+1, tid)
395
397
#Insert a list of tag in the first line of the buffer
396
def insert_tags(self,tag_list) :
398
def insert_tags(self, tag_list):
397
399
#First, we don't insert tags that are already present
398
for t in self.get_tagslist() :
400
for t in self.get_tagslist():
400
402
tag_list.remove(t)
401
if len(tag_list) > 0 :
403
if len(tag_list) > 0:
402
404
#We insert them just after the title
403
405
#We use the current first line if it begins with a tag
404
406
firstline = self.buff.get_iter_at_line(1)
406
for tt in firstline.get_tags() :
407
if tt.get_data('is_tag') :
408
for tt in firstline.get_tags():
409
if tt.get_data('is_tag'):
409
411
firstline.forward_to_line_end()
410
412
#Now we should check if the current char is a separator or not
411
413
#Currently, we insert a space
412
self.insert_text(" ",firstline)
414
self.insert_text(" ", firstline)
413
415
#Now we check if this newline is empty (it contains only " " and ",")
415
417
# endline = firstline.copy()
416
# if not endline.ends_line() :
418
# if not endline.ends_line():
417
419
# endline.forward_to_line_end()
418
# text = self.buff.get_text(firstline,endline)
419
# if not text.strip(", ") :
420
# text = self.buff.get_text(firstline, endline)
421
# if not text.strip(", "):
420
422
# newline = False
421
423
# firstline.forward_to_line_end()
422
424
#Now we can process
424
426
firstline = self.buff.get_iter_at_line(0)
425
427
firstline.forward_to_line_end()
426
self.insert_text("\n",firstline)
428
self.insert_text("\n", firstline)
427
429
firstline = self.buff.get_iter_at_line(1)
428
line_mark = self.buff.create_mark("firstline",firstline,False)
429
#self.tv.insert_at_mark(buf,line_mark,"\n")
430
line_mark = self.buff.create_mark("firstline", firstline, False)
431
#self.tv.insert_at_mark(buf, line_mark,"\n")
430
432
ntags = len(tag_list)
432
434
ntags = ntags - 1
433
self.insert_at_mark(self.buff,line_mark,t)
435
self.insert_at_mark(self.buff, line_mark, t)
435
self.insert_at_mark(self.buff,line_mark,",")
437
self.insert_at_mark(self.buff, line_mark,",")
436
438
self.buff.delete_mark(line_mark)
437
439
self.modified(full=True)
528
530
#The following 3 lines are a quick ugly fix for bug #359469
529
531
# temp = buff.get_iter_at_line(1)
530
532
# temp.backward_char()
531
# self._detect_tag(buff,temp,buff.get_end_iter())
533
# self._detect_tag(buff, temp, buff.get_end_iter())
532
534
#This should be the good line
533
self._detect_tag(buff,local_start,local_end)
534
self._detect_url(buff,local_start,local_end)
535
self._detect_tag(buff, local_start, local_end)
536
self._detect_url(buff, local_start, local_end)
536
538
#subt_list = self.get_subtasks()
537
539
#First, we remove the olds tags
539
def subfunc(texttag,data=None): #pylint: disable-msg=W0613
541
def subfunc(texttag, data=None): #pylint: disable-msg=W0613
540
542
if texttag.get_data('is_subtask'):
541
543
tag_list.append(texttag)
542
544
table.foreach(subfunc)
543
start,end = buff.get_bounds()
545
buff.remove_tag(t,start,end)
545
start, end = buff.get_bounds()
547
buff.remove_tag(t, start, end)
548
550
#We apply the hyperlink tag to subtask
549
for s in self.get_subtasks() :
551
for s in self.get_subtasks():
550
552
start_mark = buff.get_mark(s)
551
# "applying %s to %s - %s"%(s,start_mark,end_mark)
553
# "applying %s to %s - %s"%(s, start_mark, end_mark)
553
555
#In fact, the subtask mark always go to the end of line.
554
556
start_i = buff.get_iter_at_mark(start_mark)
555
557
if self._get_indent_level(start_i) > 0:
556
558
start_i.forward_to_line_end()
557
end_mark = buff.create_mark("/%s"%s,start_i,False)
558
self.apply_subtask_tag(buff,s,start_mark,end_mark)
559
end_mark = buff.create_mark("/%s"%s, start_i, False)
560
self.apply_subtask_tag(buff, s, start_mark, end_mark)
560
562
self.remove_subtask(s)
563
565
#Now we apply the tag tag to the marks
564
for t in self.get_tagslist() :
566
for t in self.get_tagslist():
565
567
start_mark = buff.get_mark(t)
566
568
end_mark = buff.get_mark("/%s"%t)
567
# "applying %s to %s - %s"%(t,start_mark,end_mark)
568
if start_mark and end_mark :
569
self.apply_tag_tag(buff,t,start_mark,end_mark)
569
# "applying %s to %s - %s"%(t, start_mark, end_mark)
570
if start_mark and end_mark:
571
self.apply_tag_tag(buff, t, start_mark, end_mark)
571
573
#Ok, we took care of the modification
572
574
self.buff.set_modified(False)
573
575
#Else we save the task anyway (but without refreshing all)
577
579
#Detect URL in the tasks
579
def _detect_url(self,buff,start,end) :
581
def _detect_url(self, buff, start, end):
580
582
#subt_list = self.get_subtasks()
581
583
#First, we remove the olds tags
583
585
table = buff.get_tag_table()
584
def subfunc(texttag,data=None):
586
def subfunc(texttag, data=None):
585
587
if texttag.get_data('is_anchor'):
586
588
tag_list.append(texttag)
587
589
table.foreach(subfunc)
589
buff.remove_tag(t,start,end)
591
buff.remove_tag(t, start, end)
590
592
#Now we add the tag URL
591
593
it = start.copy()
592
594
prev = start.copy()
593
while (it.get_offset() < end.get_offset()) and (it.get_char() != '\0') :
595
while (it.get_offset() < end.get_offset()) and (it.get_char() != '\0'):
594
596
it.forward_word_end()
596
598
prev.backward_word_start()
597
text = buff.get_text(prev,it)
599
text = buff.get_text(prev, it)
599
601
if text in ["http", "https", "www", "file"]:
600
602
isurl = buff.get_text(prev, buff.get_end_iter())
601
603
m = urlregex.match(isurl)
602
604
if m is not None:
603
url = isurl[:m.end()]
605
url = isurl[:m.end()]
604
606
# For short URL we must add http:// prefix
605
607
if text == "www":
606
608
url = "http://" + url
607
609
texttag = self.create_anchor_tag(buff, url, text=None, typ="http")
609
611
it.forward_chars(m.end())
610
buff.apply_tag(texttag, prev , it)
612
buff.apply_tag(texttag, prev, it)
612
elif text in ["bug", "lp", "bgo", "fdo", "bko"] :
613
if it.get_char() == " " :
615
if it.get_char() == "#" :
617
while it.get_char().isdigit() and (it.get_char() != '\0') :
614
elif text in ["bug", "lp", "bgo", "fdo", "bko"]:
615
if it.get_char() == " ":
617
if it.get_char() == "#":
619
while it.get_char().isdigit() and (it.get_char() != '\0'):
618
620
it.forward_char()
619
url = buff.get_text(prev,it)
621
url = buff.get_text(prev, it)
620
622
nbr = url.split("#")[1]
622
if url.startswith("bug #") or url.startswith("lp #") :
624
if url.startswith("bug #") or url.startswith("lp #"):
623
625
topoint = "https://launchpad.net/bugs/%s" %nbr
624
elif url.startswith("bgo #") :
626
elif url.startswith("bgo #"):
625
627
topoint = "http://bugzilla.gnome.org/show_bug.cgi?id=%s" %nbr
626
elif url.startswith("bko #") :
628
elif url.startswith("bko #"):
627
629
topoint = "https://bugs.kde.org/show_bug.cgi?id=%s" %nbr
628
elif url.startswith("fdo #") :
630
elif url.startswith("fdo #"):
629
631
topoint = "http://bugs.freedesktop.org/show_bug.cgi?id=%s" %nbr
631
633
texttag = self.create_anchor_tag(buff,\
632
topoint,text=None,typ="http")
633
buff.apply_tag(texttag, prev , it)
634
topoint, text=None, typ="http")
635
buff.apply_tag(texttag, prev, it)
636
638
#Detect tags in buff in the region between start iter and end iter
637
def _detect_tag(self,buff,start,end) :
639
def _detect_tag(self, buff, start, end):
638
640
# Removing already existing tag in the current selection
639
641
# out of the tag table
640
642
it = start.copy()
719
721
word_end = char_end.copy()
721
723
# Stop loop if we are at the end
722
if char_end.compare(end) == 0:
724
if char_end.compare(end) == 0:
725
727
# We search the next word
726
728
char_start = char_end.copy()
727
729
char_end.forward_char()
729
# Update tags in model :
731
# Update tags in model:
730
732
# we remove tags that are not in the description anymore
732
if not t in new_tags :
734
if not t in new_tags:
733
735
self.remove_tag_callback(t)
735
def is_at_title(self,buff,itera) :
737
def is_at_title(self, buff, itera):
736
738
to_return = False
737
if itera.get_line() == 0 :
739
if itera.get_line() == 0:
739
741
#We are at a line with the title tag applied
740
elif self.title_tag in itera.get_tags() :
742
elif self.title_tag in itera.get_tags():
742
744
#else, we look if there's something between us and buffer start
743
elif not buff.get_text(buff.get_start_iter(),itera).strip('\n\t ') :
745
elif not buff.get_text(buff.get_start_iter(), itera).strip('\n\t '):
747
749
#When the user removes a selection, we remove subtasks and @tags
748
750
#from this selection
749
def _delete_range(self,buff,start,end) :
751
def _delete_range(self, buff, start, end):
750
752
# #If we are at the beginning of a mark, put this mark at the end
751
753
# marks = start.get_marks()
753
755
# print m.get_name()
754
# buff.move_mark(m,end)
756
# buff.move_mark(m, end)
755
757
#If the begining of the selection is in the middle of an indent
756
758
#We want to start at the begining
757
759
tags = start.get_tags()+start.get_toggled_tags(False)
759
761
if (ta.get_data('is_indent')):
760
762
line = start.get_line()
761
763
start = self.buff.get_iter_at_line(line)
796
798
#now we really delete the selected stuffs
797
799
selec = self.buff.get_selection_bounds()
799
# print "deleted text is ##%s##" %self.buff.get_text(selec[0],selec[1])#(start,end)
801
# print "deleted text is ##%s##" %self.buff.get_text(selec[0], selec[1])#(start, end)
800
802
# self.buff.disconnect(self.delete_sigid)
801
803
# self.disconnect(self.backspace_sigid)
802
804
# self.buff.stop_emission("delete-range")
803
# if self.buff.get_has_selection() :
804
# self.buff.delete_selection(False,True)
805
# if self.buff.get_has_selection():
806
# self.buff.delete_selection(False, True)
806
808
# end.forward_char()
807
# self.buff.backspace(end,False,True)
808
# self.delete_sigid = self.buff.connect("delete-range",self._delete_range)
809
# self.backspace_sigid = self.connect("backspace",self.backspace)
809
# self.buff.backspace(end, False, True)
810
# self.delete_sigid = self.buff.connect("delete-range", self._delete_range)
811
# self.backspace_sigid = self.connect("backspace", self.backspace)
810
812
#We return false so the parent still get the signal
813
815
#Apply the title and return an iterator after that title.buff.get_iter_at_mar
814
def _apply_title(self,buff,refresheditor=True) :
816
def _apply_title(self, buff, refresheditor=True):
815
817
start = buff.get_start_iter()
816
818
end = buff.get_end_iter()
818
820
linecount = buff.get_line_count()
820
# Apply the title tag on the first line
822
# Apply the title tag on the first line
821
823
#---------------------------------------
823
825
# Determine the iterators for title
824
title_start = start.copy()
825
if linecount > line_nbr :
826
title_start = start.copy()
827
if linecount > line_nbr:
826
828
# Applying title on the first line
827
829
title_end = buff.get_iter_at_line(line_nbr-1)
828
830
title_end.forward_to_line_end()
829
stripped = buff.get_text(title_start,title_end).strip('\n\t ')
831
stripped = buff.get_text(title_start, title_end).strip('\n\t ')
830
832
# Here we ignore lines that are blank
831
833
# Title is the first written line
832
while line_nbr <= linecount and not stripped :
834
while line_nbr <= linecount and not stripped:
834
836
title_end = buff.get_iter_at_line(line_nbr-1)
835
837
title_end.forward_to_line_end()
836
838
stripped = buff.get_text(title_start, title_end).strip('\n\t ')
837
839
# Or to all the buffer if there is only one line
839
841
title_end = end.copy()
840
buff.apply_tag_by_name('title', title_start , title_end)
841
buff.remove_tag_by_name('title', title_end , end)
842
buff.apply_tag_by_name('title', title_start, title_end)
843
buff.remove_tag_by_name('title', title_end, end)
842
844
# Refresh title of the window
843
845
if refresheditor:
844
self.refresh(buff.get_text(title_start,title_end).strip('\n\t'))
846
self.refresh(buff.get_text(title_start, title_end).strip('\n\t'))
849
def __newsubtask(self,buff,title,line_nbr, level=1) :
851
def __newsubtask(self, buff, title, line_nbr, level=1):
850
852
anchor = self.new_subtask_callback(title)
851
end_i = self.write_subtask(buff,line_nbr,anchor,level=level)
853
end_i = self.write_subtask(buff, line_nbr, anchor, level=level)
854
856
#Write the subtask then return the iterator at the end of the line
855
def write_subtask(self,buff,line_nbr,anchor,level=1) :
857
def write_subtask(self, buff, line_nbr, anchor, level=1):
856
858
#disable the insert signal to avoid recursion
857
859
#firstly, we check that the subtask exists !
858
860
if not self.req.has_task(anchor):
860
862
reconnect_insert = False
861
863
reconnect_modified = False
862
if self.insert_sigid :
864
if self.insert_sigid:
863
865
self.buff.disconnect(self.insert_sigid)
864
866
self.insert_sigid = False
865
867
reconnect_insert = True
866
if self.modified_sigid :
868
if self.modified_sigid:
867
869
self.buff.disconnect(self.modified_sigid)
868
870
self.modified_sigid = False
869
871
reconnect_modified = True
881
883
# start_i.backward_char()
882
884
# #But only if this is not the title.
883
885
insert_enter = False
884
# if start_i.has_tag(self.title_tag) :
886
# if start_i.has_tag(self.title_tag):
885
887
# start_i.forward_char()
886
888
# insert_enter = False
887
start = buff.create_mark("start",start_i,True)
889
start = buff.create_mark("start", start_i, True)
888
890
end_i.forward_line()
889
end = buff.create_mark("end",end_i,False)
890
buff.delete(start_i,end_i)
891
end = buff.create_mark("end", end_i, False)
892
buff.delete(start_i, end_i)
891
893
start_i = buff.get_iter_at_mark(start)
892
self.insert_indent(buff,start_i,level, enter=insert_enter)
894
self.insert_indent(buff, start_i, level, enter=insert_enter)
893
895
newline = self.get_subtasktitle(anchor)
894
896
end_i = buff.get_iter_at_mark(end)
895
startm = buff.create_mark(anchor,end_i,True)
897
startm = buff.create_mark(anchor, end_i, True)
896
898
#Putting the subtask marks around the title
897
self.insert_at_mark(buff,end,newline)
899
self.insert_at_mark(buff, end, newline)
898
900
end_i = buff.get_iter_at_mark(end)
899
endm = buff.create_mark("/%s"%anchor,end_i,False)
901
endm = buff.create_mark("/%s"%anchor, end_i, False)
900
902
#put the tag on the marks
901
self.apply_subtask_tag(buff,anchor,startm,endm)
903
self.apply_subtask_tag(buff, anchor, startm, endm)
902
904
#buff.delete_mark(start)
903
905
#buff.delete_mark(end)
905
if reconnect_insert :
906
908
self.insert_sigid = self.buff.connect('insert-text', self._insert_at_cursor)
907
if reconnect_modified :
908
self.modified_sigid = self.buff.connect("changed" , self.modified)
909
if reconnect_modified:
910
self.modified_sigid = self.buff.connect("changed", self.modified)
911
def insert_newtask(self,fitera=None) :
913
def insert_newtask(self, fitera=None):
913
915
fitera = self.get_insert()
914
916
#First, find a line without subtask
915
917
line = fitera.get_line()
916
918
#Avoid the title at all cost
919
921
startl = self.buff.get_iter_at_line(line)
923
for t in startl.get_tags() :
924
if t.get_data('is_indent') :
925
for t in startl.get_tags():
926
if t.get_data('is_indent'):
926
928
startl = self.buff.get_iter_at_line(line)
927
if line < self.buff.get_line_count() :
929
if line < self.buff.get_line_count():
932
934
#if the last line is indented, then insert a new line
934
if line == self.buff.get_line_count() :
936
if line == self.buff.get_line_count():
935
937
itera.forward_to_line_end()
936
mark = self.buff.create_mark(None,itera,True)
938
mark = self.buff.create_mark(None, itera, True)
937
939
self.buff.insert(itera,"\n")
938
940
itera = self.buff.get_iter_at_mark(mark)
939
941
self.buff.delete_mark(mark)
942
944
#but if we are at the start of line, then create the subtask
943
945
#before the current line
945
if itera.starts_line() :
946
mark = self.buff.create_mark(None,itera,True)
947
if itera.starts_line():
948
mark = self.buff.create_mark(None, itera, True)
947
949
self.buff.insert(itera,"\n")
948
950
itera = self.buff.get_iter_at_mark(mark)
949
951
self.buff.delete_mark(mark)
951
elif not itera.ends_line() :
953
elif not itera.ends_line():
952
954
itera.forward_to_line_end()
953
endm = self.insert_indent(self.buff,itera,1,enter=enter)
955
endm = self.insert_indent(self.buff, itera, 1, enter=enter)
954
956
end = self.buff.get_iter_at_mark(endm)
955
957
self.buff.place_cursor(end)
957
def insert_indent(self,buff,start_i,level,enter=True) :
959
def insert_indent(self, buff, start_i, level, enter=True):
958
960
#We will close the current subtask tag
959
961
list_stag = start_i.get_toggled_tags(False)
962
if t.get_data('is_subtask') :
964
if t.get_data('is_subtask'):
964
966
#maybe the tag was not toggled off here but we were in the middle
966
968
list_stag = start_i.get_tags()
968
if t.get_data('is_subtask') :
970
if t.get_data('is_subtask'):
971
973
#We will remove the tag from the whole text
972
974
subtid = stag.get_data('child')
973
975
#We move the end_subtask mark to here
974
976
#We have to create a temporary mark with left gravity
975
977
#It will be later replaced by the good one with right gravity
976
temp_mark = self.buff.create_mark("temp",start_i,True)
978
temp_mark = self.buff.create_mark("temp", start_i, True)
978
end = buff.create_mark("end",start_i,False)
980
end = buff.create_mark("end", start_i, False)
980
982
buff.insert(start_i,"\n")
982
984
#Moving the end of subtask mark to the position of the temp mark
984
986
itera = buff.get_iter_at_mark(temp_mark)
985
buff.move_mark_by_name("/%s"%subtid,itera)
987
buff.move_mark_by_name("/%s"%subtid, itera)
986
988
buff.delete_mark(temp_mark)
987
989
#The mark has right gravity but because we put it on the left
988
990
#of the newly inserted \n, it will not move anymore.
990
992
itera = buff.get_iter_at_mark(end)
991
993
#We should never have an indentation at 0.
992
994
#This is normally not needed and purely defensive
993
if itera.get_line() <= 0 :
995
if itera.get_line() <= 0:
994
996
itera = buff.get_iter_at_line(1)
995
start = buff.create_mark("start",itera,True)
997
start = buff.create_mark("start", itera, True)
997
999
#adding two spaces by level
999
1001
indentation = indentation + (level-1)*spaces
1002
indentation = "%s%s "%(indentation,self.bullet1)
1003
buff.insert(itera,indentation)
1004
indenttag = self.create_indent_tag(buff,level)
1005
self.__apply_tag_to_mark(start,end,tag=indenttag)
1004
indentation = "%s%s "%(indentation, self.bullet1)
1005
buff.insert(itera, indentation)
1006
indenttag = self.create_indent_tag(buff, level)
1007
self.__apply_tag_to_mark(start, end, tag=indenttag)
1009
def __apply_tag_to_mark(self,start,end,tag=None,name=None) :
1011
def __apply_tag_to_mark(self, start, end, tag=None, name=None):
1010
1012
start_i = self.buff.get_iter_at_mark(start)
1011
1013
end_i = self.buff.get_iter_at_mark(end)
1012
1014
#we should apply the tag only if the mark are separated
1013
if end_i.get_offset() - start_i.get_offset() > 0 :
1015
self.buff.apply_tag(tag,start_i,end_i)
1017
self.buff.apply_tag_by_name(name,start_i,end_i)
1019
self.buff.remove_tag(tag,start_i,end_i)
1015
if end_i.get_offset() - start_i.get_offset() > 0:
1017
self.buff.apply_tag(tag, start_i, end_i)
1019
self.buff.apply_tag_by_name(name, start_i, end_i)
1021
self.buff.remove_tag(tag, start_i, end_i)
1021
def insert_at_mark(self,buff,mark,text,anchor=None) :
1023
def insert_at_mark(self, buff, mark, text, anchor=None):
1022
1024
ite = buff.get_iter_at_mark(mark)
1024
self.insert_with_anchor(text,anchor,_iter=ite,typ="subtask")
1026
buff.insert(ite,text)
1029
def _get_indent_level(self,itera) :
1026
self.insert_with_anchor(text, anchor, _iter=ite, typ="subtask")
1028
buff.insert(ite, text)
1031
def _get_indent_level(self, itera):
1030
1032
line_nbr = itera.get_line()
1031
1033
start_line = itera.copy()
1032
1034
start_line.set_line(line_nbr)
1033
1035
tags = start_line.get_tags()
1034
1036
current_indent = 0
1036
if ta.get_data('is_indent') :
1038
if ta.get_data('is_indent'):
1037
1039
current_indent = ta.get_data('indent_level')
1038
1040
return current_indent
1040
1042
#Method called on copy and cut actions
1041
1043
#param is either "cut" or "copy"
1042
def copy_clipboard(self,widget,param=None):
1044
def copy_clipboard(self, widget, param=None):
1043
1045
clip = gtk.clipboard_get(gdk.SELECTION_CLIPBOARD)
1045
1047
#First, we analyse the selection to put in our own
1046
1048
#GTG clipboard a selection with description of subtasks
1047
1049
bounds = self.buff.get_selection_bounds()
1050
1052
start, stop = self.buff.get_selection_bounds()
1052
self.clipboard.copy(start,stop,bullet=self.bullet1)
1054
self.clipboard.copy(start, stop, bullet=self.bullet1)
1054
1056
clip.set_text(self.clipboard.paste_text())
1058
self.buff.delete_selection(False,True)
1060
self.buff.delete_selection(False, True)
1059
1061
self.stop_emission("cut_clipboard")
1061
1063
self.stop_emission("copy_clipboard")
1063
1065
#Called on paste.
1064
def paste_clipboard(self,widget,param=None):
1066
def paste_clipboard(self, widget, param=None):
1065
1067
clip = gtk.clipboard_get(gdk.SELECTION_CLIPBOARD)
1066
1068
#if the clipboard text is the same are our own internal
1067
1069
#clipboard text, it means that we can paste from our own clipboard
1068
1070
#else, that we can empty it.
1069
1071
our_paste = self.clipboard.paste_text()
1070
if our_paste != None and clip.wait_for_text() == our_paste :
1072
if our_paste != None and clip.wait_for_text() == our_paste:
1071
1073
#first, we delete the current selection
1072
self.buff.delete_selection(False,True)
1074
self.buff.delete_selection(False, True)
1073
1075
for line in self.clipboard.paste():
1074
1076
if line[0] == 'text':
1075
1077
self.buff.insert_at_cursor(line[1])
1111
1113
subtask_nbr = None
1112
1114
current_indent = self._get_indent_level(itera)
1113
1115
tags = itera.get_tags()
1115
if ta.get_data('is_subtask') :
1117
if ta.get_data('is_subtask'):
1116
1118
subtask_nbr = ta.get_data('child')
1117
1119
#Maybe we are simply at the end of the tag
1118
1120
if not subtask_nbr and itera.ends_tag():
1119
for ta in itera.get_toggled_tags(False) :
1120
if ta.get_data('is_subtask') :
1121
for ta in itera.get_toggled_tags(False):
1122
if ta.get_data('is_subtask'):
1121
1123
subtask_nbr = ta.get_data('child')
1123
#New line : the user pressed enter !
1125
#New line: the user pressed enter !
1124
1126
#If the line begins with "-", it's a new subtask !
1126
1128
self.buff.create_mark("insert_point", itera, True)
1127
1129
#First, we close tag tags.
1128
1130
#If we are at the end of a tag, we look for closed tags
1129
1131
closed_tag = None
1130
1132
cutting_subtask = False
1131
if itera.ends_tag() :
1133
if itera.ends_tag():
1132
1134
list_stag = itera.get_toggled_tags(False)
1133
1135
#Or maybe we are in the middle of a tag
1135
1137
list_stag = itera.get_tags()
1136
for t in list_stag :
1137
if t.get_data('is_tag') :
1139
if t.get_data('is_tag'):
1138
1140
closed_tag = t.get_data('tagname')
1139
elif t.get_data('is_subtask') :
1141
elif t.get_data('is_subtask'):
1140
1142
cutting_subtask = True
1141
1143
closed_tag = t.get_data('child')
1142
1144
#We add a bullet list but not on the first line
1143
1145
#Because it's the title
1145
1147
line = start_line.get_slice(end_line)
1146
1148
#the part after the enter
1147
1149
realend = end_line.copy()
1154
1156
#If indent is 0, We check if we created a new task
1155
1157
#the "-" might be after a space
1156
1158
#Python 2.5 should allow both tests in one
1157
if current_indent == 0 :
1158
if line.startswith('-') or line.startswith(' -') :
1159
if current_indent == 0:
1160
if (line.startswith('-') or line.startswith(' -')) and line.lstrip(' -').strip() != "":
1159
1161
line = line.lstrip(' -')
1160
end_i = self.__newsubtask(self.buff,line,line_nbr)
1162
end_i = self.__newsubtask(self.buff, line, line_nbr)
1161
1163
#Here, we should increment indent level
1162
1164
#If we inserted enter in the middle of a line
1163
if restofline and restofline.strip() != "" :
1165
if restofline and restofline.strip() != "":
1164
1166
#it means we have two subtask to create
1165
1167
if self.buff.get_line_count() > line_nbr+1:
1166
1168
#but don't merge with the next line
1167
1169
itera = self.buff.get_iter_at_line(line_nbr+1)
1168
1170
self.buff.insert(itera,"\n\n")
1169
self.__newsubtask(self.buff,restofline,\
1171
self.__newsubtask(self.buff, restofline,\
1172
self.insert_indent(self.buff,end_i,1,enter=True)
1174
self.insert_indent(self.buff, end_i, 1, enter=True)
1173
1175
tv.emit_stop_by_name('insert-text')
1175
1177
self.buff.insert(itera,"\n")
1176
1178
tv.emit_stop_by_name('insert-text')
1178
1180
#Then, if indent > 0, we increment it
1179
#First step : we preserve it.
1181
#First step: we preserve it.
1181
1183
if not line.lstrip("%s "%self.bullet1):
1182
1184
#if we didn't write a task, we remove the indent
1183
#we check if the iterator is well at the end of
1185
#we check if the iterator is well at the end of
1185
1187
if end_line.ends_line():
1186
self.deindent(itera,newlevel=0)
1187
#else, it means that we pressed enter before
1188
self.deindent(itera, newlevel=0)
1189
#else, it means that we pressed enter before
1188
1190
#a subtask title
1190
1192
#we first put the subtask one line below
1191
1193
itera2 = self.buff.get_iter_at_line(line_nbr)
1192
1194
self.buff.insert(itera2,"\n")
1193
1195
#and increment the new white line
1194
1196
itera2 = self.buff.get_iter_at_line(line_nbr)
1195
self.insert_indent(self.buff,itera2,current_indent,enter=False)
1196
elif current_indent == 1 :
1197
self.insert_indent(self.buff,itera,current_indent)
1197
self.insert_indent(self.buff, itera2, current_indent, enter=False)
1198
elif current_indent == 1:
1199
self.insert_indent(self.buff, itera, current_indent)
1198
1200
#we stop the signal in all cases
1199
1201
tv.emit_stop_by_name('insert-text')
1200
1202
#Then we close the tag tag
1202
1204
insert_mark = self.buff.get_mark("insert_point")
1203
1205
insert_iter = self.buff.get_iter_at_mark(insert_mark)
1204
self.buff.move_mark_by_name("/%s"%closed_tag,insert_iter)
1206
self.buff.move_mark_by_name("/%s"%closed_tag, insert_iter)
1205
1207
self.buff.delete_mark(insert_mark)
1206
if cutting_subtask :
1207
1209
cursor = self.buff.get_iter_at_mark(self.buff.get_insert())
1208
1210
endl = cursor.copy()
1209
if not endl.ends_line() :
1211
if not endl.ends_line():
1210
1212
endl.forward_to_line_end()
1211
text = self.buff.get_text(cursor,endl)
1213
text = self.buff.get_text(cursor, endl)
1212
1214
anchor = self.new_subtask_callback(text)
1213
self.buff.create_mark(anchor,cursor,True)
1214
self.buff.create_mark("/%s"%anchor,endl,False)
1215
self.buff.create_mark(anchor, cursor, True)
1216
self.buff.create_mark("/%s"%anchor, endl, False)
1215
1217
self.modified(full=True)
1216
1218
#The user entered something else than \n
1218
1220
#We are on an indented line without subtask ? Create it !
1219
if current_indent > 0 and not subtask_nbr :
1221
if current_indent > 0 and not subtask_nbr:
1220
1222
if itera.starts_line():
1221
1223
#we are at the start of an existing subtask
1222
1224
#we simply move that subtask down
1223
1225
self.buff.insert(itera,"\n")
1224
1226
itera2 = self.buff.get_iter_at_line(line_nbr)
1225
self.buff.insert(itera2,tex)
1227
self.buff.insert(itera2, tex)
1226
1228
itera3 = self.buff.get_iter_at_line(line_nbr)
1227
1229
itera3.forward_to_line_end()
1228
1230
self.buff.place_cursor(itera3)
1229
1231
tv.emit_stop_by_name('insert-text')
1231
#self.__newsubtask(self.buff,tex,line_nbr, level=current_indent)
1233
#self.__newsubtask(self.buff, tex, line_nbr, level=current_indent)
1232
1234
anchor = self.new_subtask_callback(tex)
1233
self.buff.create_mark(anchor,itera,True)
1234
self.buff.create_mark("/%s"%anchor,itera,False)
1235
self.buff.create_mark(anchor, itera, True)
1236
self.buff.create_mark("/%s"%anchor, itera, False)
1235
1237
self.insert_sigid = self.buff.connect('insert-text', self._insert_at_cursor)
1236
1238
self.connect('key_press_event', self._keypress)
1237
self.modified_sigid = self.buff.connect("changed" , self.modified)
1239
self.modified_sigid = self.buff.connect("changed", self.modified)
1239
1241
def _keypress(self, widget, event):
1240
1242
# Check for Ctrl-Return/Enter
1260
1262
def deindent(self, itera, newlevel=-1):
1261
1263
line = itera.get_line()
1262
1264
startline = self.buff.get_iter_at_line(line)
1264
for t in itera.get_toggled_tags(False) :
1265
if t.get_data('is_indent') :
1266
for t in itera.get_toggled_tags(False):
1267
if t.get_data('is_indent'):
1266
1268
newlevel = t.get_data('indent_level')
1270
1272
#If it's still < 0
1272
print "bug : no is_indent tag on that line"
1274
print "bug: no is_indent tag on that line"
1273
1275
#startline.backward_char()
1274
1276
#We make a temp mark where we should insert the new indent
1275
#tempm = self.buff.create_mark("temp",startline)
1277
#tempm = self.buff.create_mark("temp", startline)
1276
1278
self.buff.disconnect(self.delete_sigid)
1277
#print "deintdent-delete : %s" %self.buff.get_text(startline,itera)
1278
self.buff.delete(startline,itera)
1279
#print "deintdent-delete: %s" %self.buff.get_text(startline, itera)
1280
self.buff.delete(startline, itera)
1279
1281
self.delete_sigid = self.buff.connect("delete-range", \
1280
1282
self._delete_range)
1281
1283
#For the day when we will have different indent levels
1282
1284
#newiter = self.buff.get_iter_at_mark(tempm)
1283
1285
#self.buff.delete_mark(tempm)
1284
#self.insert_indent(self.buff,newiter,newlevel,enter=False)
1286
#self.insert_indent(self.buff, newiter, newlevel, enter=False)
1286
1288
def backspace(self, tv):
1287
1289
self.buff.disconnect(self.insert_sigid)
1288
1290
insert_mark = self.buff.get_insert()
1289
1291
insert_iter = self.buff.get_iter_at_mark(insert_mark)
1290
1292
#All this crap to find if we are at the end of an indent tag
1291
if insert_iter.ends_tag() :
1292
for t in insert_iter.get_toggled_tags(False) :
1293
if t.get_data('is_indent') :
1293
if insert_iter.ends_tag():
1294
for t in insert_iter.get_toggled_tags(False):
1295
if t.get_data('is_indent'):
1294
1296
self.deindent(insert_iter)
1295
1297
tv.emit_stop_by_name('backspace')
1296
#we stopped the signal, don't forget to erase
1298
#we stopped the signal, don't forget to erase
1297
1299
#the selection if one
1298
self.buff.delete_selection(True,True)
1300
self.buff.delete_selection(True, True)
1299
1301
self.insert_sigid = self.buff.connect('insert-text', \
1300
1302
self._insert_at_cursor)