Esempio n. 1
0
 def update_label(self):
     if self.last_activity and self.last_activity.end_time is None:
         delta = dt.datetime.now() - self.last_activity.start_time
         duration = delta.seconds /  60
         label = "%s %s" % (self.last_activity.activity,
                            stuff.format_duration(duration, False))
         self.button.set_text(self.last_activity.activity,
                              stuff.format_duration(duration, False))
     else:
         label = "%s" % _(u"No activity")
         self.button.set_text(label, None)
Esempio n. 2
0
    def update_label(self):
        '''Override for menu items sensitivity and to update the menu'''
        if self.project.last_activity:
            # Let's see if activity is an attribute and cache the result.
            # This is only required for backwards compatibility
            if self._activity_as_attribute == None:
                self._activity_as_attribute = hasattr(self.project.last_activity,
                                                      'activity')
            if self._activity_as_attribute:
                start_time = self.project.last_activity.start_time
                end_time = self.project.last_activity.end_time
                last_activity_name = self.project.last_activity.activity
            else:
                start_time = self.project.last_activity['start_time']
                end_time = self.project.last_activity['end_time']
                last_activity_name = self.project.last_activity['name']
        self.project.load_day()
        facts = self.project.todays_facts
        today_duration = 0
        if facts:
            for fact in facts:
                today_duration += 24 * 60 * fact.delta.days + fact.delta.seconds / 60
#        if self.duration:
#            today_duration += self.duration
        today_duration = "%s:%02d" % (today_duration/60, today_duration%60)
        if self.project.last_activity and end_time is None:
            self._set_activity_status(1)
            delta = dt.datetime.now() - start_time
            duration = delta.seconds /  60
            label = "%s %s" % (last_activity_name,
                               stuff.format_duration(duration, False))
            self.set_activity_text(last_activity_name,
                                 stuff.format_duration(duration, False))
            indicator_label = "%s %s / %sh" % (self._clamp_text(self.activity,
                                         length=self._label_length,
                                         with_ellipsis=False),
                                         self.duration,
                                         today_duration)
        else:
            self._set_activity_status(0)
            label = "%s" % _(u"New activity")
            self.set_activity_text(label, None)
            indicator_label = self._get_no_activity_label(today_duration)

        # Update the indicator label, if needed
        if self._show_label:
            self.indicator.set_label(indicator_label)
        else:
            self.indicator.set_label("")

        # Update the menu or the new activity text won't show up
        self.refresh_menu()
Esempio n. 3
0
    def set_last_activity(self):
        activity = self.last_activity
        #sets all the labels and everything as necessary
        self.get_widget("stop_tracking").set_sensitive(activity != None)


        if activity:
            self.get_widget("switch_activity").show()
            self.get_widget("start_tracking").hide()

            delta = dt.datetime.now() - activity.start_time
            duration = delta.seconds /  60

            if activity.category != _("Unsorted"):
                self.get_widget("last_activity_name").set_text("%s - %s" % (activity.activity, activity.category))
            else:
                self.get_widget("last_activity_name").set_text(activity.activity)

            self.get_widget("last_activity_duration").set_text(stuff.format_duration(duration) or _("Just started"))
            self.get_widget("last_activity_description").set_text(activity.description or "")
            self.get_widget("activity_info_box").show()

            self.tag_box.draw(activity.tags)
        else:
            self.get_widget("switch_activity").hide()
            self.get_widget("start_tracking").show()

            self.get_widget("last_activity_name").set_text(_("No activity"))

            self.get_widget("activity_info_box").hide()

            self.tag_box.draw([])
