[hamster-applet] due to whole overhaul have to rethink totals. dropping stacked bar and the tree for now.



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 &#x2013; 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 (&#215;%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]