コード例 #1
0
ファイル: monitor.py プロジェクト: HieronymusCH/TaskCoach
 def unmonitorClass(self, klass):
     if klass in self._classes:
         for name in klass.monitoredAttributes():
             eventType = getattr(klass, '%sChangedEventType' % name)()    
             if eventType.startswith('pubsub'):
                 pub.unsubscribe(self.onAttributeChanged, eventType)
             else:
                 self.removeObserver(self.onAttributeChanged_Deprecated, eventType)
         if issubclass(klass, ObservableComposite):
             self.removeObserver(self.onChildAdded, klass.addChildEventType())
             self.removeObserver(self.onChildRemoved, klass.removeChildEventType())
         if issubclass(klass, CategorizableCompositeObject):
             self.removeObserver(self.onCategoryAdded, klass.categoryAddedEventType())
             self.removeObserver(self.onCategoryRemoved, klass.categoryRemovedEventType())
         if issubclass(klass, Task):
             pub.unsubscribe(self.onEffortAddedOrRemoved, Task.effortsChangedEventType())
             pub.unsubscribe(self.onPrerequisitesChanged, Task.prerequisitesChangedEventType())
         if issubclass(klass, NoteOwner):
             self.removeObserver(self.onOtherObjectAdded, klass.noteAddedEventType())
             self.removeObserver(self.onOtherObjectRemoved, klass.noteRemovedEventType())
         if issubclass(klass, AttachmentOwner):
             self.removeObserver(self.onOtherObjectAdded, klass.attachmentAddedEventType())
             self.removeObserver(self.onOtherObjectRemoved, klass.attachmentRemovedEventType())
         if issubclass(klass, Effort):
             pub.unsubscribe(self.onEffortTaskChanged, Effort.taskChangedEventType())
         self._classes.remove(klass)
コード例 #2
0
class TwoWayNewTasksState4(BaseState):
    def init(self):
        super(TwoWayNewTasksState4, self).init('ssddfz[s]', self.newTasksCount)

    def handleNewObject(self, (subject, description, startDate, dueDate,
                               completionDateTime, parentId, categories)):
        parent = self.taskMap[parentId] if parentId and self.taskMap.has_key(
            parentId) else None

        if self.version < 5:
            startDateTime = DateTime() if startDate == Date() else DateTime(
                year=startDate.year,
                month=startDate.month,
                day=startDate.day,
                hour=self.disp().settings.getint('view', 'efforthourstart'))

            dueDateTime = DateTime() if dueDate == Date() else DateTime(
                year=dueDate.year,
                month=dueDate.month,
                day=dueDate.day,
                hour=self.disp().settings.getint('view', 'efforthourend'))

        task = Task(subject=subject,
                    description=description,
                    startDateTime=startDateTime,
                    dueDateTime=dueDateTime,
                    completionDateTime=completionDateTime,
                    parent=parent)

        self.disp().window.addIPhoneTask(task, [self.categoryMap[catId] for catId in categories \
                                                    if self.categoryMap.has_key(catId)])
        self.disp().log(_('New task %s'), task.id())

        self.taskMap[task.id()] = task
        self.pack('s', task.id())
コード例 #3
0
ファイル: tasksource.py プロジェクト: HieronymusCH/TaskCoach
    def _parseObject(self, item):
        parser = vcal.VCalendarParser()
        parser.parse(map(lambda x: x.rstrip('\r'), item.data.split('\n')))

        categories = parser.tasks[0].pop('categories', [])

        task = Task(**parser.tasks[0])

        for category in categories:
            categoryObject = self.categoryList.findCategoryByName(category)
            if categoryObject is None:
                categoryObject = Category(category)
                self.categoryList.extend([categoryObject])
            task.addCategory(categoryObject)

        return task
コード例 #4
0
 def OnAdd(self, event):  # pylint: disable=W0613
     template = Task(subject=_('New task template'))
     for name in ('plannedstartdatetmpl', 'duedatetmpl',
                  'completiondatetmpl', 'remindertmpl'):
         setattr(template, name, None)
     theTask = self._templates.addTemplate(template)
     self.appendTemplate(self._root, theTask)
コード例 #5
0
    def _parseObject(self, item):
        parser = ical.VCalendarParser()
        parser.parse(map(lambda x: x.rstrip('\r'), item.data.split('\n')))

        categories = parser.tasks[0].pop('categories', [])

        kwargs = dict([(k, v) for k, v in parser.tasks[0].items() if k in inspect.getargspec(Task.__init__)[0]])
        task = Task(**kwargs)

        for category in categories:
            categoryObject = self.categoryList.findCategoryByName(category)
            if categoryObject is None:
                categoryObject = Category(category)
                self.categoryList.extend([categoryObject])
            task.addCategory(categoryObject)

        return task