Esempio n. 4
0
    def _write_fact(self, fact):
        # no having end time is fine
        end_time_str, end_time_iso_str = "", ""
        if fact.end_time:
            end_time_str = fact.end_time.strftime('%H:%M')
            end_time_iso_str = fact.end_time.isoformat()

        category = ""
        if fact.category != _("Unsorted"): #do not print "unsorted" in list
            category = fact.category


        data = dict(
            date = fact.date.strftime(
                   # date column format for each row in HTML report
                   # Using python datetime formatting syntax. See:
                   # http://docs.python.org/library/time.html#time.strftime
                   C_("html report","%b %d, %Y")),
            date_iso = fact.date.isoformat(),
            activity = fact.activity,
            category = category,
            tags = fact.tags,
            start = fact.start_time.strftime('%H:%M'),
            start_iso = fact.start_time.isoformat(),
            end = end_time_str,
            end_iso = end_time_iso_str,
            duration = stuff.format_duration(fact.delta) or "",
            duration_minutes = "%d" % (stuff.duration_minutes(fact.delta)),
            duration_decimal = "%.2f" % (stuff.duration_minutes(fact.delta) / 60.0),
            description = fact.description or ""
        )
        self.fact_rows.append(Template(self.fact_row_template).safe_substitute(data))
Esempio n. 5
0
    def check_user(self):
        """check if we need to notify user perhaps"""
        if not self.notification or self.notify_interval <= 0 or self.notify_interval >= 121:
            return

        now = dt.datetime.now()
        message = None

        # update duration of current task
        if self.last_activity:
            delta = now - self.last_activity.start_time
            duration = delta.seconds /  60

            if duration and duration % self.notify_interval == 0:
                message = _(u"Working on <b>%s</b>") % self.last_activity.name

            self.get_widget("last_activity_duration").set_text(stuff.format_duration(duration) or _("Just started"))

        if not self.last_activity and self.notify_on_idle:
            #if we have no last activity, let's just calculate duration from 00:00
            if (now.minute + now.hour *60) % self.notify_interval == 0:
                message = _(u"No activity")

        if message:
            self.notification.update(_("Time Tracker"), message, "hamster-applet")
            self.notification.show()
Esempio n. 6
0
    def __init__(self, width, fact, color, **kwargs):
        graphics.Sprite.__init__(self, **kwargs)
        self.width = width
        self.height = 27
        self.natural_height = 27
        self.fact = fact
        self.color = color

        self.interactive = True
        self.mouse_cursor = gdk.CursorType.XTERM

        self.fact_labels = graphics.Sprite()

        self.start_label = graphics.Label("", color="#333", size=11, x=10, y=5, interactive=True,
                                          mouse_cursor=gdk.CursorType.XTERM)
        self.start_label.text = "%s - " % fact.start_time.strftime("%H:%M")
        self.fact_labels.add_child(self.start_label)

        self.end_label = graphics.Label("", color="#333", size=11, x=65, y=5, interactive=True,
                                        mouse_cursor=gdk.CursorType.XTERM)
        if fact.end_time:
            self.end_label.text = fact.end_time.strftime("%H:%M")
        self.fact_labels.add_child(self.end_label)

        self.activity_label = graphics.Label(fact.activity, color="#333", size=11, x=120, y=5, interactive=True,
                                             mouse_cursor=gdk.CursorType.XTERM)
        self.fact_labels.add_child(self.activity_label)

        self.category_label = graphics.Label("", color="#333", size=9, y=7, interactive=True,
                                             mouse_cursor=gdk.CursorType.XTERM)
        self.category_label.text = stuff.escape_pango(" - %s" % fact.category)
        self.category_label.x = self.activity_label.x + self.activity_label.width
        self.fact_labels.add_child(self.category_label)


        self.duration_label = graphics.Label(stuff.format_duration(fact.delta), size=11, color="#333", interactive=True,
                                             mouse_cursor=gdk.CursorType.XTERM)
        self.duration_label.x = self.width - self.duration_label.width - 5
        self.duration_label.y = 5
        self.fact_labels.add_child(self.duration_label)

        self.add_child(self.fact_labels)

        self.edit_links = graphics.Sprite(x=10, y = 110, opacity=0)

        self.delete_link = graphics.Label("Delete", size=11, color="#555", interactive=True)
        self.save_link = graphics.Label("Save", size=11, x=390, color="#555", interactive=True)
        self.cancel_link = graphics.Label("Cancel", size=11, x=440, color="#555", interactive=True)
        self.edit_links.add_child(self.delete_link, self.save_link, self.cancel_link)

        self.add_child(self.edit_links)

        for sprite in self.fact_labels.sprites:
            sprite.connect("on-click", self.on_sprite_click)

        self.connect("on-render", self.on_render)
        self.connect("on-click", self.on_click)
