예제 #1
0
파일: test_dates.py 프로젝트: jaesivsm/gtg
 def test_parse_fuzzy_dates(self):
     """ Parse fuzzy dates like now, soon, later, someday """
     self.assertEqual(Date("now"), Date.now())
     self.assertEqual(Date("soon"), Date.soon())
     self.assertEqual(Date("later"), Date.someday())
     self.assertEqual(Date("someday"), Date.someday())
     self.assertEqual(Date(""), Date.no_date())
예제 #2
0
    def test_due(self):
        expected1 = {
            'title': 'Do a thing',
            'tags': set(),
            'start': None,
            'due': Date.parse('monday'),
            'recurring': None
        }

        expected2 = {
            'title': 'Do a thing',
            'tags': set(),
            'start': None,
            'due': Date.parse('someday'),
            'recurring': None
        }

        expected3 = {
            'title': 'Do a thing',
            'tags': set(),
            'start': None,
            'due': Date.parse('2099/02/12'),
            'recurring': None
        }

        text1 = 'Do a thing due:monday'
        text2 = 'Do a thing due:monday'
        text3 = 'Do a thing due: monday'
        text4 = 'Do a thing due: someday'
        text5 = 'Do a thing due: 2099/02/12'

        self.assertEqual(expected1, parse(text1))
        self.assertEqual(expected1, parse(text2))
        self.assertEqual(expected1, parse(text3))
        self.assertEqual(expected3, parse(text5))
예제 #3
0
    def set_due_date(self, new_duedate):
        """Defines the task's due date."""
        def __get_defined_parent_list(task):
            """Recursively fetch a list of parents that have a defined due date
               which is not fuzzy"""
            parent_list = []
            for par_id in task.parents:
                par = self.req.get_task(par_id)
                if par.get_due_date().is_fuzzy():
                    parent_list += __get_defined_parent_list(par)
                else:
                    parent_list.append(par)
            return parent_list

        def __get_defined_child_list(task):
            """Recursively fetch a list of children that have a defined
               due date which is not fuzzy"""
            child_list = []
            for child_id in task.children:
                child = self.req.get_task(child_id)
                if child.get_due_date().is_fuzzy():
                    child_list += __get_defined_child_list(child)
                else:
                    child_list.append(child)
            return child_list

        old_due_date = self.due_date
        new_duedate_obj = Date(new_duedate)  # caching the conversion
        self.due_date = new_duedate_obj
        # If the new date is fuzzy or undefined, we don't update related tasks
        if not new_duedate_obj.is_fuzzy():
            # if the task's start date happens later than the
            # new due date, we update it (except for fuzzy dates)
            if not self.get_start_date().is_fuzzy() and \
                    self.get_start_date() > new_duedate_obj:
                self.set_start_date(new_duedate)
            # if some ancestors' due dates happen before the task's new
            # due date, we update them (except for fuzzy dates)
            for par in __get_defined_parent_list(self):
                if par.get_due_date() < new_duedate_obj:
                    par.set_due_date(new_duedate)
            # we must apply the constraints to the defined & non-fuzzy children
            # as well
            for sub in __get_defined_child_list(self):
                sub_duedate = sub.get_due_date()
                # if the child's due date happens later than the task's: we
                # update it to the task's new due date
                if sub_duedate > new_duedate_obj:
                    sub.set_due_date(new_duedate)
                # if the child's start date happens later than
                # the task's new due date, we update it
                # (except for fuzzy start dates)
                sub_startdate = sub.get_start_date()
                if not sub_startdate.is_fuzzy() and \
                        sub_startdate > new_duedate_obj:
                    sub.set_start_date(new_duedate)
        # If the date changed, we notify the change for the children since the
        # constraints might have changed
        if old_due_date != new_duedate_obj:
            self.recursive_sync()
예제 #4
0
파일: task.py 프로젝트: snoord/gtg
    def __init__(self, task_id, requester, newtask=False):
        super().__init__(task_id)
        # the id of this task in the project should be set
        # tid is a string ! (we have to choose a type and stick to it)
        assert(isinstance(task_id, str) or isinstance(task_id, str))
        self.tid = str(task_id)
        self.set_uuid(uuid.uuid4())
        self.remote_ids = {}
        self.content = ""
        self.title = _("My new task")
        # available status are: Active - Done - Dismiss - Note
        self.status = self.STA_ACTIVE

        self.recurring_term = None
        self.recurring = self.inherit_recursion()

        self.added_date = Date.no_date()
        if newtask:
            self.added_date = datetime.now()

        self.closed_date = Date.no_date()
        self.due_date = Date.no_date()
        self.start_date = Date.no_date()
        self.can_be_deleted = newtask
        # tags
        self.tags = []
        self.req = requester
        self.__main_treeview = requester.get_main_view()
        # If we don't have a newtask, we will have to load it.
        self.loaded = newtask
        # Should not be necessary with the new backends