コード例 #6
0
 def unmonitorClass(self, klass):
     if klass in self._classes:
         for name in klass.monitoredAttributes():
             eventType = getattr(klass, '%sChangedEventType' % name)()
             if eventType.startswith('pubsub'):
                 pub.unsubscribe(self.onAttributeChanged, eventType)
             else:
                 self.removeObserver(self.onAttributeChanged_Deprecated,
                                     eventType)
         if issubclass(klass, ObservableComposite):
             self.removeObserver(self.onChildAdded,
                                 klass.addChildEventType())
             self.removeObserver(self.onChildRemoved,
                                 klass.removeChildEventType())
         if issubclass(klass, CategorizableCompositeObject):
             self.removeObserver(self.onCategoryAdded,
                                 klass.categoryAddedEventType())
             self.removeObserver(self.onCategoryRemoved,
                                 klass.categoryRemovedEventType())
         if issubclass(klass, Task):
             pub.unsubscribe(self.onEffortAddedOrRemoved,
                             Task.effortsChangedEventType())
             pub.unsubscribe(self.onPrerequisitesChanged,
                             Task.prerequisitesChangedEventType())
         if issubclass(klass, NoteOwner):
             self.removeObserver(self.onOtherObjectAdded,
                                 klass.noteAddedEventType())
             self.removeObserver(self.onOtherObjectRemoved,
                                 klass.noteRemovedEventType())
         if issubclass(klass, AttachmentOwner):
             self.removeObserver(self.onOtherObjectAdded,
                                 klass.attachmentAddedEventType())
             self.removeObserver(self.onOtherObjectRemoved,
                                 klass.attachmentRemovedEventType())
         if issubclass(klass, Effort):
             pub.unsubscribe(self.onEffortTaskChanged,
                             Effort.taskChangedEventType())
         self._classes.remove(klass)
コード例 #7
0
class TwoWayNewTasksState5(BaseState):
    def init(self):
        super(TwoWayNewTasksState5, self).init('ssffffiiiiiz[s]',
                                               self.newTasksCount)

    def handleNewObject(self,
                        (subject, description, startDateTime, dueDateTime,
                         completionDateTime, reminderDateTime, priority,
                         hasRecurrence, recPeriod, recRepeat, recSameWeekday,
                         parentId, categories)):
        parent = self.taskMap[parentId] if parentId else None

        recurrence = None
        if hasRecurrence:
            recurrence = Recurrence(unit={
                0: 'daily',
                1: 'weekly',
                2: 'monthly',
                3: 'yearly'
            }[recPeriod],
                                    amount=recRepeat,
                                    sameWeekday=recSameWeekday)

        task = Task(subject=subject,
                    description=description,
                    startDateTime=startDateTime,
                    dueDateTime=dueDateTime,
                    completionDateTime=completionDateTime,
                    parent=parent,
                    recurrence=recurrence,
                    priority=priority)

        # Don't start a timer from this thread...
        wx.CallAfter(task.setReminder, reminderDateTime)

        self.disp().window.addIPhoneTask(task, [self.categoryMap[catId] for catId in categories \
                                                    if self.categoryMap.has_key(catId)])
        self.disp().log(_('New task %s'), task.id())

        self.taskMap[task.id()] = task
        self.pack('s', task.id())
コード例 #8
0
class TwoWayNewTasksState(BaseState):
    def init(self):
        super(TwoWayNewTasksState, self).init('ssddd[s]', self.newTasksCount)

    def handleNewObject(self, (subject, description, startDate, dueDate,
                               completionDate, categories)):
        task = Task(subject=subject,
                    description=description,
                    startDateTime=DateTime(startDate.year, startDate.month,
                                           startDate.day),
                    dueDateTime=DateTime(dueDate.year, dueDate.month,
                                         dueDate.day),
                    completionDateTime=DateTime(completionDate.year,
                                                completionDate.month,
                                                completionDate.day))

        self.disp().window.addIPhoneTask(task, [self.categoryMap[catId] for catId in categories \
                                                    if self.categoryMap.has_key(catId)])
        self.disp().log(_('New task %s'), task.id())

        self.taskMap[task.id()] = task
        self.pack('s', task.id())
