Example #1
0
    def __init__(self, parent = None):
        self.parent = parent# determine if app should shut down on close
        self._gui = load_ui_file("overview.ui")
        self.report_chooser = None
        self.window = self.get_widget("tabs_window")
        self.window.connect("delete_event", self.on_delete_window)

        self.range_pick = widgets.RangePick()
        self.get_widget("range_pick_box").add(self.range_pick)
        self.range_pick.connect("range-selected", self.on_range_selected)

        self.overview = OverviewBox()
        self.get_widget("overview_tab").add(self.overview)
        self.fact_tree = self.overview.fact_tree # TODO - this is upside down, should maybe get the overview tab over here
        self.fact_tree.connect("cursor-changed", self.on_fact_selection_changed)

        self.fact_tree.connect("button-press-event", self.on_fact_tree_button_press)

        self.reports = TotalsBox()
        self.get_widget("reports_tab").add(self.reports)

        self.timechart = widgets.TimeChart()
        self.timechart.connect("zoom-out-clicked", self.on_timechart_zoom_out_clicked)
        self.timechart.connect("range-picked", self.on_timechart_new_range)
        self.get_widget("by_day_box").add(self.timechart)

        self._gui.connect_signals(self)
        runtime.storage.connect('activities-changed',self.after_activity_update)
        runtime.storage.connect('facts-changed',self.after_activity_update)

        conf.connect('conf-changed', self.on_conf_change)
        self.show()
Example #2
0
    def __init__(self, parent = None):
        self.parent = parent# determine if app should shut down on close
        self._gui = load_ui_file("overview.ui")
        self.report_chooser = None

        self.facts = None

        self.window = self.get_widget("tabs_window")

        self.day_start = conf.get("day_start_minutes")
        self.day_start = dt.time(self.day_start / 60, self.day_start % 60)

        self.view_date = (dt.datetime.today() - dt.timedelta(hours = self.day_start.hour,
                                                        minutes = self.day_start.minute)).date()

        self.range_pick = widgets.RangePick()
        self.get_widget("range_pick_box").add(self.range_pick)
        self.range_pick.connect("range-selected", self.on_range_selected)

        #set to monday
        self.start_date = self.view_date - dt.timedelta(self.view_date.weekday() + 1)

        # look if we need to start on sunday or monday
        self.start_date = self.start_date + dt.timedelta(stuff.locale_first_weekday())

        # see if we have not gotten carried away too much in all these calculations
        if (self.view_date - self.start_date) == dt.timedelta(7):
            self.start_date += dt.timedelta(7)

        self.end_date = self.start_date + dt.timedelta(6)

        self.overview = OverviewBox()
        self.get_widget("overview_tab").add(self.overview)
        self.fact_tree = self.overview.fact_tree # TODO - this is upside down, should maybe get the overview tab over here
        self.fact_tree.connect("cursor-changed", self.on_fact_selection_changed)

        self.fact_tree.connect("button-press-event", self.on_fact_tree_button_press)

        self.reports = TotalsBox()
        self.get_widget("reports_tab").add(self.reports)

        self.current_range = "week"

        self.timechart = widgets.TimeChart()
        self.timechart.connect("zoom-out-clicked", self.on_timechart_zoom_out_clicked)
        self.timechart.connect("range-picked", self.on_timechart_new_range)
        self.timechart.day_start = self.day_start

        self.get_widget("by_day_box").add(self.timechart)

        self._gui.connect_signals(self)
        runtime.storage.connect('activities-changed',self.after_activity_update)
        runtime.storage.connect('facts-changed',self.after_activity_update)

        conf.connect('conf-changed', self.on_conf_change)

        if conf.get("overview_window_maximized"):
            self.window.maximize()
        else:
            window_box = conf.get("overview_window_box")
            if window_box:
                x, y, w, h = (int(i) for i in window_box)
                self.window.move(x, y)
                self.window.resize(w, h)
            else:
                self.window.set_position(gtk.WIN_POS_CENTER)

        self.window.show_all()

        self.search()