#        if self.loaded:
#            self.req._task_loaded(self.tid)
        self.attributes = {}
        self._modified_update()
예제 #5
0
파일: task.py 프로젝트: snoord/gtg
 def set_start_date(self, fulldate):
     self.start_date = Date(fulldate)
     if not Date(fulldate).is_fuzzy() and \
         not self.due_date.is_fuzzy() and \
             Date(fulldate) > self.due_date:
         self.set_due_date(fulldate)
     self.sync()
예제 #6
0
파일: test_dates.py 프로젝트: jaesivsm/gtg
 def test_parse_fuzzy_dates_str(self):
     """ Print fuzzy dates in localized version """
     self.assertEqual(Date("now").localized_str, _("now"))
     self.assertEqual(Date("soon").localized_str, _("soon"))
     self.assertEqual(Date("later").localized_str, _("someday"))
     self.assertEqual(Date("someday").localized_str, _("someday"))
     self.assertEqual(Date("").localized_str, "")
예제 #7
0
파일: test_dates.py 프로젝트: jaesivsm/gtg
 def test_parse_local_fuzzy_dates(self):
     """ Parse fuzzy dates in their localized version """
     self.assertEqual(Date(_("now")), Date.now())
     self.assertEqual(Date(_("soon")), Date.soon())
     self.assertEqual(Date(_("later")), Date.someday())
     self.assertEqual(Date(_("someday")), Date.someday())
     self.assertEqual(Date(""), Date.no_date())
예제 #8
0
파일: quick_add.py 프로젝트: jaesivsm/gtg
def parse(text: str) -> Dict:
    """Parse contents of the quick add input."""

    result = {
        'title': '',
        'tags': set(),
        'start': None,
        'due': None,
        'recurring': None
    }

    for match in re.finditer(TAG_REGEX, text):
        data = match.group(0)
        result['tags'].add(data[1:])

    for match in re.finditer(TOKEN_REGEX, text):
        token = match.group(2)
        data = match.group(3)
        matched = False

        if token in TAGS_TOKEN:
            for tag in data.split(','):
                if tag:
                    # Strip @
                    if tag.startswith('@'):
                        tag = tag[1:]

                    result['tags'].add(tag)

            matched = True

        elif token in START_TOKEN:
            try:
                result['start'] = Date.parse(data)
                matched = True
            except ValueError:
                pass

        elif token in DUE_TOKEN:
            try:
                result['due'] = Date.parse(data)
                matched = True
            except ValueError:
                pass

        elif token in REPEAT_TOKEN:
            try:
                Date.today().parse_from_date(data)
                result['recurring'] = data
                matched = True
            except ValueError:
                pass

        # Remove this part from the title
        if matched:
            text = text.replace(match[0], '')

    result['title'] = text
    return result
예제 #9
0
 def get_gtg(self, task: Task, namespace: str = None):
     gtg_date = super().get_gtg(task, namespace)
     if isinstance(gtg_date, Date):
         if gtg_date.accuracy in {Accuracy.date, Accuracy.timezone,
                                  Accuracy.datetime}:
             return Date(self._normalize(gtg_date.dt_value))
         return gtg_date
     return Date(self._normalize(gtg_date))
예제 #10
0
 def sort_by_duedate(self, task1, task2, order):
     t1 = task1.get_urgent_date()
     t2 = task2.get_urgent_date()
     if t1 == Date.no_date():
         t1 = task1.get_due_date_constraint()
     if t2 == Date.no_date():
         t2 = task2.get_due_date_constraint()
     return self.__date_comp_continue(task1, task2, order, t1, t2)
예제 #11
0
파일: backend_rtm.py 프로젝트: snoord/gtg
 def get_due_date(self):
     """
     Gets the task due date
     """
     due = self.rtm_task.due
     if due == "":
         return Date.no_date()
     date = self.__time_rtm_to_datetime(due).date()
     return Date(date)
예제 #12
0
 def _get_dt_for_dav_writing(value):
     if isinstance(value, Date):
         if value.accuracy is Accuracy.timezone:
             return '', value.dt_value
         if value.accuracy is Accuracy.fuzzy:
             return str(value), value.dt_by_accuracy(Accuracy.timezone)
     else:
         value = Date(value)
     return '', value.dt_by_accuracy(Accuracy.timezone)
