Exemple #1
0
    def test_container_removing(self):
        tac = TaskAttributeContainer()

        s = 'note=aiueo,repeat=2'
        tac.from_string(s)

        tac.remove_attribute('note')

        self.assert_exception(tac.get_note)
        self.assertEqual('repeat=2', tac.to_string())
Exemple #2
0
    def test_container_get_value_as_string(self):
        tac = TaskAttributeContainer()

        s = 'note=noteノート,repeat=1'
        tac.from_string(s)

        import taskattr
        self.assertEqual('noteノート', tac.get_value_as_string(taskattr.Note.KEY))
        # 非文字列値の場合, 文字列値が返ってくること.
        self.assertEqual('1', tac.get_value_as_string(taskattr.Repeat.KEY))
Exemple #3
0
    def test_container_if_key_not_exists(self):
        tac = TaskAttributeContainer()

        s = ''
        tac.from_string(s)

        # 存在しない時のgetはエラー
        self.assert_exception(tac.get_note)
        self.assert_exception(tac.get_repeat)

        # 存在しない時のsetは新規になる.
        tac.set_note('にゅーnote')
        tac.set_repeat(3)
        new_s = tac.to_string()
        self.assertEqual('note=にゅーnote,repeat=3', new_s)
Exemple #4
0
    def test_container_if_key_exists(self):
        tac = TaskAttributeContainer()

        # from_string
        s = 'note=noteノート,repeat=1'
        tac.from_string(s)

        # 一通りget
        self.assertEqual('noteノート', tac.get_note())
        self.assertEqual(1, tac.get_repeat())

        # 一通りset and 一通りto_string
        tac.set_note('にゅーnote')
        tac.set_repeat(3)
        new_s = tac.to_string()
        self.assertEqual('note=にゅーnote,repeat=3', new_s)
Exemple #5
0
    def test_container_empty_cases(self):
        tac = TaskAttributeContainer()

        tac.from_string('')
        self.assertEqual('', tac.to_string())
        self.assert_exception(tac.get_note)