Example #3
0
class Overview(object):
    def __init__(self, parent = None):
        self.parent = parent# determine if app should shut down on close
        self._gui = load_ui_file("overview.ui")
        self.report_chooser = None

        self.facts = None

        self.window = self.get_widget("tabs_window")

        self.day_start = conf.get("day_start_minutes")
        self.day_start = dt.time(self.day_start / 60, self.day_start % 60)

        self.view_date = (dt.datetime.today() - dt.timedelta(hours = self.day_start.hour,
                                                        minutes = self.day_start.minute)).date()

        self.range_pick = widgets.RangePick()
        self.get_widget("range_pick_box").add(self.range_pick)
        self.range_pick.connect("range-selected", self.on_range_selected)

        #set to monday
        self.start_date = self.view_date - dt.timedelta(self.view_date.weekday() + 1)

        # look if we need to start on sunday or monday
        self.start_date = self.start_date + dt.timedelta(stuff.locale_first_weekday())

        # see if we have not gotten carried away too much in all these calculations
        if (self.view_date - self.start_date) == dt.timedelta(7):
            self.start_date += dt.timedelta(7)

        self.end_date = self.start_date + dt.timedelta(6)

        self.overview = OverviewBox()
        self.get_widget("overview_tab").add(self.overview)
        self.fact_tree = self.overview.fact_tree # TODO - this is upside down, should maybe get the overview tab over here
        self.fact_tree.connect("cursor-changed", self.on_fact_selection_changed)

        self.fact_tree.connect("button-press-event", self.on_fact_tree_button_press)

        self.reports = TotalsBox()
        self.get_widget("reports_tab").add(self.reports)

        self.current_range = "week"

        self.timechart = widgets.TimeChart()
        self.timechart.connect("zoom-out-clicked", self.on_timechart_zoom_out_clicked)
        self.timechart.connect("range-picked", self.on_timechart_new_range)
        self.timechart.day_start = self.day_start

        self.get_widget("by_day_box").add(self.timechart)

        self._gui.connect_signals(self)
        runtime.storage.connect('activities-changed',self.after_activity_update)
        runtime.storage.connect('facts-changed',self.after_activity_update)

        conf.connect('conf-changed', self.on_conf_change)

        if conf.get("overview_window_maximized"):
            self.window.maximize()
        else:
            window_box = conf.get("overview_window_box")
            if window_box:
                x, y, w, h = (int(i) for i in window_box)
                self.window.move(x, y)
                self.window.resize(w, h)
            else:
                self.window.set_position(gtk.WIN_POS_CENTER)

        self.window.show_all()

        self.search()

    def on_fact_tree_button_press(self, treeview, event):
        if event.button == 3:
            x = int(event.x)
            y = int(event.y)
            time = event.time
            pthinfo = treeview.get_path_at_pos(x, y)
            if pthinfo is not None:
                path, col, cellx, celly = pthinfo
                treeview.grab_focus()
                treeview.set_cursor( path, col, 0)
                self.get_widget("fact_tree_popup").popup( None, None, None, event.button, time)
            return True

    def on_timechart_new_range(self, chart, start_date, end_date):
        self.start_date = start_date
        self.end_date = end_date
        self.apply_range_select()

    def on_timechart_zoom_out_clicked(self, chart):
        if (self.end_date - self.start_date < dt.timedelta(days=6)):
            self.on_week_activate(None)
        elif (self.end_date - self.start_date < dt.timedelta(days=27)):
            self.on_month_activate(None)
        else:
            self.current_range = "manual"
            self.start_date = self.view_date.replace(day=1, month=1)
            self.end_date = self.start_date.replace(year = self.start_date.year + 1) - dt.timedelta(days=1)
            self.apply_range_select()




    def search(self):
        if self.start_date > self.end_date: # make sure the end is always after beginning
            self.start_date, self.end_date = self.end_date, self.start_date

        search_terms = self.get_widget("search").get_text().decode("utf8", "replace")
        self.facts = runtime.storage.get_facts(self.start_date, self.end_date, search_terms)

        self.get_widget("export").set_sensitive(len(self.facts) > 0)

        self.set_title()

        self.range_pick.set_range(self.start_date, self.end_date, self.view_date)

        durations = [(fact.start_time, fact.delta) for fact in self.facts]
        self.timechart.draw(durations, self.start_date, self.end_date)

        if self.get_widget("window_tabs").get_current_page() == 0:
            self.overview.search(self.start_date, self.end_date, self.facts)
            self.reports.search(self.start_date, self.end_date, self.facts)
        else:
            self.reports.search(self.start_date, self.end_date, self.facts)
            self.overview.search(self.start_date, self.end_date, self.facts)

    def set_title(self):
        self.title = stuff.format_range(self.start_date, self.end_date)
        self.window.set_title(self.title.decode("utf-8"))


    def on_conf_change(self, event, key, value):
        if key == "day_start_minutes":
            self.day_start = dt.time(value / 60, value % 60)
            self.timechart.day_start = self.day_start
            self.search()

    def on_fact_selection_changed(self, tree):
        """ enables and disables action buttons depending on selected item """
        fact = tree.get_selected_fact()
        real_fact = fact is not None and isinstance(fact, stuff.Fact)

        self.get_widget('remove').set_sensitive(real_fact)
        self.get_widget('edit').set_sensitive(real_fact)

        return True

    def after_activity_update(self, widget):
        self.search()

    def on_search_icon_press(self, widget, position, data):
        if position == gtk.ENTRY_ICON_SECONDARY:
            widget.set_text('')

        self.search()

    def on_search_activate(self, widget):
        self.search()

    def on_search_changed(self, widget):
        has_text = len(widget.get_text()) > 0
        widget.set_icon_sensitive(gtk.ENTRY_ICON_SECONDARY, has_text)

    def on_export_activate(self, widget):
        def on_report_chosen(widget, format, path):
            self.report_chooser = None
            reports.simple(self.facts, self.start_date, self.end_date, format, path)

            if format == ("html"):
                webbrowser.open_new("file://%s" % path)
            else:
                try:
                    gtk.show_uri(gtk.gdk.Screen(), "file://%s" % os.path.split(path)[0], 0L)
                except:
                    pass # bug 626656 - no use in capturing this one i think

        def on_report_chooser_closed(widget):
            self.report_chooser = None

        if not self.report_chooser:
            self.report_chooser = widgets.ReportChooserDialog()
            self.report_chooser.connect("report-chosen", on_report_chosen)
            self.report_chooser.connect("report-chooser-closed",
                                        on_report_chooser_closed)
            self.report_chooser.show(self.start_date, self.end_date)
        else:
            self.report_chooser.present()


    def apply_range_select(self):
        if self.view_date < self.start_date:
            self.view_date = self.start_date

        if self.view_date > self.end_date:
            self.view_date = self.end_date

        self.search()


    def on_range_selected(self, widget, range, start, end):
        self.current_range = range
        self.start_date = start
        self.end_date = end
        self.apply_range_select()

    def on_day_activate(self, button):
        self.current_range = "day"
        self.start_date = self.view_date
        self.end_date = self.start_date + dt.timedelta(0)
        self.apply_range_select()

    def on_week_activate(self, button):
        self.current_range = "week"
        self.start_date, self.end_date = stuff.week(self.view_date)
        self.apply_range_select()

    def on_month_activate(self, button):
        self.current_range = "month"
        self.start_date, self.end_date = stuff.month(self.view_date)
        self.apply_range_select()

    def on_manual_range_apply_clicked(self, button):
        self.current_range = "manual"
        cal_date = self.get_widget("start_calendar").get_date()
        self.start_date = dt.date(cal_date[0], cal_date[1] + 1, cal_date[2])

        cal_date = self.get_widget("end_calendar").get_date()
        self.end_date = dt.date(cal_date[0], cal_date[1] + 1, cal_date[2])

        self.apply_range_select()


    def on_tabs_window_configure_event(self, window, event):
        # this is required so that the rows would grow on resize
        self.fact_tree.fix_row_heights()

    def on_tabs_window_state_changed(self, window, event):
        # not enough space - maximized the overview window
        maximized = window.get_window().get_state() & gtk.gdk.WINDOW_STATE_MAXIMIZED
        if maximized:
            trophies.unlock("not_enough_space")




    def on_prev_activate(self, action):
        if self.current_range == "day":
            self.start_date -= dt.timedelta(1)
            self.end_date -= dt.timedelta(1)
        elif self.current_range == "week":
            self.start_date -= dt.timedelta(7)
            self.end_date -= dt.timedelta(7)
        elif self.current_range == "month":
            self.end_date = self.start_date - dt.timedelta(1)
            first_weekday, days_in_month = calendar.monthrange(self.end_date.year, self.end_date.month)
            self.start_date = self.end_date - dt.timedelta(days_in_month - 1)
        else:
            # manual range - just jump to the next window
            days =  (self.end_date - self.start_date) + dt.timedelta(days = 1)
            self.start_date = self.start_date - days
            self.end_date = self.end_date - days

        self.view_date = self.start_date
        self.search()

    def on_next_activate(self, action):
        if self.current_range == "day":
            self.start_date += dt.timedelta(1)
            self.end_date += dt.timedelta(1)
        elif self.current_range == "week":
            self.start_date += dt.timedelta(7)
            self.end_date += dt.timedelta(7)
        elif self.current_range == "month":
            self.start_date = self.end_date + dt.timedelta(1)
            first_weekday, days_in_month = calendar.monthrange(self.start_date.year, self.start_date.month)
            self.end_date = self.start_date + dt.timedelta(days_in_month - 1)
        else:
            # manual range - just jump to the next window
            days =  (self.end_date - self.start_date) + dt.timedelta(days = 1)
            self.start_date = self.start_date + days
            self.end_date = self.end_date + days

        self.view_date = self.start_date
        self.search()


    def on_home_activate(self, action):
        self.view_date = (dt.datetime.today() - dt.timedelta(hours = self.day_start.hour,
                                                        minutes = self.day_start.minute)).date()
        if self.current_range == "day":
            self.start_date = self.view_date
            self.end_date = self.start_date + dt.timedelta(0)

        elif self.current_range == "week":
            self.start_date = self.view_date - dt.timedelta(self.view_date.weekday() + 1)
            self.start_date = self.start_date + dt.timedelta(stuff.locale_first_weekday())
            self.end_date = self.start_date + dt.timedelta(6)
        elif self.current_range == "month":
            self.start_date = self.view_date - dt.timedelta(self.view_date.day - 1) #set to beginning of month
            first_weekday, days_in_month = calendar.monthrange(self.view_date.year, self.view_date.month)
            self.end_date = self.start_date + dt.timedelta(days_in_month - 1)
        else:
            days =  (self.end_date - self.start_date)
            self.start_date = self.view_date
            self.end_date = self.view_date + days

        self.search()

    def get_widget(self, name):
        """ skip one variable (huh) """
        return self._gui.get_object(name)

    def on_window_tabs_switch_page(self, notebook, page, pagenum):
        if pagenum == 0:
            self.on_fact_selection_changed(self.fact_tree)
        elif pagenum == 1:
            self.get_widget('remove').set_sensitive(False)
            self.get_widget('edit').set_sensitive(False)
            self.reports.do_charts()


    def on_add_activate(self, action):
        fact = self.fact_tree.get_selected_fact()
        if not fact:
            selected_date = self.start_date
        elif isinstance(fact, dt.date):
            selected_date = fact
        else:
            selected_date = fact["date"]

        dialogs.edit.show(self, fact_date = selected_date)

    def on_remove_activate(self, button):
        self.overview.delete_selected()


    def on_edit_activate(self, button):
        fact = self.fact_tree.get_selected_fact()
        if not fact or isinstance(fact, dt.date):
            return
        dialogs.edit.show(self, fact_id = fact.id)

    def on_tabs_window_deleted(self, widget, event):
        self.close_window()

    def on_window_key_pressed(self, tree, event_key):
      if (event_key.keyval == gtk.keysyms.Escape
          or (event_key.keyval == gtk.keysyms.w
              and event_key.state & gtk.gdk.CONTROL_MASK)):
        self.close_window()

    def on_close_activate(self, action):
        self.close_window()

    def close_window(self):
        # properly saving window state and position
        maximized = self.window.get_window().get_state() & gtk.gdk.WINDOW_STATE_MAXIMIZED
        conf.set("overview_window_maximized", maximized)

        # make sure to remember dimensions only when in normal state
        if maximized == False and not self.window.get_window().get_state() & gtk.gdk.WINDOW_STATE_ICONIFIED:
            x, y = self.window.get_position()
            w, h = self.window.get_size()
            conf.set("overview_window_box", [x, y, w, h])


        if not self.parent:
            gtk.main_quit()
        else:
            self.window.destroy()
            return False

    def show(self):
        self.window.show()