예제 #13
0
파일: test_task2.py 프로젝트: jaesivsm/gtg
    def test_toggle_dismiss_single(self):
        task = Task2(id=uuid4(), title='A Task')

        task.toggle_dismiss()
        self.assertEqual(task.status, Status.DISMISSED)
        self.assertEqual(task.date_closed, Date.today())

        task.toggle_dismiss()
        self.assertEqual(task.status, Status.ACTIVE)
        self.assertEqual(task.date_closed, Date.no_date())
예제 #14
0
파일: editor.py 프로젝트: tkdchen/gtg
    def on_date_cleared(self, widget, kind):
        """ Callback when a date is cleared through the popups. """

        if kind == GTGCalendar.DATE_KIND_START:
            self.task.set_start_date(Date.no_date())
            self.start_entry.set_text('')

        elif kind == GTGCalendar.DATE_KIND_DUE:
            self.task.set_due_date(Date.no_date())
            self.due_entry.set_text('')
예제 #15
0
파일: test_task2.py 프로젝트: jaesivsm/gtg
    def test_toggle_active_single(self):
        task = Task2(id=uuid4(), title='A Task')

        self.assertEqual(task.status, Status.ACTIVE)

        task.toggle_active()
        self.assertEqual(task.status, Status.DONE)
        self.assertEqual(task.date_closed, Date.today())

        task.toggle_active()
        self.assertEqual(task.status, Status.ACTIVE)
        self.assertEqual(task.date_closed, Date.no_date())
예제 #16
0
파일: task.py 프로젝트: sramkrishna/gtg
    def set_complex_title(self, text, tags=[]):
        if tags:
            assert (isinstance(tags[0], str))
        due_date = Date.no_date()
        defer_date = Date.no_date()
        if text:
            # Get tags in the title
            for match in extract_tags_from_text(text):
                tags.append(match)
            # Get attributes
            regexp = r'([\s]*)([\w-]+):\s*([^\s]+)'
            matches = re.findall(regexp, text, re.UNICODE)
            for spaces, attribute, args in matches:
                valid_attribute = True
                if attribute.lower() in ["tags", _("tags"), "tag", _("tag")]:
                    for tag in args.split(","):
                        if not tag.strip() == "@" and not tag.strip() == "":
                            if not tag.startswith("@"):
                                tag = "@" + tag
                            tags.append(tag)
                elif attribute.lower() in [
                        "defer", _("defer"), "start",
                        _("start")
                ]:
                    try:
                        defer_date = Date.parse(args)
                    except ValueError:
                        valid_attribute = False
                elif attribute.lower() == "due" or \
                        attribute.lower() == _("due"):
                    try:
                        due_date = Date.parse(args)
                    except:
                        valid_attribute = False
                else:
                    # attribute is unknown
                    valid_attribute = False

                if valid_attribute:
                    # remove valid attribute from the task title
                    text = \
                        text.replace(f"{spaces}{attribute}:{args}", "")

            for t in tags:
                self.add_tag(t)

            if text != "":
                self.set_title(text.strip())
                self.set_to_keep()

            self.set_due_date(due_date)
            self.set_start_date(defer_date)
예제 #17
0
def parse(text: str) -> Dict:
    """Parse contents of the quick add input."""

    result = {
        'title': '',
        'tags': set(),
        'start': None,
        'due': None,
        'recurring': None
    }

    for match in re.finditer(TAG_REGEX, text):
        data = match.group(0)
        result['tags'].add(data[1:])

    for match in re.finditer(TOKEN_REGEX, text):
        token = match.group(2)
        data = match.group(3)

        if token in TAGS_TOKEN:
            for t in data.split(','):
                # Strip @
                if t.startswith('@'):
                    t = t[1:]

                result['tags'].add(t)

        elif token in START_TOKEN:
            try:
                result['start'] = Date.parse(data)
            except ValueError:
                continue

        elif token in DUE_TOKEN:
            try:
                result['due'] = Date.parse(data)
            except ValueError:
                continue

        elif token in REPEAT_TOKEN:
            try:
                Date.today().parse_from_date(data)
                result['recurring'] = data
            except ValueError:
                continue

        # Remove this part from the title
        text = text[:match.start()] + text[match.end():]

    result['title'] = text
    return result
예제 #18
0
파일: tasks2.py 프로젝트: jaesivsm/gtg
    def __init__(self, id: UUID, title: str) -> None:
        self.id = id
        self.raw_title = title.strip('\t\n')
        self.content = ''
        self.tags = []
        self.children = []
        self.status = Status.ACTIVE
        self.parent = None

        self._date_added = Date.no_date()
        self._date_due = Date.no_date()
        self._date_start = Date.no_date()
        self._date_closed = Date.no_date()
        self._date_modified = Date(datetime.datetime.now())
