def on_clipboard_text(self, clipboard, text, data):
        # first check that we have a date selected
        fact = self.fact_tree.get_selected_fact()

        if not fact:
            return

        if isinstance(fact, dt.date):
            selected_date = fact
        else:
            selected_date = fact.date

        fact = stuff.Fact(text.decode("utf-8"))

        if not all((fact.activity, fact.start_time, fact.end_time)):
            return

        fact.start_time = fact.start_time.replace(year=selected_date.year,
                                                  month=selected_date.month,
                                                  day=selected_date.day)
        fact.end_time = fact.end_time.replace(year=selected_date.year,
                                              month=selected_date.month,
                                              day=selected_date.day)
        new_id = runtime.storage.add_fact(fact)

        # You can do that?! - copy/pasted an activity
        trophies.unlock("can_do_that")

        if new_id:
            self.fact_tree.select_fact(new_id)
예제 #2
0
    def on_today_row_activated(self, tree, path, column):
        fact = tree.get_selected_fact()
        fact = stuff.Fact(fact.activity,
                          tags=", ".join(fact.tags),
                          category=fact.category,
                          description=fact.description)

        if fact.activity:
            runtime.storage.add_fact(fact)
            self.__show_toggle(False)
예제 #3
0
    def on_switch_activity_clicked(self, widget):
        activity, temporary = self.new_name.get_value()

        fact = stuff.Fact(activity,
                          tags=self.new_tags.get_text().decode(
                              "utf8", "replace"))
        if not fact.activity:
            return

        runtime.storage.add_fact(fact, temporary)
        self.new_name.set_text("")
        self.new_tags.set_text("")
        self.__show_toggle(False)
예제 #4
0
def from_dbus_fact(fact):
    """unpack the struct into a proper dict"""
    return stuff.Fact(
        fact[4],
        start_time=dt.datetime.utcfromtimestamp(fact[1]),
        end_time=dt.datetime.utcfromtimestamp(fact[2]) if fact[2] else None,
        description=fact[3],
        activity_id=fact[5],
        category=fact[6],
        tags=fact[7],
        date=dt.datetime.utcfromtimestamp(fact[8]).date(),
        delta=dt.timedelta(days=fact[9] // (24 * 60 * 60),
                           seconds=fact[9] % (24 * 60 * 60)),
        id=fact[0])
예제 #5
0
    def AddFact(self, fact, start_time, end_time, temporary=False):
        start_time = dt.datetime.utcfromtimestamp(
            start_time) if start_time else None
        end_time = dt.datetime.utcfromtimestamp(end_time) if end_time else None

        fact = stuff.Fact(fact, start_time=start_time, end_time=end_time)
        start_time = fact.start_time or dt.datetime.now().replace(
            second=0, microsecond=0)

        self.start_transaction()
        result = self.__add_fact(fact.serialized_name(), start_time, end_time,
                                 temporary)
        self.end_transaction()

        if result:
            self.FactsChanged()
        return result or 0
예제 #6
0
    def on_save_button_clicked(self, button):
        activity_name, temporary = self.new_name.get_value()

        if self.get_widget("in_progress").get_active():
            end_time = None
        else:
            end_time = self._get_datetime("end")

        fact = stuff.Fact(activity_name,
                          description=self.figure_description(),
                          tags=self.new_tags.get_text().decode('utf8'),
                          start_time=self._get_datetime("start"),
                          end_time=end_time)
        if not fact.activity:
            return False

        if self.fact_id:
            runtime.storage.update_fact(self.fact_id, fact, temporary)
        else:
            runtime.storage.add_fact(fact, temporary)

        self.close_window()