Esempio n. 7
0
    def update_text(self):
        today = self.storage.get_todays_facts()

        if today and today[-1].end_time is None:
            fact = today[-1]

            self.iface.SetText("%s - %s" % (fact.activity, fact.category))
            self.iface.SetBadgeText(stuff.format_duration(fact.delta, human=False))
        else:
            self.iface.SetText(_("No activity"))
            self.iface.ResetBadgeText()
Esempio n. 8
0
    def show(self, g, colors, fact, current=False):
        g.save_context()

        color, bg = colors["normal"], colors["normal_bg"]
        if current:
            color, bg = colors["selected"], colors["selected_bg"]
            g.fill_area(0, 0, self.width, self.height(fact), bg)

        g.translate(5, 2)

        time_label = fact.start_time.strftime("%H:%M -")
        if fact.end_time:
            time_label += fact.end_time.strftime(" %H:%M")

        g.set_color(color)
        self.time_label.show(g, time_label)

        self.activity_label.show(g, stuff.escape_pango(fact.activity))
        if fact.category:
            g.save_context()
            g.set_color(color if current else "#999")
            x = self.activity_label.x + self.activity_label.layout.get_pixel_size()[0]
            self.category_label.show(g, "  - %s" % stuff.escape_pango(fact.category), x=x, y=2)
            g.restore_context()

        if fact.description or fact.tags:
            g.save_context()
            g.translate(self.activity_label.x, self.activity_label.height + 3)

            if fact.tags:
                self._show_tags(g, fact.tags, color, bg)
                g.translate(0, self.tag_label.height + 5)

            if fact.description:
                self.description_label.show(g, "<small>%s</small>" % stuff.escape_pango(fact.description))
            g.restore_context()

        self.duration_label.show(g, stuff.format_duration(fact.delta), x=self.width - 105)

        g.restore_context()
Esempio n. 9
0
    def set_facts(self, facts):
        totals = defaultdict(lambda: defaultdict(dt.timedelta))
        for fact in facts:
            for key in ('category', 'activity'):
                totals[key][getattr(fact, key)] += fact.delta

            for tag in fact.tags:
                totals["tag"][tag] += fact.delta


        for key, group in totals.items():
            totals[key] = sorted(group.items(), key=lambda x: x[1], reverse=True)
        self.totals = totals

        self.activities_chart.set_values(totals['activity'])
        self.categories_chart.set_values(totals['category'])
        self.tag_chart.set_values(totals['tag'])

        self.stacked_bar.set_items([(cat, delta.total_seconds() / 60.0) for cat, delta in totals['category']])
        self.category_totals.markup = ", ".join("<b>%s:</b> %s" % (
            stuff.escape_pango(cat), stuff.format_duration(hours)) \
            for cat, hours in totals['category'])