コード例 #9
0
class FullFromDeviceTaskState(BaseState):
    def init(self):
        super(FullFromDeviceTaskState, self).init('ssddd[s]', self.taskCount)

    def handleNewObject(self, (subject, description, startDate, dueDate,
                               completionDate, categories)):
        task = Task(subject=subject,
                    description=description,
                    startDateTime=DateTime(startDate.year, startDate.month,
                                           startDate.day),
                    dueDateTime=DateTime(dueDate.year, dueDate.month,
                                         dueDate.day),
                    completionDateTime=DateTime(completionDate.year,
                                                completionDate.month,
                                                completionDate.day))

        self.disp().window.addIPhoneTask(
            task, [self.categoryMap[id_] for id_ in categories])

        self.count += 1
        self.ui.SetProgress(self.count, self.total)

        self.pack('s', task.id())
コード例 #10
0
    def read(self, **kwargs):
        fp = tempfile.TemporaryFile()
        fp.write(file(kwargs['filename'], 'rb').read().decode(kwargs['encoding']).encode('UTF-8'))
        fp.seek(0)

        rx1 = re.compile(r'^(\d+):(\d+)$')
        rx2 = re.compile(r'^(\d+):(\d+):(\d+)$')

        # When fields are associated with categories, create a top-level category for the
        # field and a subcategory for each possible value.

        toplevelCategories = dict()
        for idx, headerName in enumerate(kwargs['fields']):
            if kwargs['mappings'][idx] == _('Category'):
                category = Category(subject=headerName)
                toplevelCategories[headerName] = (category, dict())
                self.categoryList.append(category)

        reader = csv.reader(fp, dialect=kwargs['dialect'])
        if kwargs['hasHeaders']:
            reader.next()

        tasksById = dict()
        tasks = []

        for index, line in enumerate(reader):
            if kwargs['importSelectedRowsOnly'] and index not in kwargs['selectedRows']:
                continue
            subject = _('No subject')
            id_ = None
            description = StringIO.StringIO()
            categories = []
            priority = 0
            startDate = None
            dueDate = None
            completionDate = None
            budget = TimeDelta()
            fixedFee = 0.0
            hourlyFee = 0.0

            for idx, fieldValue in enumerate(line):
                if kwargs['mappings'][idx] == _('ID'):
                    id_ = fieldValue.decode('UTF-8')
                elif kwargs['mappings'][idx] == _('Subject'):
                    subject = fieldValue.decode('UTF-8')
                elif kwargs['mappings'][idx] == _('Description'):
                    description.write(fieldValue.decode('UTF-8'))
                    description.write(u'\n')
                elif kwargs['mappings'][idx] == _('Category') and fieldValue:
                    name = fieldValue.decode('UTF-8')
                    parent, cats = toplevelCategories[kwargs['fields'][idx]]
                    if name in cats:
                        theCat = cats[name]
                    else:
                        theCat = Category(subject=name)
                        parent.addChild(theCat)
                        cats[name] = theCat
                        self.categoryList.append(theCat)
                    categories.append(theCat)
                    toplevelCategories[kwargs['fields'][idx]] = (parent, cats)
                elif kwargs['mappings'][idx] == _('Priority'):
                    try:
                        priority = int(fieldValue)
                    except ValueError:
                        pass
                elif kwargs['mappings'][idx] == _('Start date'):
                    if fieldValue != '':
                        try:
                            startDate = dparser.parse(fieldValue.decode('UTF-8'), fuzzy=True).replace(tzinfo=None)
                            startDate = DateTime(startDate.year, startDate.month, startdate.day, 0, 0, 0)
                        except:
                            pass
                elif kwargs['mappings'][idx] == _('Due date'):
                    if fieldValue != '':
                        try:
                            dueDate = dparser.parse(fieldValue.decode('UTF-8'), fuzzy=True).replace(tzinfo=None)
                            dueDate = DateTime(dueDate.year, dueDate.month, dueDate.day, 23, 59, 0)
                        except:
                            pass
                elif kwargs['mappings'][idx] == _('Completion date'):
                    if fieldValue != '':
                        try:
                            completionDate = dparser.parse(fieldValue.decode('UTF-8'), fuzzy=True).replace(tzinfo=None)
                            completionDate = DateTime(completionDate.year, completionDate.month, completionDate.day, 12, 0, 0)
                        except:
                            pass
                elif kwargs['mappings'][idx] == _('Budget'):
                    try:
                        value = float(fieldValue)
                        hours = int(math.floor(value))
                        minutes = int(60 * (value - hours))
                        budget = TimeDelta(hours=hours, minutes=minutes, seconds=0)
                    except ValueError:
                        mt = rx1.search(fieldValue)
                        if mt:
                            budget = TimeDelta(hours=int(mt.group(1)), minutes=int(mt.group(2)), seconds=0)
                        else:
                            mt = rx2.search(fieldValue)
                            if mt:
                                budget = TimeDelta(hours=int(mt.group(1)), minutes=int(mt.group(2)), seconds=int(mt.group(3)))
                elif kwargs['mappings'][idx] == _('Fixed fee'):
                    try:
                        fixedFee = float(fieldValue)
                    except ValueError:
                        pass
                elif kwargs['mappings'][idx] == _('Hourly fee'):
                    try:
                        hourlyFee = float(fieldValue)
                    except ValueError:
                        pass

            task = Task(subject=subject,
                        description=description.getvalue(),
                        priority=priority,
                        startDateTime=startDate,
                        dueDateTime=dueDate,
                        completionDateTime=completionDate,
                        budget=budget,
                        fixedFee=fixedFee,
                        hourlyFee=hourlyFee)

            if id_ is not None:
                tasksById[id_] = task

            for category in categories:
                category.addCategorizable(task)
                task.addCategory(category)

            tasks.append(task)

        # OmniFocus uses the task's ID to keep track of hierarchy: 1 => 1.1 and 1.2, etc...

        if tasksById:
            ids = []
            for id_, task in tasksById.items():
                try:
                    ids.append(tuple(map(int, id_.split('.'))))
                except ValueError:
                    self.taskList.append(task)

            ids.sort()
            ids.reverse()

            for id_ in ids:
                sid = '.'.join(map(str, id_))
                if len(id_) >= 2:
                    pid = '.'.join(map(str, id_[:-1]))
                    if pid in tasksById:
                        tasksById[pid].addChild(tasksById[sid])
                else:
                    self.taskList.append(tasksById[sid])
        else:
            self.taskList.extend(tasks)
