~nmu-sscheel/gtg/rework-task-editor

« back to all changes in this revision

Viewing changes to GTG/core/task.py

  • Committer: Luca Invernizzi
  • Date: 2010-09-08 14:15:11 UTC
  • mfrom: (825.1.227 liblarch_rebased)
  • Revision ID: invernizzi.l@gmail.com-20100908141511-vsctgw74dj1xp0wi
Liblarch is now in trunk.
Note that performances are still bad and it misses DnD and multi-select
support, but its state is better that the current trunk.
Backends are added in this merge too.

Show diffs side-by-side

added added

removed removed

Lines of Context:
24
24
import xml.dom.minidom
25
25
import uuid
26
26
import cgi
 
27
import re
27
28
import xml.sax.saxutils as saxutils
 
29
import gobject
28
30
 
 
31
import GTG
29
32
from GTG              import _
30
33
from GTG.tools.dates  import date_today, no_date, Date
31
34
from datetime         import datetime
32
 
from GTG.core.tree    import TreeNode
 
35
from GTG.tools.liblarch.tree    import TreeNode
33
36
from GTG.tools.logger import Log
 
37
from GTG.tools.dates             import no_date,\
 
38
                                        FuzzyDate, \
 
39
                                        get_canonical_date
34
40
 
35
41
 
36
42
class Task(TreeNode):
64
70
        self.req = requester
65
71
        #If we don't have a newtask, we will have to load it.
66
72
        self.loaded = newtask
67
 
        if self.loaded:
68
 
            self.req._task_loaded(self.tid)
 
73
        #Should not be necessary with the new backends
 
74
#        if self.loaded:
 
75
#            self.req._task_loaded(self.tid)
69
76
        self.attributes={}
70
77
        self._modified_update()
71
78
 
76
83
        #avoid doing it multiple times
77
84
        if not self.loaded:
78
85
            self.loaded = True
79
 
            if signal:
80
 
                self.req._task_loaded(self.tid)
81
 
                #self.req._task_modified(self.tid)
 
86
            for t in self.get_tags():
 
87
                t.modified()
 
88
#            if signal:
 
89
#                self.req._task_loaded(self.tid)
82
90
 
83
91
    def set_to_keep(self):
84
92
        self.can_be_deleted = False
99
107
        if self.uuid == "":
100
108
            self.set_uuid(uuid.uuid4())
101
109
            self.sync()
102
 
        return self.uuid
 
110
        return str(self.uuid)
103
111
 
104
112
    def get_remote_ids(self):