Example #4
0
class Overview(gtk.Object):
    __gsignals__ = {"on-close": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ())}

    def __init__(self, parent=None):
        gtk.Object.__init__(self)

        self.parent = parent  # determine if app should shut down on close
        self._gui = load_ui_file("overview.ui")
        self.report_chooser = None
        self.window = self.get_widget("tabs_window")
        self.window.connect("delete_event", self.on_delete_window)

        self.range_pick = widgets.RangePick()
        self.get_widget("range_pick_box").add(self.range_pick)
        self.range_pick.connect("range-selected", self.on_range_selected)

        self.overview = OverviewBox()
        self.get_widget("overview_tab").add(self.overview)
        self.fact_tree = (
            self.overview.fact_tree
        )  # TODO - this is upside down, should maybe get the overview tab over here
        self.fact_tree.connect("cursor-changed", self.on_fact_selection_changed)

        self.fact_tree.connect("button-press-event", self.on_fact_tree_button_press)

        self.reports = TotalsBox()
        self.get_widget("reports_tab").add(self.reports)

        self.timechart = widgets.TimeChart()
        self.timechart.connect("zoom-out-clicked", self.on_timechart_zoom_out_clicked)
        self.timechart.connect("range-picked", self.on_timechart_new_range)
        self.get_widget("by_day_box").add(self.timechart)
        self.start_button = self.get_widget("start_button")

        self._gui.connect_signals(self)

        self.external_listeners = [
            (runtime.storage, runtime.storage.connect("activities-changed", self.after_activity_update)),
            (runtime.storage, runtime.storage.connect("facts-changed", self.after_activity_update)),
            (conf, conf.connect("conf-changed", self.on_conf_change)),
        ]

        #         self.external = external.ActivitiesSource()

        self.show()

    def show(self):
        self.position_window()
        self.window.show_all()

        self.facts = None

        self.day_start = conf.get("day_start_minutes")
        self.day_start = dt.time(self.day_start / 60, self.day_start % 60)

        self.view_date = (
            dt.datetime.today() - dt.timedelta(hours=self.day_start.hour, minutes=self.day_start.minute)
        ).date()

        # set to monday
        self.start_date = self.view_date - dt.timedelta(self.view_date.weekday() + 1)

        # look if we need to start on sunday or monday
        self.start_date = self.start_date + dt.timedelta(stuff.locale_first_weekday())

        # see if we have not gotten carried away too much in all these calculations
        if (self.view_date - self.start_date) == dt.timedelta(7):
            self.start_date += dt.timedelta(7)

        self.end_date = self.start_date + dt.timedelta(6)

        self.current_range = "week"

        self.timechart.day_start = self.day_start

        self.search()

    def position_window(self):
        if conf.get("overview_window_maximized"):
            self.window.maximize()
        else:
            window_box = conf.get("overview_window_box")
            if window_box:
                x, y, w, h = (int(i) for i in window_box)
                self.window.move(x, y)
                self.window.resize(w, h)
            else:
                self.window.set_position(gtk.WIN_POS_CENTER)

    def on_fact_tree_button_press(self, treeview, event):
        if event.button == 3:
            x = int(event.x)
            y = int(event.y)
            time = event.time
            pthinfo = treeview.get_path_at_pos(x, y)
            if pthinfo is not None:
                path, col, cellx, celly = pthinfo
                treeview.grab_focus()
                treeview.set_cursor(path, col, 0)
                self.get_widget("fact_tree_popup").popup(None, None, None, event.button, time)
            return True

    def on_timechart_new_range(self, chart, start_date, end_date):
        self.start_date = start_date
        self.end_date = end_date
        self.apply_range_select()

    def on_timechart_zoom_out_clicked(self, chart):
        if self.end_date - self.start_date < dt.timedelta(days=6):
            self.on_week_activate(None)
        elif self.end_date - self.start_date < dt.timedelta(days=27):
            self.on_month_activate(None)
        else:
            self.current_range = "manual"
            self.start_date = self.view_date.replace(day=1, month=1)
            self.end_date = self.start_date.replace(year=self.start_date.year + 1) - dt.timedelta(days=1)
            self.apply_range_select()

    def search(self):
        if self.start_date > self.end_date:  # make sure the end is always after beginning
            self.start_date, self.end_date = self.end_date, self.start_date

        search_terms = self.get_widget("search").get_text().decode("utf8", "replace")
        self.facts = runtime.storage.get_facts(self.start_date, self.end_date, search_terms)

        self.get_widget("export").set_sensitive(len(self.facts) > 0)
        self.get_widget("export_rt").set_sensitive(len(self.facts) > 0)
        self.get_widget("export_rt").set_visible(conf.get("activities_source") == "rt")

        self.set_title()

        self.range_pick.set_range(self.start_date, self.end_date, self.view_date)

        durations = [(fact.start_time, fact.delta) for fact in self.facts]
        self.timechart.draw(durations, self.start_date, self.end_date)

        if self.get_widget("window_tabs").get_current_page() == 0:
            self.overview.search(self.start_date, self.end_date, self.facts)
            self.reports.search(self.start_date, self.end_date, self.facts)
        else:
            self.reports.search(self.start_date, self.end_date, self.facts)
            self.overview.search(self.start_date, self.end_date, self.facts)

    def set_title(self):
        self.title = stuff.format_range(self.start_date, self.end_date)
        self.window.set_title(self.title.decode("utf-8"))

    def on_conf_change(self, event, key, value):
        if key == "day_start_minutes":
            self.day_start = dt.time(value / 60, value % 60)
            self.timechart.day_start = self.day_start
            self.search()

    def on_fact_selection_changed(self, tree):
        """ enables and disables action buttons depending on selected item """
        fact = tree.get_selected_fact()
        real_fact = fact is not None and isinstance(fact, Fact)

        self.get_widget("remove").set_sensitive(real_fact)
        self.get_widget("edit").set_sensitive(real_fact)

        return True

    def after_activity_update(self, widget):
        self.search()

    def on_search_icon_press(self, widget, position, data):
        if position == gtk.ENTRY_ICON_SECONDARY:
            widget.set_text("")

        self.search()

    def on_search_activate(self, widget):
        self.search()

    def on_search_changed(self, widget):
        has_text = len(widget.get_text()) > 0
        widget.set_icon_sensitive(gtk.ENTRY_ICON_SECONDARY, has_text)

    def on_export_activate(self, widget):
        def on_report_chosen(widget, format, path):
            self.report_chooser = None
            reports.simple(self.facts, self.start_date, self.end_date, format, path)

            if format == ("html"):
                webbrowser.open_new("file://%s" % path)
            else:
                try:
                    gtk.show_uri(gtk.gdk.Screen(), "file://%s" % os.path.split(path)[0], 0L)
                except:
                    pass  # bug 626656 - no use in capturing this one i think

        def on_report_chooser_closed(widget):
            self.report_chooser = None

        if not self.report_chooser:
            self.report_chooser = widgets.ReportChooserDialog()
            self.report_chooser.connect("report-chosen", on_report_chosen)
            self.report_chooser.connect("report-chooser-closed", on_report_chooser_closed)
            self.report_chooser.show(self.start_date, self.end_date)
        else:
            self.report_chooser.present()

    def apply_range_select(self):
        if self.view_date < self.start_date:
            self.view_date = self.start_date

        if self.view_date > self.end_date:
            self.view_date = self.end_date

        self.search()

    def on_range_selected(self, widget, range, start, end):
        self.current_range = range
        self.start_date = start
        self.end_date = end
        self.apply_range_select()

    def on_day_activate(self, button):
        self.current_range = "day"
        self.start_date = self.view_date
        self.end_date = self.start_date + dt.timedelta(0)
        self.apply_range_select()

    def on_week_activate(self, button):
        self.current_range = "week"
        self.start_date, self.end_date = stuff.week(self.view_date)
        self.apply_range_select()

    def on_month_activate(self, button):
        self.current_range = "month"
        self.start_date, self.end_date = stuff.month(self.view_date)
        self.apply_range_select()

    def on_manual_range_apply_clicked(self, button):
        self.current_range = "manual"
        cal_date = self.get_widget("start_calendar").get_date()
        self.start_date = dt.date(cal_date[0], cal_date[1] + 1, cal_date[2])

        cal_date = self.get_widget("end_calendar").get_date()
        self.end_date = dt.date(cal_date[0], cal_date[1] + 1, cal_date[2])

        self.apply_range_select()

    def on_tabs_window_configure_event(self, window, event):
        # this is required so that the rows would grow on resize
        self.fact_tree.fix_row_heights()

    def on_tabs_window_state_changed(self, window, event):
        # not enough space - maximized the overview window
        maximized = window.get_window().get_state() & gtk.gdk.WINDOW_STATE_MAXIMIZED
        if maximized:
            trophies.unlock("not_enough_space")

    def on_prev_activate(self, action):
        if self.current_range == "day":
            self.start_date -= dt.timedelta(1)
            self.end_date -= dt.timedelta(1)
        elif self.current_range == "week":
            self.start_date -= dt.timedelta(7)
            self.end_date -= dt.timedelta(7)
        elif self.current_range == "month":
            self.end_date = self.start_date - dt.timedelta(1)
            first_weekday, days_in_month = calendar.monthrange(self.end_date.year, self.end_date.month)
            self.start_date = self.end_date - dt.timedelta(days_in_month - 1)
        else:
            # manual range - just jump to the next window
            days = (self.end_date - self.start_date) + dt.timedelta(days=1)
            self.start_date = self.start_date - days
            self.end_date = self.end_date - days

        self.view_date = self.start_date
        self.search()

    def on_next_activate(self, action):
        if self.current_range == "day":
            self.start_date += dt.timedelta(1)
            self.end_date += dt.timedelta(1)
        elif self.current_range == "week":
            self.start_date += dt.timedelta(7)
            self.end_date += dt.timedelta(7)
        elif self.current_range == "month":
            self.start_date = self.end_date + dt.timedelta(1)
            first_weekday, days_in_month = calendar.monthrange(self.start_date.year, self.start_date.month)
            self.end_date = self.start_date + dt.timedelta(days_in_month - 1)
        else:
            # manual range - just jump to the next window
            days = (self.end_date - self.start_date) + dt.timedelta(days=1)
            self.start_date = self.start_date + days
            self.end_date = self.end_date + days

        self.view_date = self.start_date
        self.search()

    def on_home_activate(self, action):
        self.view_date = (
            dt.datetime.today() - dt.timedelta(hours=self.day_start.hour, minutes=self.day_start.minute)
        ).date()
        if self.current_range == "day":
            self.start_date = self.view_date
            self.end_date = self.start_date + dt.timedelta(0)

        elif self.current_range == "week":
            self.start_date = self.view_date - dt.timedelta(self.view_date.weekday() + 1)
            self.start_date = self.start_date + dt.timedelta(stuff.locale_first_weekday())
            self.end_date = self.start_date + dt.timedelta(6)
        elif self.current_range == "month":
            self.start_date = self.view_date - dt.timedelta(self.view_date.day - 1)  # set to beginning of month
            first_weekday, days_in_month = calendar.monthrange(self.view_date.year, self.view_date.month)
            self.end_date = self.start_date + dt.timedelta(days_in_month - 1)
        else:
            days = self.end_date - self.start_date
            self.start_date = self.view_date
            self.end_date = self.view_date + days

        self.search()

    def get_widget(self, name):
        """ skip one variable (huh) """
        return self._gui.get_object(name)

    def on_window_tabs_switch_page(self, notebook, page, pagenum):
        if pagenum == 0:
            self.on_fact_selection_changed(self.fact_tree)
        elif pagenum == 1:
            self.get_widget("remove").set_sensitive(False)
            self.get_widget("edit").set_sensitive(False)
            self.reports.do_charts()

    def on_add_activate(self, action):
        fact = self.fact_tree.get_selected_fact()
        if not fact:
            selected_date = self.start_date
        elif isinstance(fact, dt.date):
            selected_date = fact
        else:
            selected_date = fact["date"]

        dialogs.edit.show(self, fact_date=selected_date)

    def on_remove_activate(self, button):
        self.overview.delete_selected()

    def on_edit_activate(self, button):
        fact = self.fact_tree.get_selected_fact()
        if not fact or isinstance(fact, dt.date):
            return
        dialogs.edit.show(self, fact_id=fact.id)

    def on_tabs_window_deleted(self, widget, event):
        self.close_window()

    def on_window_key_pressed(self, tree, event_key):
        if event_key.keyval == gtk.keysyms.Escape or (
            event_key.keyval == gtk.keysyms.w and event_key.state & gtk.gdk.CONTROL_MASK
        ):
            self.close_window()

    def on_close_activate(self, action):
        self.close_window()

    def close_window(self):
        # properly saving window state and position
        maximized = self.window.get_window().get_state() & gtk.gdk.WINDOW_STATE_MAXIMIZED
        conf.set("overview_window_maximized", maximized)

        # make sure to remember dimensions only when in normal state
        if maximized == False and not self.window.get_window().get_state() & gtk.gdk.WINDOW_STATE_ICONIFIED:
            x, y = self.window.get_position()
            w, h = self.window.get_size()
            conf.set("overview_window_box", [x, y, w, h])

        if not self.parent:
            gtk.main_quit()
        else:
            for obj, handler in self.external_listeners:
                obj.disconnect(handler)
            self._gui = None
            self.window.destroy()
            self.window = None

            self.emit("on-close")

    #    UNUSED
    def on_done_activate(self, button):
        pass

    #    UNUSED
    def on_export_rt_activate(self, widget):
        pass

    def on_start_activate(self, button):
        to_report = []
        if runtime.get_external().source == SOURCE_RT or runtime.get_external().source == SOURCE_REDMINE:
            to_report = filter(self.__is_rt_ticket, self.fact_tree.get_model())
        elif runtime.get_external().source == SOURCE_JIRA:
            to_report = filter(self.__is_jira_ticket, self.fact_tree.get_model())
        to_report = [row[0].fact for row in to_report]
        dialogs.export_rt.show(self, facts=to_report)

    #     def on_start_activate_2(self, button):
    #         self.start_button.set_sensitive(False)
    #         while gtk.events_pending():
    #             gtk.main_iteration()
    # #        runtime.storage.update_fact(fact_id, fact, temporary_activity, exported)
    #         tree = self.fact_tree
    #         to_report = filter(self.__is_rt_ticket, tree.get_model())
    #
    #         for row in to_report:
    #             self.__report(row[0])
    #
    #         self.search()
    #         while gtk.events_pending():
    #             gtk.main_iteration()
    #         self.start_button.set_sensitive(True)

    def __is_rt_ticket(self, row):
        if not runtime.get_external().rt:
            logging.warn("Not connected to/logged in RT")
            return False
        if not isinstance(row[0], FactRow):
            return False
        #            self.__report(row[0])
        fact = row[0].fact
        match = re.match(TICKET_NAME_REGEX, fact.activity)
        if row[0].selected and fact.end_time and match:
            return True
        else:
            return False

    def __is_jira_ticket(self, row):
        if not runtime.get_external().jira:
            logging.warn("Not connected to/logged in JIRA")
            return False
        if not isinstance(row[0], FactRow):
            return False
        #            self.__report(row[0])
        fact = row[0].fact
        match = re.match(JIRA_ISSUE_NAME_REGEX, fact.activity)
        if row[0].selected and fact.end_time and match:
            return True
        else:
            return False

    def __report(self, fact_row):
        fact = fact_row.fact
        logging.warn(fact_row.name)
        if runtime.get_external().tracker:
            match = re.match(TICKET_NAME_REGEX, fact.activity)
            #            if not fact_row.selected:
            #                logging.warn("Row not selected: %s" % fact.activity)
            if fact_row.selected and fact.end_time and match:
                ticket_id = match.group(1)
                text = self.get_text(fact)
                time_worked = stuff.duration_minutes(fact.delta)
                if runtime.get_external().tracker.comment(ticket_id, text, time_worked):
                    logging.warn("updated ticket #%s: %s - %s min" % (ticket_id, text, time_worked))
                    runtime.storage.update_fact(fact.id, fact, False, True)
                    fact_row.selected = False

            else:
                logging.warn("Not a RT ticket or in progress: %s" % fact.activity)
        else:
            logging.warn("Not connected to/logged in RT")

    def get_text(self, fact):
        text = "%s, %s-%s" % (fact.date, fact.start_time.strftime("%H:%M"), fact.end_time.strftime("%H:%M"))
        if fact.description:
            text += ": %s" % (fact.description)
        if fact.tags:
            text += " (" + ", ".join(fact.tags) + ")"
        return text

    def on_delete_window(self, window, event):
        self.close_window()
        return True