コード例 #11
0
    def read(self, **kwargs):
        fp = tempfile.TemporaryFile()
        fp.write(file(kwargs['filename'], 'rb').read().decode(kwargs['encoding']).encode('UTF-8'))
        fp.seek(0)
        
        rx1 = re.compile(r'^(\d+):(\d+)$')
        rx2 = re.compile(r'^(\d+):(\d+):(\d+)$')

        reader = self.createReader(fp, kwargs['dialect'], kwargs['hasHeaders'])
        dayfirst = kwargs['dayfirst']
        tasksById = dict()
        tasks = []

        for index, line in enumerate(reader):
            if kwargs['importSelectedRowsOnly'] and index not in kwargs['selectedRows']:
                continue
            subject = _('No subject')
            id_ = None
            description = StringIO.StringIO()
            categories = []
            priority = 0
            actualStartDateTime = None
            plannedStartDateTime = None
            dueDateTime = None
            completionDateTime = None
            reminderDateTime = None
            budget = TimeDelta()
            fixedFee = 0.0
            hourlyFee = 0.0
            percentComplete = 0

            for idx, fieldValue in enumerate(line):
                if kwargs['mappings'][idx] == _('ID'):
                    id_ = fieldValue.decode('UTF-8')
                elif kwargs['mappings'][idx] == _('Subject'):
                    subject = fieldValue.decode('UTF-8')
                elif kwargs['mappings'][idx] == _('Description'):
                    description.write(fieldValue.decode('UTF-8'))
                    description.write(u'\n')
                elif kwargs['mappings'][idx] == _('Category') and fieldValue:
                    name = fieldValue.decode('UTF-8')
                    if name.startswith('(') and name.endswith(')'):
                        continue  # Skip categories of subitems
                    cat = self.categoryList.findCategoryByName(name)
                    if not cat:
                        cat = self.createCategory(name)
                    categories.append(cat)
                elif kwargs['mappings'][idx] == _('Priority'):
                    try:
                        priority = int(fieldValue)
                    except ValueError:
                        pass
                elif kwargs['mappings'][idx] == _('Actual start date'):
                    actualStartDateTime = self.parseDateTime(fieldValue, dayfirst=dayfirst)
                elif kwargs['mappings'][idx] == _('Planned start date'):
                    plannedStartDateTime = self.parseDateTime(fieldValue, dayfirst=dayfirst)
                elif kwargs['mappings'][idx] == _('Due date'):
                    dueDateTime = self.parseDateTime(fieldValue, 23, 59, 59, dayfirst=dayfirst) 
                elif kwargs['mappings'][idx] == _('Completion date'):
                    completionDateTime = self.parseDateTime(fieldValue, 12, 0, 0, dayfirst=dayfirst) 
                elif kwargs['mappings'][idx] == _('Reminder date'):
                    reminderDateTime = self.parseDateTime(fieldValue, dayfirst=dayfirst)
                elif kwargs['mappings'][idx] == _('Budget'):
                    try:
                        value = float(fieldValue)
                        hours = int(math.floor(value))
                        minutes = int(60 * (value - hours))
                        budget = TimeDelta(hours=hours, minutes=minutes, seconds=0)
                    except ValueError:
                        mt = rx1.search(fieldValue)
                        if mt:
                            budget = TimeDelta(hours=int(mt.group(1)), minutes=int(mt.group(2)), seconds=0)
                        else:
                            mt = rx2.search(fieldValue)
                            if mt:
                                budget = TimeDelta(hours=int(mt.group(1)), minutes=int(mt.group(2)), seconds=int(mt.group(3)))
                elif kwargs['mappings'][idx] == _('Fixed fee'):
                    try:
                        fixedFee = float(fieldValue)
                    except ValueError:
                        pass
                elif kwargs['mappings'][idx] == _('Hourly fee'):
                    try:
                        hourlyFee = float(fieldValue)
                    except ValueError:
                        pass
                elif kwargs['mappings'][idx] == _('Percent complete'):
                    try:
                        percentComplete = max(0, min(100, int(fieldValue)))
                    except ValueError:
                        pass

            task = Task(subject=subject,
                        description=description.getvalue(),
                        priority=priority,
                        actualStartDateTime=actualStartDateTime,
                        plannedStartDateTime=plannedStartDateTime,
                        dueDateTime=dueDateTime,
                        completionDateTime=completionDateTime,
                        reminder=reminderDateTime,
                        budget=budget,
                        fixedFee=fixedFee,
                        hourlyFee=hourlyFee,
                        percentageComplete=percentComplete)

            if id_ is not None:
                tasksById[id_] = task

            for category in categories:
                category.addCategorizable(task)
                task.addCategory(category)

            tasks.append(task)

        # OmniFocus uses the task's ID to keep track of hierarchy: 1 => 1.1 and 1.2, etc...

        if tasksById:
            ids = []
            for id_, task in tasksById.items():
                try:
                    ids.append(tuple(map(int, id_.split('.'))))
                except ValueError:
                    self.taskList.append(task)

            ids.sort()
            ids.reverse()

            for id_ in ids:
                sid = '.'.join(map(str, id_))
                if len(id_) >= 2:
                    pid = '.'.join(map(str, id_[:-1]))
                    if pid in tasksById:
                        tasksById[pid].addChild(tasksById[sid])
                else:
                    self.taskList.append(tasksById[sid])
        else:
            self.taskList.extend(tasks)