예제 #7
0
    def on_workspace_changed(self, screen, previous_workspace):
        if not previous_workspace:
            # wnck has a slight hiccup on init and after that calls
            # workspace changed event with blank previous state that should be
            # ignored
            return

        if not self.workspace_tracking:
            return  # default to not doing anything

        current_workspace = screen.get_active_workspace()

        # rely on workspace numbers as names change
        prev = previous_workspace.get_number()
        new = current_workspace.get_number()

        # on switch, update our mapping between spaces and activities
        self.workspace_activities[prev] = self.last_activity

        activity = None
        if "name" in self.workspace_tracking:
            # first try to look up activity by desktop name
            mapping = conf.get("workspace_mapping")

            fact = None
            if new < len(mapping):
                fact = stuff.Fact(mapping[new])

                if fact.activity:
                    category_id = None
                    if fact.category:
                        category_id = runtime.storage.get_category_id(
                            fact.category)

                    activity = runtime.storage.get_activity_by_name(
                        fact.activity, category_id, resurrect=False)
                    if activity:
                        # we need dict below
                        activity = dict(name=activity.activity,
                                        category=activity.category,
                                        description=fact.description,
                                        tags=fact.tags)

        if not activity and "memory" in self.workspace_tracking:
            # now see if maybe we have any memory of the new workspace
            # (as in - user was here and tracking Y)
            # if the new workspace is in our dict, switch to the specified activity
            if new in self.workspace_activities and self.workspace_activities[
                    new]:
                activity = self.workspace_activities[new]

        if not activity:
            return

        # check if maybe there is no need to switch, as field match:
        if self.last_activity and \
           self.last_activity.activity.lower() == activity.activity.lower() and \
           (self.last_activity.category or "").lower() == (activity.category or "").lower() and \
           ", ".join(self.last_activity.tags).lower() == ", ".join(activity.tags).lower():
            return

        # ok, switch
        fact = stuff.Fact(activity.activity,
                          tags=", ".join(activity.tags),
                          category=activity.category,
                          description=activity.description)
        runtime.storage.add_fact(fact)

        if self.notification:
            self.notification.update(_("Changed activity"),
                                     _("Switched to '%s'") % activity.activity,
                                     "hamster-applet")
            self.notification.show()
예제 #8
0
파일: db.py 프로젝트: jcbrand/hamster
    def __add_fact(self,
                   serialized_fact,
                   start_time,
                   end_time=None,
                   temporary=False):
        fact = stuff.Fact(serialized_fact,
                          start_time=start_time,
                          end_time=end_time)

        start_time = start_time or fact.start_time
        end_time = end_time or fact.end_time

        if not fact.activity or start_time is None:  # sanity check
            return 0

        # get tags from database - this will create any missing tags too
        tags = [
            dict(zip(('id', 'name', 'autocomplete'), row))
            for row in self.GetTagIds(fact.tags)
        ]

        # now check if maybe there is also a category
        category_id = None
        if fact.category:
            category_id = self.__get_category_id(fact.category)
            if not category_id:
                category_id = self.__add_category(fact.category)

                trophies.unlock("no_hands")

        # try to find activity, resurrect if not temporary
        activity_id = self.__get_activity_by_name(fact.activity,
                                                  category_id,
                                                  resurrect=not temporary)
        if not activity_id:
            activity_id = self.__add_activity(fact.activity, category_id,
                                              temporary)
        else:
            activity_id = activity_id['id']

        # if we are working on +/- current day - check the last_activity
        if (dt.timedelta(days=-1) <= dt.datetime.now() - start_time <=
                dt.timedelta(days=1)):
            # pull in previous facts
            facts = self.__get_todays_facts()

            previous = None
            if facts and facts[-1]["end_time"] == None:
                previous = facts[-1]

            if previous and previous['start_time'] <= start_time:
                # check if maybe that is the same one, in that case no need to restart
                if previous["activity_id"] == activity_id \
                   and set(previous["tags"]) == set([tag["name"] for tag in tags]) \
                   and (previous["description"] or "") == (fact.description or ""):
                    return None

                # if no description is added
                # see if maybe previous was too short to qualify as an activity
                if not previous["description"] \
                   and 60 >= (start_time - previous['start_time']).seconds >= 0:
                    self.__remove_fact(previous['id'])

                    # now that we removed the previous one, see if maybe the one
                    # before that is actually same as the one we want to start
                    # (glueing)
                    if len(facts) > 1 and 60 >= (
                            start_time - facts[-2]['end_time']).seconds >= 0:
                        before = facts[-2]
                        if before["activity_id"] == activity_id \
                           and set(before["tags"]) == set([tag["name"] for tag in tags]):
                            # resume and return
                            update = """
                                       UPDATE facts
                                          SET end_time = null
                                        WHERE id = ?
                            """
                            self.execute(update, (before["id"], ))

                            return before["id"]
                else:
                    # otherwise stop
                    update = """
                               UPDATE facts
                                  SET end_time = ?
                                WHERE id = ?
                    """
                    self.execute(update, (start_time, previous["id"]))

        # done with the current activity, now we can solve overlaps
        if not end_time:
            end_time = self.__squeeze_in(start_time)
        else:
            self.__solve_overlaps(start_time, end_time)

        # finally add the new entry
        insert = """
                    INSERT INTO facts (activity_id, start_time, end_time, description)
                               VALUES (?, ?, ?, ?)
        """
        self.execute(insert,
                     (activity_id, start_time, end_time, fact.description))

        fact_id = self.__last_insert_rowid()

        #now link tags
        insert = ["insert into fact_tags(fact_id, tag_id) values(?, ?)"
                  ] * len(tags)
        params = [(fact_id, tag["id"]) for tag in tags]
        self.execute(insert, params)

        self.__remove_index([fact_id])
        return fact_id
