[hamster-applet] due to whole overhaul have to rethink totals. dropping stacked bar and the tree for now.
- From: Toms Baugis <tbaugis src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [hamster-applet] due to whole overhaul have to rethink totals. dropping stacked bar and the tree for now.
- Date: Sun, 27 Dec 2009 21:17:26 +0000 (UTC)
commit 9b717364e7f574959a797ac9b00f749411d0b451
Author: Toms Bauģis <toms baugis gmail com>
Date: Sun Dec 27 21:04:33 2009 +0000
due to whole overhaul have to rethink totals. dropping stacked bar and the tree for now.
data/stats_reports.ui | 227 ++++++++++---------------
hamster/stats.py | 47 ++++-
hamster/stats_reports.py | 423 ++++++++--------------------------------------
3 files changed, 201 insertions(+), 496 deletions(-)
---
diff --git a/data/stats_reports.ui b/data/stats_reports.ui
index 4bfa1b1..51f7db0 100644
--- a/data/stats_reports.ui
+++ b/data/stats_reports.ui
@@ -4,127 +4,148 @@
<!-- interface-naming-policy project-wide -->
<object class="GtkWindow" id="reports_window">
<child>
- <object class="GtkVBox" id="reports_box">
+ <object class="GtkVBox" id="reports_vbox">
<property name="visible">True</property>
<property name="border_width">12</property>
<property name="orientation">vertical</property>
<property name="spacing">6</property>
<child>
- <object class="GtkHPaned" id="hpaned1">
+ <object class="GtkScrolledWindow" id="scrolledwindow1">
<property name="visible">True</property>
<property name="can_focus">True</property>
- <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
- <property name="position">400</property>
- <property name="position_set">True</property>
+ <property name="hscrollbar_policy">never</property>
+ <property name="vscrollbar_policy">automatic</property>
<child>
- <object class="GtkScrolledWindow" id="totals_tree_box">
+ <object class="GtkViewport" id="viewport1">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
- <property name="hscrollbar_policy">never</property>
- <property name="vscrollbar_policy">automatic</property>
- <property name="shadow_type">in</property>
+ <property name="resize_mode">queue</property>
<child>
- <placeholder/>
- </child>
- </object>
- <packing>
- <property name="resize">False</property>
- <property name="shrink">True</property>
- </packing>
- </child>
- <child>
- <object class="GtkFrame" id="frame1">
- <property name="visible">True</property>
- <property name="label_xalign">0</property>
- <child>
- <object class="GtkEventBox" id="graph_frame">
+ <object class="GtkEventBox" id="reports_box">
<property name="visible">True</property>
- <signal name="size_allocate" handler="on_graph_frame_size_allocate"/>
+ <signal name="expose_event" handler="on_reports_box_expose_event"/>
<child>
- <object class="GtkVBox" id="vbox4">
+ <object class="GtkVBox" id="vbox1">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<child>
- <object class="GtkVBox" id="graphs">
+ <object class="GtkHBox" id="charts">
<property name="visible">True</property>
- <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
- <property name="border_width">4</property>
- <property name="orientation">vertical</property>
- <property name="spacing">24</property>
- <property name="homogeneous">True</property>
+ <property name="border_width">12</property>
+ <property name="spacing">12</property>
<child>
- <object class="GtkFrame" id="fram1">
+ <object class="GtkVBox" id="vbox2">
<property name="visible">True</property>
- <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
- <property name="label_xalign">0</property>
- <property name="shadow_type">none</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
<child>
- <object class="GtkHBox" id="week_box">
+ <object class="GtkFrame" id="frame1">
<property name="visible">True</property>
- <property name="border_width">9</property>
- <property name="spacing">36</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
<child>
- <object class="GtkEventBox" id="totals_by_category">
+ <object class="GtkAlignment" id="alignment1">
<property name="visible">True</property>
+ <property name="top_padding">8</property>
+ <property name="left_padding">12</property>
<child>
- <placeholder/>
+ <object class="GtkAlignment" id="totals_by_category">
+ <property name="height_request">10</property>
+ <property name="visible">True</property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
</child>
</object>
- <packing>
- <property name="expand">False</property>
- <property name="position">0</property>
- </packing>
</child>
- <child>
- <object class="GtkEventBox" id="totals_by_day">
+ <child type="label">
+ <object class="GtkLabel" id="label1">
<property name="visible">True</property>
- <child>
- <placeholder/>
- </child>
+ <property name="label" translatable="yes">Categories</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
</object>
- <packing>
- <property name="position">1</property>
- </packing>
</child>
</object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
</child>
- <child type="label">
- <object class="GtkLabel" id="dayview_caption">
+ <child>
+ <object class="GtkFrame" id="frame2">
<property name="visible">True</property>
- <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
- <property name="label" translatable="yes">Week</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <object class="GtkAlignment" id="alignment2">
+ <property name="visible">True</property>
+ <property name="top_padding">8</property>
+ <property name="left_padding">12</property>
+ <child>
+ <object class="GtkAlignment" id="totals_by_activity">
+ <property name="visible">True</property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Activities</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
</object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
</child>
</object>
<packing>
+ <property name="expand">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
- <object class="GtkFrame" id="frame39">
+ <object class="GtkFrame" id="frame3">
<property name="visible">True</property>
- <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
- <object class="GtkEventBox" id="totals_by_activity">
+ <object class="GtkAlignment" id="alignment3">
<property name="visible">True</property>
- <property name="border_width">12</property>
+ <property name="top_padding">8</property>
+ <property name="left_padding">12</property>
<child>
- <placeholder/>
+ <object class="GtkAlignment" id="totals_by_tag">
+ <property name="visible">True</property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
</child>
</object>
</child>
<child type="label">
- <object class="GtkLabel" id="label5">
+ <object class="GtkLabel" id="label3">
<property name="visible">True</property>
- <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
- <property name="label" translatable="yes">Activity</property>
+ <property name="label" translatable="yes">Tags</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
</object>
</child>
</object>
<packing>
+ <property name="expand">False</property>
<property name="position">1</property>
</packing>
</child>
@@ -135,8 +156,13 @@
</child>
<child>
<object class="GtkLabel" id="no_data_label">
- <property name="no_show_all">True</property>
+ <property name="visible">True</property>
<property name="label" translatable="yes">No data for this interval</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ <attribute name="size" value="20000"/>
+ <attribute name="foreground" value="#d6b5d6b5d6b5"/>
+ </attributes>
</object>
<packing>
<property name="position">1</property>
@@ -146,81 +172,14 @@
</child>
</object>
</child>
- <child type="label_item">
- <placeholder/>
- </child>
- </object>
- <packing>
- <property name="resize">True</property>
- <property name="shrink">True</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="position">400</property>
- </packing>
- </child>
- </object>
- </child>
- </object>
- <object class="GtkFileChooserDialog" id="save_report_dialog">
- <property name="border_width">5</property>
- <property name="title" translatable="yes">Save report – Time Tracker</property>
- <property name="window_position">center</property>
- <property name="type_hint">normal</property>
- <property name="has_separator">False</property>
- <child internal-child="vbox">
- <object class="GtkVBox" id="dialog-vbox1">
- <property name="visible">True</property>
- <property name="orientation">vertical</property>
- <property name="spacing">2</property>
- <child>
- <placeholder/>
- </child>
- <child internal-child="action_area">
- <object class="GtkHButtonBox" id="dialog-action_area1">
- <property name="visible">True</property>
- <property name="layout_style">end</property>
- <child>
- <object class="GtkButton" id="cancel_button">
- <property name="label">gtk-cancel</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <property name="use_stock">True</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkButton" id="save_button">
- <property name="label">gtk-save</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <property name="use_stock">True</property>
</object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">1</property>
- </packing>
</child>
</object>
<packing>
- <property name="expand">False</property>
- <property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
</object>
</child>
- <action-widgets>
- <action-widget response="0">cancel_button</action-widget>
- <action-widget response="0">save_button</action-widget>
- </action-widgets>
</object>
</interface>
diff --git a/hamster/stats.py b/hamster/stats.py
index 76b2109..28fcede 100644
--- a/hamster/stats.py
+++ b/hamster/stats.py
@@ -24,13 +24,14 @@ pygtk.require('2.0')
import os
import datetime as dt
import calendar
+import webbrowser
import gtk, gobject
import pango
import stuff
from hamster.i18n import C_
-from configuration import runtime
+from configuration import runtime, colors
class StatsViewer(object):
def __init__(self, parent = None):
@@ -41,6 +42,9 @@ class StatsViewer(object):
self.parent = parent# determine if app should shut down on close
self._gui = stuff.load_ui_file("stats.ui")
+ self.report_chooser = None
+
+ self.facts = None
self.window = self.get_widget("tabs_window")
@@ -113,7 +117,6 @@ class StatsViewer(object):
return True
def after_activity_update(self, widget, renames):
- print widget, renames
self.search()
def search(self):
@@ -124,25 +127,49 @@ class StatsViewer(object):
self.end_date_input.set_date(self.end_date)
search_terms = self.get_widget("search").get_text().decode("utf8", "replace")
- facts = runtime.storage.get_facts(self.start_date, self.end_date, search_terms)
+ self.facts = runtime.storage.get_facts(self.start_date, self.end_date, search_terms)
- self.get_widget("report_button").set_sensitive(len(facts) > 0)
+ self.get_widget("report_button").set_sensitive(len(self.facts) > 0)
- self.timeline.draw(facts, self.start_date, self.end_date)
+ self.timeline.draw(self.facts, 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, facts)
- self.reports.search(self.start_date, self.end_date, facts)
+ 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, facts)
- self.overview.search(self.start_date, self.end_date, facts)
+ self.reports.search(self.start_date, self.end_date, self.facts)
+ self.overview.search(self.start_date, self.end_date, self.facts)
def on_search_activate(self, widget):
self.search()
def on_report_button_clicked(self, widget):
- self.reports.on_report_button_clicked(widget) #forward for now
+ import widgets # TODO - should fix the import thing that was caused by using runtime.dialogs
+ import reports
+
+ 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:
+ gtk.show_uri(gtk.gdk.Screen(),
+ "file://%s" % os.path.split(path)[0], 0L)
+
+ 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 on_range_combo_changed(self, combo):
diff --git a/hamster/stats_reports.py b/hamster/stats_reports.py
index 94cb483..c1b7598 100644
--- a/hamster/stats_reports.py
+++ b/hamster/stats_reports.py
@@ -42,53 +42,39 @@ class ReportsBox(gtk.VBox):
def __init__(self):
gtk.VBox.__init__(self)
self._gui = stuff.load_ui_file("stats_reports.ui")
- self.get_widget("reports_box").reparent(self) #mine!
+ self.get_widget("reports_vbox").reparent(self) #mine!
self.start_date, self.end_date = None, None
-
- self.totals_tree = TotalsTree()
- self.get_widget("totals_tree_box").add(self.totals_tree)
-
-
+
#graphs
self.background = (0.975, 0.975, 0.975)
- self.get_widget("graph_frame").modify_bg(gtk.STATE_NORMAL,
+ self.get_widget("reports_box").modify_bg(gtk.STATE_NORMAL,
gtk.gdk.Color(*[int(b*65536.0) for b in self.background]))
+ x_offset = 100 # align all graphs to the left edge
- x_offset = 90 # align all graphs to the left edge
-
- self.category_chart = charting.BarChart(background = self.background,
- bar_base_color = (238,221,221),
- legend_width = x_offset,
- max_bar_width = 35,
- show_stack_labels = True
- )
- self.get_widget("totals_by_category").add(self.category_chart)
-
- self.day_chart = charting.BarChart(background = self.background,
- bar_base_color = (220, 220, 220),
- show_scale = True,
- max_bar_width = 35,
- grid_stride = 4,
- legend_width = 20)
- self.get_widget("totals_by_day").add(self.day_chart)
-
-
- self.activity_chart = charting.HorizontalBarChart(orient = "horizontal",
- max_bar_width = 25,
- values_on_bars = True,
- stretch_grid = True,
- legend_width = x_offset,
- value_format = "%.1f",
- background = self.background,
- bars_beveled = False,
- animate = False)
+ self.category_chart = charting.HorizontalBarChart(background = self.background,
+ max_bar_width = 20,
+ legend_width = x_offset,
+ value_format = "%.1f",
+ animate = False)
+ self.get_widget("totals_by_category").add(self.category_chart);
+
+ self.activity_chart = charting.HorizontalBarChart(background = self.background,
+ max_bar_width = 20,
+ legend_width = x_offset,
+ value_format = "%.1f",
+ animate = False)
self.get_widget("totals_by_activity").add(self.activity_chart);
- # TODO - this looks expensive. cache it in db!
- self.popular_categories = [cat[0] for cat in runtime.storage.get_popular_categories()]
+ self.tag_chart = charting.HorizontalBarChart(background = self.background,
+ max_bar_width = 20,
+ legend_width = x_offset,
+ value_format = "%.1f",
+ animate = False)
+ self.get_widget("totals_by_tag").add(self.tag_chart);
+
self._gui.connect_signals(self)
@@ -97,6 +83,8 @@ class ReportsBox(gtk.VBox):
self.report_chooser = None
+ def on_reports_box_expose_event(self, box, someth):
+ self.do_charts()
def search(self, start_date, end_date, facts):
self.facts = facts
@@ -105,336 +93,67 @@ class ReportsBox(gtk.VBox):
self.do_graph()
def do_graph(self):
- self.fill_totals_tree()
-
- if not self.facts:
- self.get_widget("graphs").hide()
+ if self.facts:
+ self.get_widget("no_data_label").hide()
+ self.get_widget("charts").show()
+ self.do_charts()
+ else:
self.get_widget("no_data_label").show()
- return
-
- self.get_widget("no_data_label").hide()
- self.get_widget("graphs").show()
- self.do_charts(self.facts)
-
-
- def fill_totals_tree(self):
- #first group by category, activity and tags
- #sort before grouping
- facts = sorted(self.facts, key = lambda fact:(fact["category"], fact["name"], fact["tags"]))
-
- totals = []
- for group, facts in groupby(facts, lambda fact:(fact["category"], fact["name"], fact["tags"])):
- facts = list(facts)
- total_duration = dt.timedelta()
- for fact in facts:
- total_duration += fact["delta"]
-
- group = list(group)
- group.extend([total_duration, len(facts)])
- totals.append(group)
-
- self.totals_tree.clear()
-
- # second iteration - group the interim result by category
- i = 0
- for category, totals in groupby(totals, lambda total:total[0]):
- i+=1
- totals = list(totals)
+ self.get_widget("charts").hide()
- category_duration = sum([stuff.duration_minutes(total[3]) for total in totals])
- category_occurences = sum([total[4] for total in totals])
-
-
- # adds group of facts with the given label
- category_row = self.totals_tree.model.append(None,
- [category,
- None,
- stuff.format_duration(category_duration),
- str(category_occurences)])
-
- #now group by activity too
- for group, totals in groupby(totals, lambda total:(total[0], total[1])):
- totals = list(totals)
-
- if len(totals) > 1:
- activity_duration = sum([stuff.duration_minutes(total[3]) for total in totals])
- activity_occurences = sum([total[4] for total in totals])
-
-
- # adds group of facts with the given label
- activity_row = self.totals_tree.model.append(category_row,
- [group[1],
- None,
- stuff.format_duration(activity_duration),
- str(activity_occurences)])
-
- for total in totals:
- self.totals_tree.add_total(total, activity_row)
- else:
- self.totals_tree.add_total(totals[0], category_row)
-
- self.totals_tree.expand_row((i-1,), False)
-
-
- def do_charts(self, facts):
- all_categories = self.popular_categories
-
-
- #the single "totals" (by category) bar
- category_sums = stuff.totals(facts, lambda fact: fact["category"],
- lambda fact: stuff.duration_minutes(fact["delta"]) / 60.0)
- category_totals = [category_sums.get(cat, 0) for cat in all_categories]
- category_keys = ["%s %.1f" % (cat, category_sums.get(cat, 0.0))
- for cat in all_categories]
- self.category_chart.plot([_("Total")],
- [category_totals],
- stack_keys = category_keys)
-
- # day / category chart
- all_days = [self.start_date + dt.timedelta(i)
- for i in range((self.end_date - self.start_date).days + 1)]
+ def do_charts(self):
+ if not self.facts:
+ return
- by_date_cat = stuff.totals(facts,
- lambda fact: (fact["date"], fact["category"]),
- lambda fact: stuff.duration_minutes(fact["delta"]) / 60.0)
-
- res = [[by_date_cat.get((day, cat), 0)
- for cat in all_categories] for day in all_days]
-
-
- #show days or dates depending on scale
- if (self.end_date - self.start_date).days < 20:
- day_keys = [day.strftime("%a") for day in all_days]
+ #totals by category
+ category_sums = stuff.totals(self.facts,
+ lambda fact: (fact["category"]),
+ lambda fact: stuff.duration_minutes(fact["delta"]) / 60.0)
+ if category_sums:
+ category_sums = sorted(category_sums.items(), key=lambda x:x[1], reverse = True)
+ keys, values = zip(*category_sums)
+ self.get_widget("totals_by_category").set_size_request(280, len(keys) * 20)
+ self.category_chart.plot(keys, values)
else:
- # date format used in the overview graph when month view is selected
- # Using python datetime formatting syntax. See:
- # http://docs.python.org/library/time.html#time.strftime
- day_keys = [day.strftime(C_("overview graph", "%b %d"))
- for day in all_days]
-
- self.day_chart.plot(day_keys, res, stack_keys = all_categories)
-
-
- #totals by activity, disguised under a stacked bar chart to get category colors
- activity_sums = stuff.totals(facts,
- lambda fact: (fact["name"],
- fact["category"]),
- lambda fact: stuff.duration_minutes(fact["delta"]))
-
- #now join activities with same name
- activities = {}
- for key in activity_sums.keys():
- activities.setdefault(key[0], [0.0] * len(all_categories))
- activities[key[0]][all_categories.index(key[1])] = activity_sums[key] / 60.0
-
- by_duration = sorted(activities.items(),
- key = lambda x: sum(x[1]),
- reverse = True)
- by_duration_keys = [entry[0] for entry in by_duration]
-
- by_duration = [entry[1] for entry in by_duration]
-
- self.activity_chart.plot(by_duration_keys,
- by_duration,
- stack_keys = all_categories)
-
-
- def on_graph_frame_size_allocate(self, widget, new_size):
- w = min(new_size.width / 4, 200)
+ self.category_chart.plot([], [])
+
+
+ #totals by activity
+ activity_sums = stuff.totals(self.facts,
+ lambda fact: (fact["name"]),
+ lambda fact: stuff.duration_minutes(fact["delta"]) / 60.0)
+ activity_sums = sorted(activity_sums.items(), key=lambda x:x[1], reverse = True)
+ keys, values = zip(*activity_sums)
+ self.get_widget("totals_by_activity").set_size_request(10,10)
+ self.get_widget("totals_by_activity").set_size_request(280, len(keys) * 20)
+ self.activity_chart.plot(keys, values)
+
+
+ tag_sums = {}
+ for fact in self.facts:
+ for tag in fact["tags"]:
+ tag_sums.setdefault(tag, 0)
+ tag_sums[tag] += stuff.duration_minutes(fact["delta"]) / 60.0
+
+ if tag_sums:
+ tag_sums = sorted(tag_sums.items(), key=lambda x:x[1], reverse = True)
+ keys, values = zip(*tag_sums)
+ self.get_widget("totals_by_tag").set_size_request(10,10)
+ self.get_widget("totals_by_tag").set_size_request(280, len(keys) * 20)
+ self.tag_chart.plot(keys, values)
+ else:
+ self.tag_chart.plot([], [])
- self.activity_chart.legend_width = w
- self.category_chart.legend_width = w
- self.get_widget("totals_by_category").set_size_request(w + 40, -1)
-
-
def get_widget(self, name):
""" skip one variable (huh) """
return self._gui.get_object(name)
- def init_report_dialog(self):
- chooser = self.get_widget('save_report_dialog')
- chooser.set_action(gtk.FILE_CHOOSER_ACTION_SAVE)
- """
- chooser.set
-
- chooser = gtk.FileChooserDialog(title = _("Save report - Time Tracker"),
- parent = None,
- buttons=(gtk.STOCK_CANCEL,
- gtk.RESPONSE_CANCEL,
- gtk.STOCK_SAVE,
- gtk.RESPONSE_OK))
- """
- chooser.set_current_folder(os.path.expanduser("~"))
-
- filters = {}
-
- filter = gtk.FileFilter()
- filter.set_name(_("HTML Report"))
- filter.add_mime_type("text/html")
- filter.add_pattern("*.html")
- filter.add_pattern("*.htm")
- filters[filter] = "html"
- chooser.add_filter(filter)
-
- filter = gtk.FileFilter()
- filter.set_name(_("Tab-Separated Values (TSV)"))
- filter.add_mime_type("text/plain")
- filter.add_pattern("*.tsv")
- filter.add_pattern("*.txt")
- filters[filter] = "tsv"
- chooser.add_filter(filter)
-
- filter = gtk.FileFilter()
- filter.set_name(_("XML"))
- filter.add_mime_type("text/xml")
- filter.add_pattern("*.xml")
- filters[filter] = "xml"
- chooser.add_filter(filter)
-
- filter = gtk.FileFilter()
- filter.set_name(_("iCal"))
- filter.add_mime_type("text/calendar")
- filter.add_pattern("*.ics")
- filters[filter] = "ical"
- chooser.add_filter(filter)
-
- filter = gtk.FileFilter()
- filter.set_name("All files")
- filter.add_pattern("*")
- chooser.add_filter(filter)
-
- def on_report_chosen(self, 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:
- gtk.show_uri(gtk.gdk.Screen(),
- "file://%s" % os.path.split(path)[0], 0L)
-
- def on_report_chooser_closed(self, widget):
- self.report_chooser = None
-
- def on_report_button_clicked(self, widget):
- if not self.report_chooser:
- self.report_chooser = widgets.ReportChooserDialog()
- self.report_chooser.connect("report-chosen", self.on_report_chosen)
- self.report_chooser.connect("report-chooser-closed",
- self.on_report_chooser_closed)
- self.report_chooser.show(self.start_date, self.end_date)
- else:
- self.report_chooser.present()
-
-
def on_day_start_changed(self, event, new_minutes):
self.do_graph()
-class TotalsTree(gtk.TreeView):
- def __init__(self):
- gtk.TreeView.__init__(self)
-
- self.set_headers_visible(False)
- self.set_show_expanders(True)
-
- # group name / activity name, tags, duration, occurences
- self.set_model(gtk.TreeStore(str, gobject.TYPE_PYOBJECT, str, str))
-
- # name
- nameColumn = gtk.TreeViewColumn()
- nameCell = gtk.CellRendererText()
- nameColumn.pack_start(nameCell, True)
- nameColumn.set_cell_data_func(nameCell, self.parent_painter)
- self.append_column(nameColumn)
-
- tag_cell = widgets.TagCellRenderer()
- tag_cell.set_font_size(8);
- tagColumn = gtk.TreeViewColumn("", tag_cell, data=1)
- tagColumn.set_expand(True)
-
- self.append_column(tagColumn)
-
- # duration
- timeColumn = gtk.TreeViewColumn()
- timeCell = gtk.CellRendererText()
- timeColumn.pack_end(timeCell, True)
- timeColumn.set_cell_data_func(timeCell, self.duration_painter)
- self.append_column(timeColumn)
-
-
- self.show()
-
- def clear(self):
- self.model.clear()
-
- @property
- def model(self):
- return self.get_model()
-
- def add_total(self, total, parent = None):
- duration = stuff.duration_minutes(total[3])
-
-
- self.model.append(parent, [total[1],
- total[2],
- stuff.format_duration(duration),
- str(total[4])])
-
- def add_group(self, group_label, totals):
- total_duration = sum([stuff.duration_minutes(total[3]) for total in totals])
- total_occurences = sum([total[4] for total in totals])
-
-
- # adds group of facts with the given label
- group_row = self.model.append(None,
- [group_label,
- None,
- stuff.format_duration(total_duration),
- str(total_occurences)])
-
- for total in totals:
- self.add_total(total, group_row)
-
- self.expand_all()
-
- @staticmethod
- def parent_painter(column, cell, model, iter):
- if not model.get_value(iter, 3):
- return
-
- count = int(model.get_value(iter, 3))
-
- if count > 1:
- cell_text = "%s (×%s)" % (stuff.escape_pango(model.get_value(iter, 0)), count)
- else:
- cell_text = "%s" % stuff.escape_pango(model.get_value(iter, 0))
-
-
- if model.iter_parent(iter) is None:
- if model.get_path(iter) == (0,):
- text = '<span weight="heavy">%s</span>' % cell_text
- else:
- text = '<span weight="heavy" rise="-20000">%s</span>' % cell_text
-
- cell.set_property('markup', text)
-
- else:
- cell.set_property('markup', cell_text)
-
- @staticmethod
- def duration_painter(column, cell, model, iter):
- cell.set_property('xalign', 1)
- text = model.get_value(iter, 2)
- if model.iter_parent(iter) is None:
- if model.get_path(iter) == (0,):
- text = '<span weight="heavy">%s</span>' % text
- else:
- text = '<span weight="heavy" rise="-20000">%s</span>' % text
- cell.set_property('markup', text)
-
if __name__ == "__main__":
gtk.window_set_default_icon_name("hamster-applet")
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]