105
113
        '''
139
147
            return True
140
148
        else:
141
149
            return False
 
150
            
 
151
    #TODO : should we merge this function with set_title ?
 
152
    def set_complex_title(self,text,tags=[]):
 
153
        due_date = no_date
 
154
        defer_date = no_date
 
155
        if text:
 
156
            
 
157
            # Get tags in the title
 
158
            #NOTE: the ?: tells regexp that the first one is 
 
159
            # a non-capturing group, so it must not be returned
 
160
            # to findall. http://www.amk.ca/python/howto/regex/regex.html
 
161
            # ~~~~Invernizzi
 
162
            for match in re.findall(r'(?:^|[\s])(@\w+)', text):
 
163
                tags.append(GTG.core.tagstore.Tag(match, self.req))
 
164
                # Remove the @
 
165
                #text =text.replace(match,match[1:],1)
 
166
            # Get attributes
 
167
            regexp = r'([\s]*)([\w-]+):([^\s]+)'
 
168
            for spaces, attribute, args in re.findall(regexp, text):
 
169
                valid_attribute = True
 
170
                if attribute.lower() in ["tags", "tag"] or \
 
171
                   attribute.lower() in [_("tags"), _("tag")]:
 
172
                    for tag in args.split(","):
 
173
                        if not tag.startswith("@") :
 
174
                            tag = "@"+tag
 
175
                        tags.append(GTG.core.tagstore.Tag(tag, self.req))
 
176
                elif attribute.lower() == "defer" or \
 
177
                     attribute.lower() == _("defer"):
 
178
                    defer_date = get_canonical_date(args)
 
179
                    if not defer_date:
 
180
                        valid_attribute = False
 
181
                elif attribute.lower() == "due" or \
 
182
                     attribute.lower() == _("due"):
 
183
                    due_date = get_canonical_date(args)
 
184
                    if not due_date:
 
185
                        valid_attribute = False
 
186
                else:
 
187
                    # attribute is unknown
 
188
                    valid_attribute = False
 
189
                if valid_attribute:
 
190
                    # if the command is valid we have to remove it
 
191
                    # from the task title
 
192
                    text = \
 
193
                        text.replace("%s%s:%s" % (spaces, attribute, args), "")
 
194
#            # Create the new task
 
195
#            task = self.req.new_task(tags=[t.get_name() for t in tags], newtask=True)
 
196
            for t in tags:
 
197
                self.add_tag(t.get_name())
 
198
            if text != "":
 
199
                self.set_title(text.strip())
 
200
                self.set_to_keep()
 
201
            self.set_due_date(due_date)
 
202
            self.set_start_date(defer_date)
142
203
 
143
204
    def set_status(self, status, donedate=None):
144
205
        old_status = self.status
181
242
        return self.status
182
243
 
183
244
    def get_modified(self):
184
 
        return self.modified
 
245
        return self.last_modified
185
246
 
186
247
    def get_modified_string(self):
187
 
        return self.modified.strftime("%Y-%m-%dT%H:%M:%S")
 
248
        return self.last_modified.strftime("%Y-%m-%dT%H:%M:%S")
188
249
 
189
250
    def set_modified(self, modified):
190
 
        self.modified = modified
 
251
        self.last_modified = modified
191
252
 
192
253
    def set_due_date(self, fulldate):
193
254
        assert(isinstance(fulldate, Date))
333
394
                for t in self.get_tags():
334
395
                    child.tag_added(t.get_name())
335
396
            self.sync()
336
 
            #This one should be handled by the self.call_modified()
337
 
#            child.sync()
338
397
            return True
339
398
        else:
340
399
            Log.debug("child addition failed (or still pending)")
390
449
 
391
450
    ### PARENTS ##############################################################
392
451
 
393
 
    #Take a tid object as parameter
394
 
    def add_parent(self, parent_tid):
395
 
        #FIXME : the sync should be automatically done
396
 
        #at the tree level. remove this function
397
 
        Log.debug("adding parent %s to task %s" %(parent_tid, self.get_id()))
398
 
        added = TreeNode.add_parent(self, parent_tid)
399
 
        if added:
400
 
            self.sync()
401
 
            #the parent is handled by the sync
402
 
#            self.req.get_task(parent_tid).sync()
403
 
            return True
404
 
        else:
405
 
            return False
 
452
#   Not necessary anymore with liblarch
 
453
#    #Take a tid object as parameter
 
454
#    def add_parent(self, parent_tid):
 
455
#        #FIXME : the sync should be automatically done
 
456
#        #at the tree level. remove this function
 
457
#        Log.debug("adding parent %s to task %s" %(parent_tid, self.get_id()))
 
458
#        added = TreeNode.add_parent(self, parent_tid)
 
459
#        if added:
 
460
#            self.sync()
 
461
#            #the parent is handled by the sync
 
462
##            self.req.get_task(parent_tid).sync()
 
463
#            return True
 
464
#        else:
 
465
#            return False
406
466
 
407
 
    #Take a tid as parameter
408
 
    def remove_parent(self, tid):
409
 
        #FIXME : the sync should be automatically done
410
 
        #at the tree level. remove this function
411
 
        TreeNode.remove_parent(self,tid)
412
 
        self.sync()
413
 
        parent = self.req.get_task(tid)
414
 
        if parent:
415
 
            parent.sync()
 
467
#    #Take a tid as parameter
 
468
#    def remove_parent(self, tid):
 
469
#        #FIXME : the sync should be automatically done
 
470
#        #at the tree level. remove this function
 
471
#        TreeNode.remove_parent(self,tid)
 
472
#        self.sync()
 
473
#        parent = self.req.get_task(tid)
 
474
#        if parent:
 
475
#            parent.sync()
416
476
 
417
477
    #Return true is the task has parent
418
478
    #If tag is provided, return True only
419
479
    #if the parent has this particular tag
420
 
    #FIXME : this function should be removed. Use the tree instead !
 
480
    #FIXME : this function should be removed. Use the liblarch instead !
421
481
    def has_parents(self, tag=None):
422
482
        has_par = TreeNode.has_parent(self)
423
483
        #The "all tag" argument
449
509
        """
450
510
        return self.attributes.get((namespace, att_name), None)
451
511
 
452
 
    #Method called before the task is deleted
453
 
    #This method is called by the datastore and should not be called directly
454
 
    #Use the requester
455
 
    def delete(self):
456
 
        #we issue a delete for all the children
457
 
        for task in self.get_subtasks():
458
 
            #I think it's superfluous (invernizzi)
459
 
            #task.remove_parent(self.get_id())
460
 
            task.delete()
461
 
        #we tell the parents we have to go
462
 
        for i in self.get_parents():
463
 
            task = self.req.get_task(i)
464
 
            task.remove_child(self.get_id())
465
 
        #we tell the tags about the deletion
466
 
        for tagname in self.tags:
467
 
            tag = self.req.get_tag(tagname)
468
 
            tag.remove_task(self.get_id())
469
 
        #then we signal the we are ready to be removed
470
 
        self.req._task_deleted(self.get_id())
471
 
 
472
512
    def sync(self):
473
513
        self._modified_update()
474
514
        if self.is_loaded():
475
 
            self.call_modified()
 
515
            #This is a liblarch call to the TreeNode ancestor
 
516
            gobject.idle_add(self.modified)
 
517
            for t in self.get_tags():
 
518
                gobject.idle_add(t.modified)
476
519
            return True
477
520
        else:
478
521
            return False
479
 
    
480
 
    #This function send the modified signals for the tasks, 
481
 
    #parents and children
482
 
    def call_modified(self):
483
 
        #we first modify children
484
 
        for s in self.get_children():
485
 
            self.req._task_modified(s)
486
 
        #then the task
487
 
        self.req._task_modified(self.tid)
488
 
        #then parents
489
 
        for p in self.get_parents():
490
 
            self.req._task_modified(p)
491
522
 
492
523
    def _modified_update(self):
493
524
        '''