Exemple #6
0
class TaskLine:
    LENGTH = 88
    BLANK_LINE = ' '*LENGTH

    def __init__(self, line, systemconfig):
        self._line = line
        self._systemconfig = systemconfig

        self._parse()

    def _parse(self):
        ln = self._line

        try:
             self._type       = Type(ln)
             self._date       = Date(ln)
             self._section    = Section(ln)
             self._number     = Number(ln)
             self._category   = Category(ln)
             self._name       = Name(ln)
             self._est_hour   = EstimationHour(ln)
             self._est_minute = EstimationMinutes(ln)
             self._act_minute = ActualMinutes(ln)
             self._starttime  = StartTime(ln)
             self._endtime    = EndTime(ln)
        except PropertyParseError as e:
            raise PropertyParseError('Failed to parsing the property line "%s".' % e)

        properties_by_str = ln[TaskLine.LENGTH:]
        self._attrs = TaskAttributeContainer()
        try:
            self._attrs.from_string(properties_by_str)
        except TaskAttributeError as e:
            raise PropertyParseError('Failed to parsing the attribute description "%s".' % e)

    def clone(self):
        import copy
        return copy.deepcopy(self)

    # get property
    # ------------

    def get_printable_value(self, no_config=False):
        """ @param no_config config 設定を無視する場合に立てる.

        本メソッドはデータファイルへの保存時にも利用するが,
        config に従うと「省略表示を行う config だった場合」に
        「省略表示のままデータファイルに保存されてしまう」.
        これを防ぐため, config 設定を無視するオプションを用意した.

        なお, no_config をどう解釈するかは都度考えること. """

        print_orders = [
            self._type, self._date, self._section, self._number,
            self._category, self._name,
            self._est_hour, self._est_minute,
            self._act_minute, self._starttime, self._endtime,
        ]

        ret = ''
        PROPERTY_SEP = ' '

        # プロパティ
        for inst in print_orders:
            ret += inst.get_printable_value() + PROPERTY_SEP

        # 属性
        # * showattr config で指定した属性を表示.
        #   一致しない場合はとりあえず表示しない.
        # * save 時は内容をフルで出力しないといけないため出す.
        if no_config:
            ret += self._attrs.to_string()
            return ret

        attrkey = self._systemconfig.showattr.get()
        attrvalue = ''
        try:
            attrvalue = self._attrs.get_value_as_string(attrkey)
        except TaskAttributeError:
            pass
        ret += attrvalue
        return ret

    def get_type(self):
        return self._type.get_printable_value()

    def get_date(self):
        return self._date.get_printable_value()

    def get_section(self):
        return self._section.get_printable_value()

    def get_number(self):
        return self._number.get_printable_value()

    def get_category(self):
        return self._category.get_printable_value()

    def get_taskname(self):
        return self._name.get_printable_value()

    def get_est_hour(self):
        return self._est_hour.get_printable_value()

    def get_est_minute(self):
        return self._est_minute.get_printable_value()

    def get_actual_minute(self):
        return self._act_minute.get_printable_value()

    def get_starttime(self):
        return self._starttime.get_printable_value()

    def get_endtime(self):
        return self._endtime.get_printable_value()

    # get attribute
    # -------------

    def get_note(self):
        return self._attrs.get_note()

    def get_repeat(self):
        return self._attrs.get_repeat()

    # edit
    # ----

    def edit(self, key, value):
        """ @return edit後のprintable value.
        @exception PropertyParseError edit失敗(valueのフォーマットがおかしい)
        @exception EditError edit失敗(key不正や連携などedit絡みのエラー) """
        return TaskEdit.edit(self, key, value)

    # change property
    # * 連携更新や省力記法展開も併せて行う.
    # * unittest のため, change 後の値を返却すること.
    # ---------------

    def change_date(self, value):
        # value の書式を解釈して, 省力記法なら展開する.
        v = util.DateWalker(self._systemconfig.basedate.get()).walk(value)

        ret = self._date.from_userinput(v).get_printable_value()
        self.update_type()
        return ret

    def change_section(self, value):
        return self._section.from_userinput(value).get_printable_value()

    def change_number(self, value):
        return self._number.from_userinput(value).get_printable_value()

    def change_category(self, value):
        return self._category.from_userinput(value).get_printable_value()

    def change_taskname(self, value):
        return self._name.from_userinput(value).get_printable_value()

    def change_estimate(self, value):
        v = value

        if len(value)==0:
            return self.change_estimate_minutes(v)
        elif value[-1]=='h':
            v = value[:-1]
            return self.change_estimate_hour(v)
        elif value[-1]=='m':
            v = value[:-1]
            return self.change_estimate_minutes(v)

        # デフォルトは好みで分扱い.
        return self.change_estimate_minutes(v)

    def change_estimate_minutes(self, value):
        ret = self._est_minute.from_userinput(value).get_printable_value()

        hourstr = PropertyReactor.est_hour(self._est_minute)
        self._est_hour.from_reactive(hourstr)

        return ret

    def change_estimate_hour(self, value):
        ret = self._est_hour.from_userinput(value).get_printable_value()

        minutestr = PropertyReactor.est_minute(self._est_hour)
        self._est_minute.from_reactive(minutestr)

        return ret

    def change_starttime(self, value):
        v = util.deploy_to_today_timestr_if_possible(value)
        ret = self._starttime.from_userinput(v).get_printable_value()

        # actual の再計算.
        # * 空値入力時は計算不可なので actual も空値にする.
        # * endtime が存在するなら, actual を再計算する.
        if PropertyInterface.is_empty_value(v):
            self.empty_actual_minute()
        elif not self._endtime.is_empty():
            self.update_actual_minute()

        return ret

    def change_endtime(self, value):
        v = util.deploy_to_today_timestr_if_possible(value)

        # starttime が入力されてない場合は受け付けない.
        # ただし空値が入力された時はこの限りではない.
        if PropertyInterface.is_empty_value(v):
            pass
        elif self._starttime.is_empty():
            raise EditError('End-time requires the Start-time')
        ret = self._endtime.from_userinput(v).get_printable_value()

        self.update_type()
        self.update_actual_minute()

        return ret

    # change attribute
    # ----------------

    def change_note(self, value):
        self._attrs.set_note(value)

    def remove_note(self):
        import taskattr
        self._attrs.remove_attribute(taskattr.Note.KEY)

    def change_repeat(self, value):
        self._attrs.set_repeat(value)

    def remove_repeat(self):
        import taskattr
        self._attrs.remove_attribute(taskattr.Repeat.KEY)

    # update
    # ------

    def empty_actual_minute(self):
        self._act_minute.from_userinput('')

    def update_actual_minute(self):
        actualminute = PropertyReactor.actual_minute(self._starttime, self._endtime)
        self._act_minute.from_reactive(actualminute)

    def update_type(self):
        newtype = PropertyReactor.type(
            date_property=self._date,
            basedate_str=self._systemconfig.basedate.get(),
            endtime_property=self._endtime)
        self._type.from_reactive(newtype)

    # matching by list conditions
    # ---------------------------

    def is_matched(self, conds):
        """ @param conds listコマンドにて与える条件文字列. `(COND1) (COND2) ...`
        @retval A boolean.

        AND MATCH のため全条件がマッチして始めてマッチとみなすことに注意. """
        cond_list = conds.split(' ')

        for cond in cond_list:
            match_result = self._is_matched(cond)
            if not match_result:
                return False

        return True

    def _is_matched(self, cond):
        if cond=='todo':
            todo_types = [Type.AT, Type.TT, Type.BT, Type.UT]
            if self._type.get_printable_value() in todo_types:
                return True
            return False
        elif cond=='done':
            todo_types = [Type.AD, Type.TD, Type.BD, Type.UD]
            if self._type.get_printable_value() in todo_types:
                return True
            return False
        elif cond=='doing':
            if not self._starttime.is_empty() and \
               self._endtime.is_empty() and self._act_minute.is_empty():
                return True
            return False
        elif cond=='nodate':
            if self._date.is_empty():
                return True
            return False
        elif cond[0]=='q':
            if len(cond)==1:
                return True
            query = cond[1:]
            # とりあえず部分一致.
            return self.get_printable_value().find(query)!=-1
        else:
            return self._do_date_match(cond)

    def _do_date_match(self, cond):
        if self._date.is_empty():
            return False
        # マッチ判定で使用しない曜日部分をカット.
        targetdatestr = self._date.get_printable_value()[:-2]

        datecond = util.DateCondition(
            targetdate_str=targetdatestr,
            basedate_str=self._systemconfig.basedate.get()
        )
        return datecond.is_matched(cond)

    # Operation about number
    # ----------------------

    def set_number(self, number_by_int):
        self._number.from_userinput(str(number_by_int))

    def equals_number(self, number_by_int):
        return self._number.equals(number_by_int)