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 = 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)
Beispiel #2
0
    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 = 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)
Beispiel #3
0
    def localized_fact(self):
        """makes sure fact is in our date"""
        fact = Fact(self.activity.get_text())
        if fact.start_time:
            fact.start_time = dt.datetime.combine(self.date, fact.start_time.time())

        if fact.end_time:
            fact.end_time = dt.datetime.combine(self.date, fact.end_time.time())

        return fact
Beispiel #4
0
    def localized_fact(self):
        """makes sure fact is in our date"""
        fact = Fact(self.activity.get_text())
        if fact.start_time:
            fact.start_time = dt.datetime.combine(self.date, fact.start_time.time())

        if fact.end_time:
            fact.end_time = dt.datetime.combine(self.date, fact.end_time.time())

        return fact
Beispiel #5
0
    def add_fact(self, fact, start_time, end_time, temporary = False):
        fact = 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.facts_changed()
        return result
Beispiel #6
0
    def add_fact(self, fact, start_time, end_time, temporary = False):
        start_time = self.__round_seconds(start_time)
        end_time = self.__round_seconds(end_time)
        fact = Fact(fact, start_time = start_time, end_time = end_time)

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

        if result:
            self.facts_changed()
        return result
Beispiel #7
0
    def add_fact(self, fact, start_time, end_time, temporary=False):
        start_time = self.__round_seconds(start_time)
        end_time = self.__round_seconds(end_time)
        fact = Fact(fact, start_time=start_time, end_time=end_time)

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

        if result:
            self.facts_changed()
        return result
Beispiel #8
0
    def add_fact(self, fact, start_time, end_time, temporary=False):
        fact = 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.facts_changed()
        return result
Beispiel #9
0
def from_dbus_fact(fact):
    """unpack the struct into a proper dict"""
    if fact[10] == -1 or fact[11] == -1:
        return 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]
                    )
    else:
        return RedmineFact(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)), redmine_issue_id = fact[10], redmine_time_activity_id = fact[11],
            id = fact[0]
            )
Beispiel #10
0
    def add_fact(self, fact, start_time, end_time, temporary = False, redmine_issue = -1, redmine_activity = -1):
        newfact = None
        if redmine_issue == -1:
            newfact = Fact(fact, start_time = start_time, end_time = end_time)
        else:
            newfact = RedmineFact(fact, start_time = start_time, end_time = end_time, redmine_issue_id = redmine_issue, redmine_time_activity_id = redmine_activity)
        fact = newfact
        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, redmine_issue, redmine_activity)
        self.end_transaction()

        if result:
            self.facts_changed()
        return result
Beispiel #11
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 = 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()
Beispiel #12
0
    def __add_fact(self, serialized_fact, start_time, end_time = None, temporary = False, redmine_issue = -1, redmine_activity = -1):
        fact = None
        if redmine_issue == -1:
            fact = Fact(serialized_fact,
                    start_time = start_time,
                    end_time = end_time)
        else:
            fact = RedmineFact(serialized_fact, redmine_issue_id = redmine_issue, redmine_time_activity_id = redmine_activity, 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 = [(tag['id'], tag['name'], tag['autocomplete']) for tag in self.get_tag_ids(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)

                if trophies:
                    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()
        
        # Redmine data
        
        if isinstance(fact, RedmineFact):
          insert = """INSERT INTO redmine_facts VALUES(?, ?, ?)"""
          self.execute(insert, (fact_id, fact.redmine_issue_id, fact.redmine_time_activity_id))
        else:
          insert = """INSERT INTO redmine_facts VALUES(?, -1, -1)"""
          self.execute(insert, (fact_id,))

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

        self.__remove_index([fact_id])
        return fact_id
Beispiel #13
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 = 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

                if trophies:
                    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"]))