494
525
        Updates the modified timestamp
495
526
        '''
496
 
        self.modified = datetime.now()
 
527
        self.last_modified = datetime.now()
497
528
 
498
529
### TAG FUNCTIONS ############################################################
499
530
#
505
536
    def get_tags(self):
506
537
        l = []
507
538
        for tname in self.tags:
508
 
            l.append(self.req.get_tag(tname))
 
539
            tag = self.req.get_tag(tname)
 
540
            if not tag:
 
541
                tag = self.req.new_tag(tname)
 
542
            l.append(tag)
509
543
        return l
510
544
        
511
545
    def rename_tag(self, old, new):
513
547
        enew = saxutils.escape(saxutils.unescape(new))
514
548
        self.content = self.content.replace(eold, enew)
515
549
        self.remove_tag(old)
516
 
        self.req._tag_modified(old)
 
550
        self.req.get_tag(old).modified()
517
551
        self.tag_added(new)
518
 
        self.req._tag_modified(new)
 
552
        self.req.get_tag(new).modifiel()
519
553
        self.sync()
520
554
 
521
555
    def tag_added(self, tagname):
524
558
        """
525
559
        #print "tag %s added to task %s" %(tagname,self.get_id())
526
560
        t = tagname.encode("UTF-8")
527
 
        tag = self.req.get_tag(t)
528
 
        if not tag:
529
 
            tag = self.req.new_tag(t)
530
 
        tag.add_task(self.get_id())
531
561
        #Do not add the same tag twice
532
562
        if not t in self.tags:
533
563
            self.tags.append(t)
536
566
            for child in self.get_subtasks():
537
567
                if child.can_be_deleted:
538
568
                    child.add_tag(t)
539
 
            self.req._tag_modified(t)
 
569
            if self.is_loaded():
 
570
                tag = self.req.get_tag(t)
 
571
                if not tag:
 
572
                    tag = self.req.new_tag(t)
 
573
                tag.modified()
540
574
            return True
541
575
    
542
576
    def add_tag(self, tagname):
567
601
 
568
602
    #remove by tagname
569
603
    def remove_tag(self, tagname):
570
 
        t = self.req.get_tag(tagname)
571
604
        modified = False
572
 
        if t:
573
 
            t.remove_task(self.get_id())
574
 
            modified = True
575
605
        if tagname in self.tags:
576
606
            self.tags.remove(tagname)
577
607
            modified = True
580
610
                    child.remove_tag(tagname)
581
611
        self.content = self._strip_tag(self.content, tagname)
582
612
        if modified:
583
 
            self.req._tag_modified(tagname)
 
613
            tag = self.req.get_tag(tagname)
 
614
            tag.modified()
584
615
    
585
616
    def set_only_these_tags(self, tags_list):
586
617
        '''
594
625
                self.remove_tag(tag)
595
626
        for tag in tags_list:
596
627
            self.add_tag(tag)
597
 
                       
 
628
 
598
629
    def _strip_tag(self, text, tagname,newtag=''):
599
630
        return (text
600
631
                    .replace('<tag>%s</tag>\n\n'%(tagname), newtag) #trail \n