예제 #19
0
파일: calendar.py 프로젝트: tkdchen/gtg
    def __day_selected(self, widget, date_type):
        if date_type == "RealDate":
            calendar_date = self.__calendar.get_date()
            date = self.__from_calendar_date_to_datetime(calendar_date)
            self.__date = Date(date)
        else:
            self.__date = Date(date_type)

        if self.__is_user_just_browsing_the_calendar:
            # this day-selected signal was caused by a month/year change
            self.__is_user_just_browsing_the_calendar = False
        else:
            # inform the Editor that the date has changed
            self.close_calendar()
            GLib.idle_add(self.emit, "date-changed")
예제 #20
0
    def bgcolor(self, node, standard_color):
        color = self.get_node_bgcolor(node)

        def __get_active_child_list(node):
            """ This function recursively fetches a list
            of all the children of a task which are active
            (i.e - the subtasks which are not marked as 'Done' or 'Dismissed'
            """
            child_list = []
            for child_id in node.children:
                child = node.req.get_task(child_id)
                child_list += __get_active_child_list(child)
                if child.get_status() in [child.STA_ACTIVE]:
                    child_list.append(child_id)
            return child_list

        child_list = __get_active_child_list(node)

        daysleft = None
        for child_id in child_list:
            child = self.req.get_task(child_id)
            if child.get_due_date() == Date.no_date():
                continue

            daysleft_of_child = child.get_due_date().days_left()
            if daysleft is None:
                daysleft = daysleft_of_child
                color = self.get_node_bgcolor(child)
            elif daysleft_of_child < daysleft:
                daysleft = daysleft_of_child
                color = self.get_node_bgcolor(child)

        return color
예제 #21
0
 def workview(self, task, parameters=None):
     wv = (self.active(task) and
           self.is_started(task) and
           self.is_workable(task) and
           self.no_disabled_tag(task) and
           task.get_due_date() != Date.someday())
     return wv
예제 #22
0
 def task_duedate_column(self, node):
     # We show the most constraining due date for task with no due dates.
     if node.get_due_date() == Date.no_date():
         return node.get_due_date_constraint().to_readable_string()
     else:
         # Other tasks show their due date (which *can* be fuzzy)
         return node.get_due_date().to_readable_string()
예제 #23
0
파일: editor.py 프로젝트: jaesivsm/gtg
    def date_focus_out(self, widget, event, date_kind):
        try:
            datetoset = Date.parse(widget.get_text())
        except ValueError:
            datetoset = None

        if datetoset is not None:
            # TODO: New Core
            t = self.app.ds.tasks.get(self.task.tid)

            if date_kind == GTGCalendar.DATE_KIND_START:
                self.task.set_start_date(datetoset)
                t.date_start = datetoset
                self.start_popover.popdown()

            elif date_kind == GTGCalendar.DATE_KIND_DUE:
                self.task.set_due_date(datetoset)
                t.date_due = datetoset
                self.due_popover.popdown()

            elif date_kind == GTGCalendar.DATE_KIND_CLOSED:
                self.task.set_closed_date(datetoset)
                t.date_closed = datetoset
                self.closed_popover.popdown()

            self.refresh_editor()
예제 #24
0
파일: calendar.py 프로젝트: tkdchen/gtg
 def __init__(self):
     super().__init__()
     self.__builder = Gtk.Builder()
     self.__builder.add_from_file(GnomeConfig.CALENDAR_UI_FILE)
     self.__date_kind = None
     self.__date = Date.no_date()
     self.__init_gtk__()
예제 #25
0
 def get_dav(self, todo=None, vtodo=None) -> Date:
     """Transforming to local naive,
     if original value MAY be naive and IS assuming UTC"""
     value = super().get_dav(todo, vtodo)
     if todo:
         vtodo = todo.instance.vtodo
     todo_value = vtodo.contents.get(self.dav_name)
     if todo_value and todo_value[0].params.get(self.FUZZY_MARK):
         return Date(todo_value[0].params[self.FUZZY_MARK][0])
     if isinstance(value, (date, datetime)):
         value = self._normalize(value)
     try:
         return Date(value)
     except ValueError:
         logger.error("Coudln't translate value %r", value)
         return Date.no_date()