Example #5
0
class Overview(gtk.Object):
    __gsignals__ = {
        "on-close": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()),
    }

    def __init__(self, parent=None):
        gtk.Object.__init__(self)

        self.parent = parent  # determine if app should shut down on close
        self._gui = load_ui_file("overview.ui")
        self.report_chooser = None
        self.window = self.get_widget("tabs_window")
        self.window.connect("delete_event", self.on_delete_window)

        self.range_pick = widgets.RangePick()
        self.get_widget("range_pick_box").add(self.range_pick)
        self.range_pick.connect("range-selected", self.on_range_selected)

        self.overview = OverviewBox()
        self.get_widget("overview_tab").add(self.overview)
        self.fact_tree = self.overview.fact_tree  # TODO - this is upside down, should maybe get the overview tab over here
        self.fact_tree.connect("cursor-changed",
                               self.on_fact_selection_changed)

        self.fact_tree.connect("button-press-event",
                               self.on_fact_tree_button_press)

        self.reports = TotalsBox()
        self.get_widget("reports_tab").add(self.reports)

        self.timechart = widgets.TimeChart()
        self.timechart.connect("zoom-out-clicked",
                               self.on_timechart_zoom_out_clicked)
        self.timechart.connect("range-picked", self.on_timechart_new_range)
        self.get_widget("by_day_box").add(self.timechart)
        self.start_button = self.get_widget("start_button")

        self._gui.connect_signals(self)

        self.external_listeners = [
            (runtime.storage,
             runtime.storage.connect('activities-changed',
                                     self.after_activity_update)),
            (runtime.storage,
             runtime.storage.connect('facts-changed',
                                     self.after_activity_update)),
            (conf, conf.connect('conf-changed', self.on_conf_change))
        ]

        self.show()

    def show(self):
        self.position_window()
        self.window.show_all()

        self.facts = None

        self.day_start = conf.get("day_start_minutes")
        self.day_start = dt.time(self.day_start / 60, self.day_start % 60)

        self.view_date = (dt.datetime.today() - dt.timedelta(
            hours=self.day_start.hour, minutes=self.day_start.minute)).date()

        self.start_date = self.view_date
        self.end_date = self.start_date + dt.timedelta(0)
        self.current_range = "day"

        self.timechart.day_start = self.day_start

        self.search()

    def position_window(self):
        if conf.get("overview_window_maximized"):
            self.window.maximize()
        else:
            window_box = conf.get("overview_window_box")
            if window_box:
                x, y, w, h = (int(i) for i in window_box)
                self.window.move(x, y)
                self.window.resize(w, h)
            else:
                self.window.set_position(gtk.WIN_POS_CENTER)

    def on_fact_tree_button_press(self, treeview, event):
        if event.button == 3:
            x = int(event.x)
            y = int(event.y)
            time = event.time
            pthinfo = treeview.get_path_at_pos(x, y)
            if pthinfo is not None:
                path, col, cellx, celly = pthinfo
                treeview.grab_focus()
                treeview.set_cursor(path, col, 0)
                self.get_widget("fact_tree_popup").popup(
                    None, None, None, event.button, time)
            return True

    def on_timechart_new_range(self, chart, start_date, end_date):
        self.start_date = start_date
        self.end_date = end_date
        self.apply_range_select()

    def on_timechart_zoom_out_clicked(self, chart):
        if (self.end_date - self.start_date < dt.timedelta(days=6)):
            self.on_week_activate(None)
        elif (self.end_date - self.start_date < dt.timedelta(days=27)):
            self.on_month_activate(None)
        else:
            self.current_range = "manual"
            self.start_date = self.view_date.replace(day=1, month=1)
            self.end_date = self.start_date.replace(year=self.start_date.year +
                                                    1) - dt.timedelta(days=1)
            self.apply_range_select()

    def search(self):
        if self.start_date > self.end_date:  # make sure the end is always after beginning
            self.start_date, self.end_date = self.end_date, self.start_date

        search_terms = self.get_widget("search").get_text().decode(
            "utf8", "replace")
        self.facts = runtime.storage.get_facts(self.start_date, self.end_date,
                                               search_terms)

        self.get_widget("export").set_sensitive(len(self.facts) > 0)

        self.set_title()

        self.range_pick.set_range(self.start_date, self.end_date,
                                  self.view_date)

        durations = [(fact.start_time, fact.delta) for fact in self.facts]
        self.timechart.draw(durations, self.start_date, self.end_date)

        if self.get_widget("window_tabs").get_current_page() == 0:
            self.overview.search(self.start_date, self.end_date, self.facts)
            self.reports.search(self.start_date, self.end_date, self.facts)
        else:
            self.reports.search(self.start_date, self.end_date, self.facts)
            self.overview.search(self.start_date, self.end_date, self.facts)

    def set_title(self):
        self.title = stuff.format_range(self.start_date, self.end_date)
        self.window.set_title(self.title.decode("utf-8"))

    def on_conf_change(self, event, key, value):
        if key == "day_start_minutes":
            self.day_start = dt.time(value / 60, value % 60)
            self.timechart.day_start = self.day_start
            self.search()

    def on_fact_selection_changed(self, tree):
        """ enables and disables action buttons depending on selected item """
        fact = tree.get_selected_fact()
        real_fact = fact is not None and isinstance(fact, Fact)

        self.get_widget('remove').set_sensitive(real_fact)
        self.get_widget('edit').set_sensitive(real_fact)

        return True

    def after_activity_update(self, widget):
        self.search()

    def on_search_icon_press(self, widget, position, data):
        if position == gtk.ENTRY_ICON_SECONDARY:
            widget.set_text('')

        self.search()

    def on_search_activate(self, widget):
        self.search()

    def on_search_changed(self, widget):
        has_text = len(widget.get_text()) > 0
        widget.set_icon_sensitive(gtk.ENTRY_ICON_SECONDARY, has_text)

    def on_export_activate(self, widget):
        def on_report_chosen(widget, format, path):
            self.report_chooser = None
            reports.simple(self.facts, self.start_date, self.end_date, format,
                           path)

            if format == ("html"):
                webbrowser.open_new("file://%s" % path)
            else:
                try:
                    gtk.show_uri(gtk.gdk.Screen(),
                                 "file://%s" % os.path.split(path)[0], 0L)
                except:
                    pass  # bug 626656 - no use in capturing this one i think

        def on_report_chooser_closed(widget):
            self.report_chooser = None

        if not self.report_chooser:
            self.report_chooser = widgets.ReportChooserDialog()
            self.report_chooser.connect("report-chosen", on_report_chosen)
            self.report_chooser.connect("report-chooser-closed",
                                        on_report_chooser_closed)
            self.report_chooser.show(self.start_date, self.end_date)
        else:
            self.report_chooser.present()

    def apply_range_select(self):
        if self.view_date < self.start_date:
            self.view_date = self.start_date

        if self.view_date > self.end_date:
            self.view_date = self.end_date

        self.search()

    def on_range_selected(self, widget, range, start, end):
        self.current_range = range
        self.start_date = start
        self.end_date = end
        self.apply_range_select()

    def on_day_activate(self, button):
        self.current_range = "day"
        self.start_date = self.view_date
        self.end_date = self.start_date + dt.timedelta(0)
        self.apply_range_select()

    def on_week_activate(self, button):
        self.current_range = "week"
        self.start_date, self.end_date = stuff.week(self.view_date)
        self.apply_range_select()

    def on_month_activate(self, button):
        self.current_range = "month"
        self.start_date, self.end_date = stuff.month(self.view_date)
        self.apply_range_select()

    def on_manual_range_apply_clicked(self, button):
        self.current_range = "manual"
        cal_date = self.get_widget("start_calendar").get_date()
        self.start_date = dt.date(cal_date[0], cal_date[1] + 1, cal_date[2])

        cal_date = self.get_widget("end_calendar").get_date()
        self.end_date = dt.date(cal_date[0], cal_date[1] + 1, cal_date[2])

        self.apply_range_select()

    def on_tabs_window_configure_event(self, window, event):
        # this is required so that the rows would grow on resize
        self.fact_tree.fix_row_heights()

    def on_tabs_window_state_changed(self, window, event):
        # not enough space - maximized the overview window
        maximized = window.get_window().get_state(
        ) & gtk.gdk.WINDOW_STATE_MAXIMIZED
        if maximized:
            trophies.unlock("not_enough_space")

    def on_prev_activate(self, action):
        if self.current_range == "day":
            self.start_date -= dt.timedelta(1)
            self.end_date -= dt.timedelta(1)
        elif self.current_range == "week":
            self.start_date -= dt.timedelta(7)
            self.end_date -= dt.timedelta(7)
        elif self.current_range == "month":
            self.end_date = self.start_date - dt.timedelta(1)
            first_weekday, days_in_month = calendar.monthrange(
                self.end_date.year, self.end_date.month)
            self.start_date = self.end_date - dt.timedelta(days_in_month - 1)
        else:
            # manual range - just jump to the next window
            days = (self.end_date - self.start_date) + dt.timedelta(days=1)
            self.start_date = self.start_date - days
            self.end_date = self.end_date - days

        self.view_date = self.start_date
        self.search()

    def on_next_activate(self, action):
        if self.current_range == "day":
            self.start_date += dt.timedelta(1)
            self.end_date += dt.timedelta(1)
        elif self.current_range == "week":
            self.start_date += dt.timedelta(7)
            self.end_date += dt.timedelta(7)
        elif self.current_range == "month":
            self.start_date = self.end_date + dt.timedelta(1)
            first_weekday, days_in_month = calendar.monthrange(
                self.start_date.year, self.start_date.month)
            self.end_date = self.start_date + dt.timedelta(days_in_month - 1)
        else:
            # manual range - just jump to the next window
            days = (self.end_date - self.start_date) + dt.timedelta(days=1)
            self.start_date = self.start_date + days
            self.end_date = self.end_date + days

        self.view_date = self.start_date
        self.search()

    def on_home_activate(self, action):
        self.view_date = (dt.datetime.today() - dt.timedelta(
            hours=self.day_start.hour, minutes=self.day_start.minute)).date()
        if self.current_range == "day":
            self.start_date = self.view_date
            self.end_date = self.start_date + dt.timedelta(0)

        elif self.current_range == "week":
            self.start_date = self.view_date - dt.timedelta(
                self.view_date.weekday() + 1)
            self.start_date = self.start_date + dt.timedelta(
                stuff.locale_first_weekday())
            self.end_date = self.start_date + dt.timedelta(6)
        elif self.current_range == "month":
            self.start_date = self.view_date - dt.timedelta(
                self.view_date.day - 1)  #set to beginning of month
            first_weekday, days_in_month = calendar.monthrange(
                self.view_date.year, self.view_date.month)
            self.end_date = self.start_date + dt.timedelta(days_in_month - 1)
        else:
            days = (self.end_date - self.start_date)
            self.start_date = self.view_date
            self.end_date = self.view_date + days

        self.search()

    def get_widget(self, name):
        """ skip one variable (huh) """
        return self._gui.get_object(name)

    def on_window_tabs_switch_page(self, notebook, page, pagenum):
        if pagenum == 0:
            self.on_fact_selection_changed(self.fact_tree)
        elif pagenum == 1:
            self.get_widget('remove').set_sensitive(False)
            self.get_widget('edit').set_sensitive(False)
            self.reports.do_charts()

    def on_add_activate(self, action):
        fact = self.fact_tree.get_selected_fact()
        if not fact:
            selected_date = self.start_date
        elif isinstance(fact, dt.date):
            selected_date = fact
        else:
            selected_date = fact["date"]

        dialogs.edit.show(self, fact_date=selected_date)

    def on_remove_activate(self, button):
        self.overview.delete_selected()

    def on_edit_activate(self, button):
        fact = self.fact_tree.get_selected_fact()
        if not fact or isinstance(fact, dt.date):
            return
        dialogs.edit.show(self, fact_id=fact.id)

    def on_tabs_window_deleted(self, widget, event):
        self.close_window()

    def on_window_key_pressed(self, tree, event_key):
        if (event_key.keyval == gtk.keysyms.Escape
                or (event_key.keyval == gtk.keysyms.w
                    and event_key.state & gtk.gdk.CONTROL_MASK)):
            self.close_window()

    def on_close_activate(self, action):
        self.close_window()

    def close_window(self):
        # properly saving window state and position
        maximized = self.window.get_window().get_state(
        ) & gtk.gdk.WINDOW_STATE_MAXIMIZED
        conf.set("overview_window_maximized", maximized)

        # make sure to remember dimensions only when in normal state
        if maximized == False and not self.window.get_window().get_state(
        ) & gtk.gdk.WINDOW_STATE_ICONIFIED:
            x, y = self.window.get_position()
            w, h = self.window.get_size()
            conf.set("overview_window_box", [x, y, w, h])

        if not self.parent:
            gtk.main_quit()
        else:
            for obj, handler in self.external_listeners:
                obj.disconnect(handler)
            self._gui = None
            self.window.destroy()
            self.window = None
            self.emit("on-close")

    def on_start_activate(self, button):
        if conf.get("activities_source") == "":
            logging.warn("Not connected to an external source.")
        else:
            to_report = filter(self.__is_rt_ticket, self.fact_tree.get_model())
            to_report = [row[0].fact for row in to_report]
            dialogs.export_rt.show(self, facts=to_report)

    def __is_rt_ticket(self, row):
        if not isinstance(row[0], FactRow):
            return False
        fact = row[0].fact
        match = re.match(TICKET_NAME_REGEX, fact.activity)
        if row[0].selected and fact.end_time and match:
            return True
        else:
            return False

    def get_text(self, fact):
        text = "%s, %s-%s" % (fact.date, fact.start_time.strftime("%H:%M"),
                              fact.end_time.strftime("%H:%M"))
        if fact.description:
            text += ": %s" % (fact.description)
        if fact.tags:
            text += " (" + ", ".join(fact.tags) + ")"
        return text

    def on_delete_window(self, window, event):
        self.close_window()
        return True

    #PRL
    def on_get_redmine_issues(self, button):
        result = runtime.storage.get_redmine_issues()

        message_type = gtk.MESSAGE_INFO
        title = "Issues updated"
        text = "New issues: %s" % result

        if result < 0:
            message_type = gtk.MESSAGE_ERROR
            title = "Error"
            text = "An error occured while trying to update issues"

        message = gtk.MessageDialog(self.window, gtk.DIALOG_MODAL,
                                    message_type, gtk.BUTTONS_OK)
        message.set_title(title)
        message.set_markup(text)
        message.run()
        message.destroy()