コード例 #12
0
    def OnAdd(self, event):
        task = Task(subject=_('New task template'))
        self._templates.addTemplate(task)
        self._templateList.InsertStringItem(self._templateList.GetItemCount(), task.subject())

        self._Check()
コード例 #13
0
    def read(self, **kwargs):
        fp = tempfile.TemporaryFile()
        fp.write(
            file(kwargs['filename'],
                 'rb').read().decode(kwargs['encoding']).encode('UTF-8'))
        fp.seek(0)

        rx1 = re.compile(r'^(\d+):(\d+)$')
        rx2 = re.compile(r'^(\d+):(\d+):(\d+)$')

        reader = self.createReader(fp, kwargs['dialect'], kwargs['hasHeaders'])
        dayfirst = kwargs['dayfirst']
        tasksById = dict()
        tasks = []

        for index, line in enumerate(reader):
            if kwargs['importSelectedRowsOnly'] and index not in kwargs[
                    'selectedRows']:
                continue
            subject = _('No subject')
            id_ = None
            description = StringIO.StringIO()
            categories = []
            priority = 0
            actualStartDateTime = None
            plannedStartDateTime = None
            dueDateTime = None
            completionDateTime = None
            reminderDateTime = None
            budget = TimeDelta()
            fixedFee = 0.0
            hourlyFee = 0.0
            percentComplete = 0

            for idx, fieldValue in enumerate(line):
                if kwargs['mappings'][idx] == _('ID'):
                    id_ = fieldValue.decode('UTF-8')
                elif kwargs['mappings'][idx] == _('Subject'):
                    subject = fieldValue.decode('UTF-8')
                elif kwargs['mappings'][idx] == _('Description'):
                    description.write(fieldValue.decode('UTF-8'))
                    description.write(u'\n')
                elif kwargs['mappings'][idx] == _('Category') and fieldValue:
                    name = fieldValue.decode('UTF-8')
                    if name.startswith('(') and name.endswith(')'):
                        continue  # Skip categories of subitems
                    cat = self.categoryList.findCategoryByName(name)
                    if not cat:
                        cat = self.createCategory(name)
                    categories.append(cat)
                elif kwargs['mappings'][idx] == _('Priority'):
                    try:
                        priority = int(fieldValue)
                    except ValueError:
                        pass
                elif kwargs['mappings'][idx] == _('Actual start date'):
                    actualStartDateTime = self.parseDateTime(fieldValue,
                                                             dayfirst=dayfirst)
                elif kwargs['mappings'][idx] == _('Planned start date'):
                    plannedStartDateTime = self.parseDateTime(
                        fieldValue, dayfirst=dayfirst)
                elif kwargs['mappings'][idx] == _('Due date'):
                    dueDateTime = self.parseDateTime(fieldValue,
                                                     23,
                                                     59,
                                                     59,
                                                     dayfirst=dayfirst)
                elif kwargs['mappings'][idx] == _('Completion date'):
                    completionDateTime = self.parseDateTime(fieldValue,
                                                            12,
                                                            0,
                                                            0,
                                                            dayfirst=dayfirst)
                elif kwargs['mappings'][idx] == _('Reminder date'):
                    reminderDateTime = self.parseDateTime(fieldValue,
                                                          dayfirst=dayfirst)
                elif kwargs['mappings'][idx] == _('Budget'):
                    try:
                        value = float(fieldValue)
                        hours = int(math.floor(value))
                        minutes = int(60 * (value - hours))
                        budget = TimeDelta(hours=hours,
                                           minutes=minutes,
                                           seconds=0)
                    except ValueError:
                        mt = rx1.search(fieldValue)
                        if mt:
                            budget = TimeDelta(hours=int(mt.group(1)),
                                               minutes=int(mt.group(2)),
                                               seconds=0)
                        else:
                            mt = rx2.search(fieldValue)
                            if mt:
                                budget = TimeDelta(hours=int(mt.group(1)),
                                                   minutes=int(mt.group(2)),
                                                   seconds=int(mt.group(3)))
                elif kwargs['mappings'][idx] == _('Fixed fee'):
                    try:
                        fixedFee = float(fieldValue)
                    except ValueError:
                        pass
                elif kwargs['mappings'][idx] == _('Hourly fee'):
                    try:
                        hourlyFee = float(fieldValue)
                    except ValueError:
                        pass
                elif kwargs['mappings'][idx] == _('Percent complete'):
                    try:
                        percentComplete = max(0, min(100, int(fieldValue)))
                    except ValueError:
                        pass

            task = Task(subject=subject,
                        description=description.getvalue(),
                        priority=priority,
                        actualStartDateTime=actualStartDateTime,
                        plannedStartDateTime=plannedStartDateTime,
                        dueDateTime=dueDateTime,
                        completionDateTime=completionDateTime,
                        reminder=reminderDateTime,
                        budget=budget,
                        fixedFee=fixedFee,
                        hourlyFee=hourlyFee,
                        percentageComplete=percentComplete)

            if id_ is not None:
                tasksById[id_] = task

            for category in categories:
                category.addCategorizable(task)
                task.addCategory(category)

            tasks.append(task)

        # OmniFocus uses the task's ID to keep track of hierarchy: 1 => 1.1 and 1.2, etc...

        if tasksById:
            ids = []
            for id_, task in tasksById.items():
                try:
                    ids.append(tuple(map(int, id_.split('.'))))
                except ValueError:
                    self.taskList.append(task)

            ids.sort()
            ids.reverse()

            for id_ in ids:
                sid = '.'.join(map(str, id_))
                if len(id_) >= 2:
                    pid = '.'.join(map(str, id_[:-1]))
                    if pid in tasksById:
                        tasksById[pid].addChild(tasksById[sid])
                else:
                    self.taskList.append(tasksById[sid])
        else:
            self.taskList.extend(tasks)