Esempio n. 10
0
    def update_suggestions(self, text=""):
        """
            * from previous activity | set time | minutes ago | start now
            * to ongoing | set time

            * activity
            * [@category]
            * #tags, #tags, #tags

            * we will leave description for later

            all our magic is space separated, strictly, start-end can be just dash

            phases:

            [start_time] | [-end_time] | activity | [@category] | [#tag]
        """
        now = dt.datetime.now()

        text = text.lstrip()

        time_re = re.compile("^([0-1]?[0-9]|[2][0-3]):([0-5][0-9])$")
        time_range_re = re.compile("^([0-1]?[0-9]|[2][0-3]):([0-5][0-9])-([0-1]?[0-9]|[2][0-3]):([0-5][0-9])$")
        delta_re = re.compile("^-[0-9]{1,3}$")

        # when the time is filled, we need to make sure that the chunks parse correctly



        delta_fragment_re = re.compile("^-[0-9]{0,3}$")


        templates = {
            "start_time": "",
            "start_delta": ("start activity -n minutes ago", "-"),
        }

        # need to set the start_time template before
        prev_fact = self.todays_facts[-1] if self.todays_facts else None
        if prev_fact and prev_fact.end_time:
            templates["start_time"] = ("from previous activity %s ago" % stuff.format_duration(now - prev_fact.end_time),
                                       prev_fact.end_time.strftime("%H:%M "))

        variants = []

        fact = Fact(text)

        # figure out what we are looking for
        # time -> activity[@category] -> tags -> description
        # presence of each next attribute means that we are not looking for the previous one
        # we still might be looking for the current one though
        looking_for = "start_time"
        fields = ["start_time", "end_time", "activity", "category", "tags", "description", "done"]
        for field in reversed(fields):
            if getattr(fact, field, None):
                looking_for = field
                if text[-1] == " ":
                    looking_for = fields[fields.index(field)+1]
                break


        fragments = [f for f in re.split("[\s|#]", text)]
        current_fragment = fragments[-1] if fragments else ""

        if not text.strip():
            variants = [templates[name] for name in ("start_time",
                                                     "start_delta") if templates[name]]
        elif looking_for == "start_time" and text == "-":
            if len(current_fragment) > 1: # avoid blank "-"
                templates["start_delta"] = ("%s minutes ago" % (-int(current_fragment)), current_fragment)
            variants.append(templates["start_delta"])


        res = []
        for (description, variant) in variants:
            res.append(DataRow(variant, description=description))

        # regular activity
        if (looking_for in ("start_time", "end_time") and not looks_like_time(text.split(" ")[-1])) or \
            looking_for in ("activity", "category"):

            search = extract_search(text)

            matches = []
            for match, score in self.suggestions:
                if search in match:
                    if match.startswith(search):
                        score += 10**8 # boost beginnings
                    matches.append((match, score))

            matches = sorted(matches, key=lambda x: x[1], reverse=True)[:7] # need to limit these guys, sorry

            for match, score in matches:
                label = (fact.start_time or now).strftime("%H:%M")
                if fact.end_time:
                    label += fact.end_time.strftime("-%H:%M")

                markup_label = label + " " + (stuff.escape_pango(match).replace(search, "<b>%s</b>" % search) if search else match)
                label += " " + match

                res.append(DataRow(markup_label, match, label))

        if not res:
            # in case of nothing to show, add preview so that the user doesn't
            # think they are lost
            label = (fact.start_time or now).strftime("%H:%M")
            if fact.end_time:
                label += fact.end_time.strftime("-%H:%M")

            if fact.activity:
                label += " " + fact.activity
            if fact.category:
                label += "@" + fact.category

            if fact.tags:
                label += " #" + " #".join(fact.tags)

            res.append(DataRow(stuff.escape_pango(label), description="Start tracking"))

        self.complete_tree.set_rows(res)
Esempio n. 11
0
    def show_popup(self):
        if not self._parent_click_watcher:
            self._parent_click_watcher = self.get_toplevel().connect("button-press-event", self._on_focus_out_event)

        # will be going either 24 hours or from start time to start time + 12 hours
        start_time = dt.datetime.combine(dt.date.today(), self.start_time) # we will be adding things
        i_time = start_time # we will be adding things

        if self.start_time:
            end_time = i_time + dt.timedelta(hours = 12)
            i_time += dt.timedelta(minutes = 15)
        else:
            end_time = i_time + dt.timedelta(days = 1)


        focus_time = dt.datetime.combine(dt.date.today(), self.figure_time(self.get_text()))
        hours = gtk.ListStore(gobject.TYPE_STRING)


        i, focus_row = 0, None
        while i_time < end_time:
            row_text = self._format_time(i_time)
            if self.start_time:
                delta = (i_time - start_time).seconds / 60
                delta_text = format_duration(delta)

                row_text += " (%s)" % delta_text

            hours.append([row_text])


            if focus_time and i_time <= focus_time <= i_time + \
                                                     dt.timedelta(minutes = 30):
                focus_row = i

            if self.start_time:
                i_time += dt.timedelta(minutes = 15)
            else:
                i_time += dt.timedelta(minutes = 30)

            i += 1

        self.time_tree.set_model(hours)

        #focus on row
        if focus_row != None:
            selection = self.time_tree.get_selection()
            selection.select_path(focus_row)
            self.time_tree.scroll_to_cell(focus_row, use_align = True, row_align = 0.4)


        #move popup under the widget
        alloc = self.get_allocation()
        w = alloc.width
        if self.start_time:
            w = w * 2
        self.time_tree.set_size_request(w, alloc.height * 5)

        window = self.get_parent_window()
        dmmy, x, y= window.get_origin()

        self.popup.move(x + alloc.x,y + alloc.y + alloc.height)
        self.popup.resize(*self.time_tree.get_size_request())
        self.popup.show_all()