Example #6
0
    def __init__(self, parent=None):
        self.parent = parent  # determine if app should shut down on close
        self._gui = load_ui_file("overview.ui")
        self.report_chooser = None

        self.facts = None

        self.window = self.get_widget("tabs_window")

        self.day_start = conf.get("day_start_minutes")
        self.day_start = dt.time(self.day_start / 60, self.day_start % 60)

        self.view_date = (dt.datetime.today() - dt.timedelta(
            hours=self.day_start.hour, minutes=self.day_start.minute)).date()

        self.range_pick = widgets.RangePick()
        self.get_widget("range_pick_box").add(self.range_pick)
        self.range_pick.connect("range-selected", self.on_range_selected)

        #set to monday
        self.start_date = self.view_date - dt.timedelta(
            self.view_date.weekday() + 1)

        # look if we need to start on sunday or monday
        self.start_date = self.start_date + dt.timedelta(
            stuff.locale_first_weekday())

        # see if we have not gotten carried away too much in all these calculations
        if (self.view_date - self.start_date) == dt.timedelta(7):
            self.start_date += dt.timedelta(7)

        self.end_date = self.start_date + dt.timedelta(6)

        self.overview = OverviewBox()
        self.get_widget("overview_tab").add(self.overview)
        self.fact_tree = self.overview.fact_tree  # TODO - this is upside down, should maybe get the overview tab over here
        self.fact_tree.connect("cursor-changed",
                               self.on_fact_selection_changed)

        self.fact_tree.connect("button-press-event",
                               self.on_fact_tree_button_press)

        self.reports = TotalsBox()
        self.get_widget("reports_tab").add(self.reports)

        self.current_range = "week"

        self.timechart = widgets.TimeChart()
        self.timechart.connect("zoom-out-clicked",
                               self.on_timechart_zoom_out_clicked)
        self.timechart.connect("range-picked", self.on_timechart_new_range)
        self.timechart.day_start = self.day_start

        self.get_widget("by_day_box").add(self.timechart)

        self._gui.connect_signals(self)
        runtime.storage.connect('activities-changed',
                                self.after_activity_update)
        runtime.storage.connect('facts-changed', self.after_activity_update)

        conf.connect('conf-changed', self.on_conf_change)

        if conf.get("overview_window_maximized"):
            self.window.maximize()
        else:
            window_box = conf.get("overview_window_box")
            if window_box:
                x, y, w, h = (int(i) for i in window_box)
                self.window.move(x, y)
                self.window.resize(w, h)
            else:
                self.window.set_position(gtk.WIN_POS_CENTER)

        self.window.show_all()

        self.search()
