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)
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)
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
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
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
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
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
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] )
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
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()
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
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"]))