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)
Example #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)
Example #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)
Example #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])
    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()
Example #6
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,
                                                                    ressurect = 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()
Example #7
0
    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)

        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 = datetime.datetime.now()
        # if in future - roll back to past
        if start_time > datetime.datetime.now():
            start_time = dt.datetime.combine(now.date(),  start_time.time())
            if start_time > now:
                start_time -= dt.timedelta(days = 1)

        if end_time and end_time > now:
            end_time = dt.datetime.combine(now.date(),  end_time.time())
            if end_time > now:
                end_time -= dt.timedelta(days = 1)


        # 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.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
Example #8
0
    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"]))