Example #7
0
class Overview(object):
    def __init__(self, parent=None):
        self.parent = parent  # determine if app should shut down on close
        self._gui = load_ui_file("overview.ui")
        self.report_chooser = None

        self.facts = None

        self.window = self.get_widget("tabs_window")

        self.day_start = conf.get("day_start_minutes")
        self.day_start = dt.time(self.day_start / 60, self.day_start % 60)

        self.view_date = (dt.datetime.today() - dt.timedelta(
            hours=self.day_start.hour, minutes=self.day_start.minute)).date()

        self.range_pick = widgets.RangePick()
        self.get_widget("range_pick_box").add(self.range_pick)
        self.range_pick.connect("range-selected", self.on_range_selected)

        #set to monday
        self.start_date = self.view_date - dt.timedelta(
            self.view_date.weekday() + 1)

        # look if we need to start on sunday or monday
        self.start_date = self.start_date + dt.timedelta(
            stuff.locale_first_weekday())

        # see if we have not gotten carried away too much in all these calculations
        if (self.view_date - self.start_date) == dt.timedelta(7):
            self.start_date += dt.timedelta(7)

        self.end_date = self.start_date + dt.timedelta(6)

        self.overview = OverviewBox()
        self.get_widget("overview_tab").add(self.overview)
        self.fact_tree = self.overview.fact_tree  # TODO - this is upside down, should maybe get the overview tab over here
        self.fact_tree.connect("cursor-changed",
                               self.on_fact_selection_changed)

        self.fact_tree.connect("button-press-event",
                               self.on_fact_tree_button_press)

        self.reports = TotalsBox()
        self.get_widget("reports_tab").add(self.reports)

        self.current_range = "week"

        self.timechart = widgets.TimeChart()
        self.timechart.connect("zoom-out-clicked",
                               self.on_timechart_zoom_out_clicked)
        self.timechart.connect("range-picked", self.on_timechart_new_range)
        self.timechart.day_start = self.day_start

        self.get_widget("by_day_box").add(self.timechart)

        self._gui.connect_signals(self)
        runtime.storage.connect('activities-changed',
                                self.after_activity_update)
        runtime.storage.connect('facts-changed', self.after_activity_update)

        conf.connect('conf-changed', self.on_conf_change)

        if conf.get("overview_window_maximized"):
            self.window.maximize()
        else:
            window_box = conf.get("overview_window_box")
            if window_box:
                x, y, w, h = (int(i) for i in window_box)
                self.window.move(x, y)
                self.window.resize(w, h)
            else:
                self.window.set_position(gtk.WIN_POS_CENTER)

        self.window.show_all()

        self.search()

    def on_fact_tree_button_press(self, treeview, event):
        if event.button == 3:
            x = int(event.x)
            y = int(event.y)
            time = event.time
            pthinfo = treeview.get_path_at_pos(x, y)
            if pthinfo is not None:
                path, col, cellx, celly = pthinfo
                treeview.grab_focus()
                treeview.set_cursor(path, col, 0)
                self.get_widget("fact_tree_popup").popup(
                    None, None, None, event.button, time)
            return True

    def on_timechart_new_range(self, chart, start_date, end_date):
        self.start_date = start_date
        self.end_date = end_date
        self.apply_range_select()

    def on_timechart_zoom_out_clicked(self, chart):
        if (self.end_date - self.start_date < dt.timedelta(days=6)):
            self.on_week_activate(None)
        elif (self.end_date - self.start_date < dt.timedelta(days=27)):
            self.on_month_activate(None)
        else:
            self.current_range = "manual"
            self.start_date = self.view_date.replace(day=1, month=1)
            self.end_date = self.start_date.replace(year=self.start_date.year +
                                                    1) - dt.timedelta(days=1)
            self.apply_range_select()

    def search(self):
        if self.start_date > self.end_date:  # make sure the end is always after beginning
            self.start_date, self.end_date = self.end_date, self.start_date

        search_terms = self.get_widget("search").get_text().decode(
            "utf8", "replace")
        self.facts = runtime.storage.get_facts(self.start_date, self.end_date,
                                               search_terms)

        self.get_widget("export").set_sensitive(len(self.facts) > 0)

        self.set_title()

        self.range_pick.set_range(self.start_date, self.end_date,
                                  self.view_date)

        durations = [(fact.start_time, fact.delta) for fact in self.facts]
        self.timechart.draw(durations, self.start_date, self.end_date)

        if self.get_widget("window_tabs").get_current_page() == 0:
            self.overview.search(self.start_date, self.end_date, self.facts)
            self.reports.search(self.start_date, self.end_date, self.facts)
        else:
            self.reports.search(self.start_date, self.end_date, self.facts)
            self.overview.search(self.start_date, self.end_date, self.facts)

    def set_title(self):
        self.title = stuff.format_range(self.start_date, self.end_date)
        self.window.set_title(self.title.decode("utf-8"))

    def on_conf_change(self, event, key, value):
        if key == "day_start_minutes":
            self.day_start = dt.time(value / 60, value % 60)
            self.timechart.day_start = self.day_start
            self.search()

    def on_fact_selection_changed(self, tree):
        """ enables and disables action buttons depending on selected item """
        fact = tree.get_selected_fact()
        real_fact = fact is not None and isinstance(fact, stuff.Fact)

        self.get_widget('remove').set_sensitive(real_fact)
        self.get_widget('edit').set_sensitive(real_fact)

        return True

    def after_activity_update(self, widget):
        self.search()

    def on_search_icon_press(self, widget, position, data):
        if position == gtk.ENTRY_ICON_SECONDARY:
            widget.set_text('')

        self.search()

    def on_search_activate(self, widget):
        self.search()

    def on_search_changed(self, widget):
        has_text = len(widget.get_text()) > 0
        widget.set_icon_sensitive(gtk.ENTRY_ICON_SECONDARY, has_text)

    def on_export_activate(self, widget):
        def on_report_chosen(widget, format, path):
            self.report_chooser = None
            reports.simple(self.facts, self.start_date, self.end_date, format,
                           path)

            if format == ("html"):
                webbrowser.open_new("file://%s" % path)
            else:
                try:
                    gtk.show_uri(gtk.gdk.Screen(),
                                 "file://%s" % os.path.split(path)[0], 0L)
                except:
                    pass  # bug 626656 - no use in capturing this one i think

        def on_report_chooser_closed(widget):
            self.report_chooser = None

        if not self.report_chooser:
            self.report_chooser = widgets.ReportChooserDialog()
            self.report_chooser.connect("report-chosen", on_report_chosen)
            self.report_chooser.connect("report-chooser-closed",
                                        on_report_chooser_closed)
            self.report_chooser.show(self.start_date, self.end_date)
        else:
            self.report_chooser.present()

    def apply_range_select(self):
        if self.view_date < self.start_date:
            self.view_date = self.start_date

        if self.view_date > self.end_date:
            self.view_date = self.end_date

        self.search()

    def on_range_selected(self, widget, range, start, end):
        self.current_range = range
        self.start_date = start
        self.end_date = end
        self.apply_range_select()

    def on_day_activate(self, button):
        self.current_range = "day"
        self.start_date = self.view_date
        self.end_date = self.start_date + dt.timedelta(0)
        self.apply_range_select()

    def on_week_activate(self, button):
        self.current_range = "week"
        self.start_date, self.end_date = stuff.week(self.view_date)
        self.apply_range_select()

    def on_month_activate(self, button):
        self.current_range = "month"
        self.start_date, self.end_date = stuff.month(self.view_date)
        self.apply_range_select()

    def on_manual_range_apply_clicked(self, button):
        self.current_range = "manual"
        cal_date = self.get_widget("start_calendar").get_date()
        self.start_date = dt.date(cal_date[0], cal_date[1] + 1, cal_date[2])

        cal_date = self.get_widget("end_calendar").get_date()
        self.end_date = dt.date(cal_date[0], cal_date[1] + 1, cal_date[2])

        self.apply_range_select()

    def on_tabs_window_configure_event(self, window, event):
        # this is required so that the rows would grow on resize
        self.fact_tree.fix_row_heights()

    def on_tabs_window_state_changed(self, window, event):
        # not enough space - maximized the overview window
        maximized = window.get_window().get_state(
        ) & gtk.gdk.WINDOW_STATE_MAXIMIZED
        if maximized:
            trophies.unlock("not_enough_space")

    def on_prev_activate(self, action):
        if self.current_range == "day":
            self.start_date -= dt.timedelta(1)
            self.end_date -= dt.timedelta(1)
        elif self.current_range == "week":
            self.start_date -= dt.timedelta(7)
            self.end_date -= dt.timedelta(7)
        elif self.current_range == "month":
            self.end_date = self.start_date - dt.timedelta(1)
            first_weekday, days_in_month = calendar.monthrange(
                self.end_date.year, self.end_date.month)
            self.start_date = self.end_date - dt.timedelta(days_in_month - 1)
        else:
            # manual range - just jump to the next window
            days = (self.end_date - self.start_date) + dt.timedelta(days=1)
            self.start_date = self.start_date - days
            self.end_date = self.end_date - days

        self.view_date = self.start_date
        self.search()

    def on_next_activate(self, action):
        if self.current_range == "day":
            self.start_date += dt.timedelta(1)
            self.end_date += dt.timedelta(1)
        elif self.current_range == "week":
            self.start_date += dt.timedelta(7)
            self.end_date += dt.timedelta(7)
        elif self.current_range == "month":
            self.start_date = self.end_date + dt.timedelta(1)
            first_weekday, days_in_month = calendar.monthrange(
                self.start_date.year, self.start_date.month)
            self.end_date = self.start_date + dt.timedelta(days_in_month - 1)
        else:
            # manual range - just jump to the next window
            days = (self.end_date - self.start_date) + dt.timedelta(days=1)
            self.start_date = self.start_date + days
            self.end_date = self.end_date + days

        self.view_date = self.start_date
        self.search()

    def on_home_activate(self, action):
        self.view_date = (dt.datetime.today() - dt.timedelta(
            hours=self.day_start.hour, minutes=self.day_start.minute)).date()
        if self.current_range == "day":
            self.start_date = self.view_date
            self.end_date = self.start_date + dt.timedelta(0)

        elif self.current_range == "week":
            self.start_date = self.view_date - dt.timedelta(
                self.view_date.weekday() + 1)
            self.start_date = self.start_date + dt.timedelta(
                stuff.locale_first_weekday())
            self.end_date = self.start_date + dt.timedelta(6)
        elif self.current_range == "month":
            self.start_date = self.view_date - dt.timedelta(
                self.view_date.day - 1)  #set to beginning of month
            first_weekday, days_in_month = calendar.monthrange(
                self.view_date.year, self.view_date.month)
            self.end_date = self.start_date + dt.timedelta(days_in_month - 1)
        else:
            days = (self.end_date - self.start_date)
            self.start_date = self.view_date
            self.end_date = self.view_date + days

        self.search()

    def get_widget(self, name):
        """ skip one variable (huh) """
        return self._gui.get_object(name)

    def on_window_tabs_switch_page(self, notebook, page, pagenum):
        if pagenum == 0:
            self.on_fact_selection_changed(self.fact_tree)
        elif pagenum == 1:
            self.get_widget('remove').set_sensitive(False)
            self.get_widget('edit').set_sensitive(False)
            self.reports.do_charts()

    def on_add_activate(self, action):
        fact = self.fact_tree.get_selected_fact()
        if not fact:
            selected_date = self.start_date
        elif isinstance(fact, dt.date):
            selected_date = fact
        else:
            selected_date = fact["date"]

        dialogs.edit.show(self, fact_date=selected_date)

    def on_remove_activate(self, button):
        self.overview.delete_selected()

    def on_edit_activate(self, button):
        fact = self.fact_tree.get_selected_fact()
        if not fact or isinstance(fact, dt.date):
            return
        dialogs.edit.show(self, fact_id=fact.id)

    def on_tabs_window_deleted(self, widget, event):
        self.close_window()

    def on_window_key_pressed(self, tree, event_key):
        if (event_key.keyval == gtk.keysyms.Escape
                or (event_key.keyval == gtk.keysyms.w
                    and event_key.state & gtk.gdk.CONTROL_MASK)):
            self.close_window()

    def on_close_activate(self, action):
        self.close_window()

    def close_window(self):
        # properly saving window state and position
        maximized = self.window.get_window().get_state(
        ) & gtk.gdk.WINDOW_STATE_MAXIMIZED
        conf.set("overview_window_maximized", maximized)

        # make sure to remember dimensions only when in normal state
        if maximized == False and not self.window.get_window().get_state(
        ) & gtk.gdk.WINDOW_STATE_ICONIFIED:
            x, y = self.window.get_position()
            w, h = self.window.get_size()
            conf.set("overview_window_box", [x, y, w, h])

        if not self.parent:
            gtk.main_quit()
        else:
            self.window.destroy()
            return False

    def show(self):
        self.window.show()