Esempio n. 12
0
    def set_last_activity(self):
        activity = self.last_activity
        #sets all the labels and everything as necessary
        self.get_widget("stop_tracking").set_sensitive(activity != None)
        arbitrary_issue_id = self.get_widget("arbitrary_issue_id_entry").get_text()
        active_activity = self.get_widget("time_activity_combo").get_active()


        if activity:
            self.get_widget("switch_activity").show()
            self.get_widget("start_tracking").hide()
            
            # If the Redmine integration is enabled, show the Redmine frame and set insensitivity of combos
            if conf.get("redmine_integration_enabled"):
              self.get_widget("redmine_frame").show()
              self.get_widget("issue_combo").set_sensitive(False)
              self.get_widget("time_activity_combo").set_sensitive(False)
              self.get_widget("arbitrary_issue_id_entry").set_sensitive(False)
              if arbitrary_issue_id != None:
                self.get_widget("arbitrary_issue_id_entry").set_text(arbitrary_issue_id)
                self.get_widget("time_activity_combo").set_active(active_activity)

            delta = dt.datetime.now() - activity.start_time
            duration = delta.seconds //  60

            if activity.category != _("Unsorted"):
                if isinstance(activity, RedmineFact):
                    self.get_widget("last_activity_name").set_text("%s %s - %s" %(activity.activity, activity.redmine_tag(), activity.category))
                else:
                    self.get_widget("last_activity_name").set_text("%s - %s" %(activity.activity, activity.category))
            else:
                if isinstance(activity, RedmineFact):
                    self.get_widget("last_activity_name").set_text("%s %s"%(activity.activity, activity.redmine_tag()))
                else:
                    self.get_widget("last_activity_name").set_text(activity.activity)

            self.get_widget("last_activity_duration").set_text(stuff.format_duration(duration) or _("Just started"))
            self.get_widget("last_activity_description").set_text(activity.description or "")
            self.get_widget("activity_info_box").show()

            self.tag_box.draw(activity.tags)
        else:
            self.get_widget("switch_activity").hide()
            self.get_widget("start_tracking").show()

            self.get_widget("last_activity_name").set_text(_("No activity"))

            self.get_widget("activity_info_box").hide()

            self.tag_box.draw([])
            
            # If the Redmine integration is enabled, show the Redmine frame and set up the combos (if there is no selection), making sure they are sensitive
            if conf.get("redmine_integration_enabled"):
              self.get_widget("redmine_frame").show()
              self.get_widget("issue_combo").set_sensitive(True)
              self.get_widget("time_activity_combo").set_sensitive(True)
              if self.get_widget("issue_combo").get_active() == -1 or self.get_widget("issue_combo").get_active() == 0:
                self.fill_issues_combo()
                self.get_widget("arbitrary_issue_id_entry").set_sensitive(True)
              if self.get_widget("time_activity_combo").get_active() == -1 or self.get_widget("time_activity_combo").get_active() == 0:
                self.fill_time_activities_combo()
              if arbitrary_issue_id != None:
                self.get_widget("arbitrary_issue_id_entry").set_text(arbitrary_issue_id)
                self.get_widget("time_activity_combo").set_active(active_activity)