예제 #26
0
파일: task.py 프로젝트: snoord/gtg
    def set_status(self, status, donedate=None):
        old_status = self.status
        self.can_be_deleted = False
        # No need to update children or whatever if the task is not loaded
        if status and self.is_loaded():
            # we first modify the status of the children
            # If Done, we set the done date
            if status in [self.STA_DONE, self.STA_DISMISSED]:
                for c in self.get_subtasks():
                    if c.get_status() in [self.STA_ACTIVE]:
                        c.set_status(status, donedate=donedate)

                # If the task is recurring, it must be duplicate with 
                # another task id and the next occurence of the task
                # Furthermore, the duplicated task's parents
                # should be set the the parent's previous task
                # as well as the children's.
                # Because we want every subtask that is recurring 
                # to occur another time after its parent has been set to done or dismiss.
                # only recurring tasks without any recurring parent can be duplicated.
                if self.recurring and not self.is_parent_recurring():
                    nexttask_tid = self.duplicate_recursively()
                    if self.has_parent():
                        for p_tid in self.get_parents():
                            par = self.req.get_task(p_tid)
                            if (par.is_loaded() and par.get_status() in
                                (self.STA_ACTIVE)):
                                par.add_child(nexttask_tid)

            # If we mark a task as Active and that some parent are not
            # Active, we break the parent/child relation
            # It has no sense to have an active subtask of a done parent.
            # (old_status check is necessary to avoid false positive a start)
            elif status in [self.STA_ACTIVE] and\
                    old_status in [self.STA_DONE, self.STA_DISMISSED]:
                if self.has_parent():
                    for p_tid in self.get_parents():
                        par = self.req.get_task(p_tid)
                        if par.is_loaded() and par.get_status() in\
                                [self.STA_DONE, self.STA_DISMISSED]:
                            # we can either break the parent/child relationship
                            # self.remove_parent(p_tid)
                            # or restore the parent too
                            par.set_status(self.STA_ACTIVE)
                # We dont mark the children as Active because
                # They might be already completed after all

        # then the task itself
        if status:
            self.status = status

        # Set closing date
        if status and status in [self.STA_DONE, self.STA_DISMISSED]:
            # to the specified date (if any)
            if donedate:
                self.closed_date = donedate
            # or to today
            else:
                self.closed_date = Date.today()
        self.sync()
예제 #27
0
파일: tasks2.py 프로젝트: jaesivsm/gtg
    def toggle_dismiss(self, propagate: bool = True) -> None:
        """Set this task to be dismissed."""

        if self.status is Status.ACTIVE:
            self.status = Status.DISMISSED
            self.date_closed = Date.today()

        elif self.status is Status.DISMISSED:
            self.status = Status.ACTIVE
            self.date_closed = Date.no_date()

            if self.parent and self.parent.status is not Status.ACTIVE:
                self.parent.toggle_dismiss(propagate=False)

        if propagate:
            for child in self.children:
                child.toggle_dismiss()
예제 #28
0
파일: test_task2.py 프로젝트: jaesivsm/gtg
    def test_toggle_dismiss_children(self):
        task = Task2(id=uuid4(), title='A Task')
        task2 = Task2(id=uuid4(), title='A Child Task')
        task.children.append(task2)
        task2.parent = task

        task.toggle_dismiss()
        self.assertEqual(task.status, Status.DISMISSED)
        self.assertEqual(task.date_closed, Date.today())
        self.assertEqual(task2.status, Status.DISMISSED)
        self.assertEqual(task2.date_closed, Date.today())

        task.toggle_dismiss()
        self.assertEqual(task.status, Status.ACTIVE)
        self.assertEqual(task.date_closed, Date.no_date())
        self.assertEqual(task2.status, Status.ACTIVE)
        self.assertEqual(task2.date_closed, Date.no_date())
예제 #29
0
파일: tasks2.py 프로젝트: jaesivsm/gtg
    def toggle_active(self, propagate: bool = True) -> None:
        """Toggle between possible statuses."""

        if self.status is Status.ACTIVE:
            self.status = Status.DONE
            self.date_closed = Date.today()

        else:
            self.status = Status.ACTIVE
            self.date_closed = Date.no_date()

            if self.parent and self.parent.status is not Status.ACTIVE:
                self.parent.toggle_active(propagate=False)

        if propagate:
            for child in self.children:
                child.toggle_active()
예제 #30
0
def _due_within(task, danger_zone):
    """
    Determine if a task is the danger zone.
    Convention: a danger zone of 1 day includes tasks due today.
    """
    ddate = task.get_due_date()
    if (ddate != Date.no_date()):
        if ddate.days_left() < danger_zone:
            return True
    return False