예제 #9
0
파일: db.py 프로젝트: jcbrand/hamster
    def __solve_overlaps(self, start_time, end_time):
        """finds facts that happen in given interval and shifts them to
        make room for new fact
        """
        if end_time is None or start_time is None:
            return

        # possible combinations and the OR clauses that catch them
        # (the side of the number marks if it catches the end or start time)
        #             |----------------- NEW -----------------|
        #      |--- old --- 1|   |2 --- old --- 1|   |2 --- old ---|
        # |3 -----------------------  big old   ------------------------ 3|
        query = """
                   SELECT a.*, b.name, c.name as category
                     FROM facts a
                LEFT JOIN activities b on b.id = a.activity_id
                LEFT JOIN categories c on b.category_id = c.id
                    WHERE (end_time > ? and end_time < ?)
                       OR (start_time > ? and start_time < ?)
                       OR (start_time < ? and end_time > ?)
                 ORDER BY start_time
                """
        conflicts = self.fetchall(
            query,
            (start_time, end_time, start_time, end_time, start_time, end_time))

        for fact in conflicts:
            # won't eliminate as it is better to have overlapping entries than loosing data
            if start_time < fact["start_time"] and end_time > fact["end_time"]:
                continue

            # split - truncate until beginning of new entry and create new activity for end
            if fact["start_time"] < start_time < fact["end_time"] and \
               fact["start_time"] < end_time < fact["end_time"]:

                logging.info("splitting %s" % fact["name"])
                # truncate until beginning of the new entry
                self.execute(
                    """UPDATE facts
                                   SET end_time = ?
                                 WHERE id = ?""", (start_time, fact["id"]))
                fact_name = fact["name"]

                # create new fact for the end
                new_fact = stuff.Fact(
                    fact["name"],
                    category=fact["category"],
                    description=fact["description"],
                )
                new_fact_id = self.__add_fact(new_fact.serialized_name(),
                                              end_time, fact["end_time"])

                # copy tags
                tag_update = """INSERT INTO fact_tags(fact_id, tag_id)
                                     SELECT ?, tag_id
                                       FROM fact_tags
                                      WHERE fact_id = ?"""
                self.execute(tag_update,
                             (new_fact_id, fact["id"]))  #clone tags

                trophies.unlock("split")

            # overlap start
            elif start_time < fact["start_time"] < end_time:
                logging.info("Overlapping start of %s" % fact["name"])
                self.execute("UPDATE facts SET start_time=? WHERE id=?",
                             (end_time, fact["id"]))

            # overlap end
            elif start_time < fact["end_time"] < end_time:
                logging.info("Overlapping end of %s" % fact["name"])
                self.execute("UPDATE facts SET end_time=? WHERE id=?",
                             (start_time, fact["id"]))