[hamster-applet] as the code has grown, split overview into three files matching the tabs to be able to manage it som



commit 4b278970ed97f2391021e13c2560b1909b2502d3
Author: Toms Bauģis <toms baugis gmail com>
Date:   Sat Dec 5 19:23:19 2009 +0000

    as the code has grown, split overview into three files matching the tabs to be able to manage it somehow

 data/Makefile.am            |    3 +
 data/stats.ui               |  784 ++++-----------------------------
 data/stats_overview.ui      |  236 ++++++++++
 data/stats_reports.ui       |  335 ++++++++++++++
 data/stats_stats.ui         |  273 ++++++++++++
 hamster/Makefile.am         |    9 +-
 hamster/stats.py            | 1025 +------------------------------------------
 hamster/stats_overview.py   |  204 +++++++++
 hamster/stats_reports.py    |  612 ++++++++++++++++++++++++++
 hamster/stats_stats.py      |  416 ++++++++++++++++++
 hamster/widgets/facttree.py |  189 ++++++++
 po/POTFILES.in              |    6 +
 12 files changed, 2377 insertions(+), 1715 deletions(-)
---
diff --git a/data/Makefile.am b/data/Makefile.am
index 1a89823..7f941f8 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -23,6 +23,9 @@ resources_DATA = \
 	Hamster_Applet.xml \
 	preferences.ui \
 	stats.ui \
+	stats_overview.ui \
+	stats_reports.ui \
+	stats_stats.ui \
 	edit_activity.ui \
         applet.ui \
 	hamster.db
diff --git a/data/stats.ui b/data/stats.ui
index 097053d..8c8a229 100644
--- a/data/stats.ui
+++ b/data/stats.ui
@@ -1,694 +1,11 @@
 <?xml version="1.0"?>
 <interface>
-  <!-- interface-requires gtk+ 2.12 -->
-  <!-- interface-naming-policy toplevel-contextual -->
+  <requires lib="gtk+" version="2.16"/>
+  <!-- interface-naming-policy project-wide -->
   <!-- interface-local-resource-path /home/toms/cvs/hamster/data/art -->
-  <object class="GtkWindow" id="stats_window">
-    <property name="width_request">600</property>
-    <property name="height_request">400</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">12</property>
-    <property name="title" translatable="yes">Overview - Hamster</property>
-    <property name="window_position">center</property>
-    <property name="default_width">800</property>
-    <property name="default_height">600</property>
-    <property name="icon_name">hamster-applet</property>
-    <signal name="key_press_event" handler="on_window_key_pressed"/>
-    <signal name="delete_event" handler="on_close"/>
-    <child>
-      <object class="GtkNotebook" id="pages">
-        <property name="visible">True</property>
-        <property name="can_focus">True</property>
-        <property name="tab_hborder">8</property>
-        <property name="tab_vborder">4</property>
-        <signal name="switch_page" handler="on_pages_switch_page"/>
-        <child>
-          <object class="GtkVBox" id="vbox1">
-            <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="orientation">vertical</property>
-            <child>
-              <object class="GtkToolbar" id="toolbar3">
-                <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>
-                <child>
-                  <object class="GtkToolButton" id="prev">
-                    <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="tooltip_text" translatable="yes">Previous week</property>
-                    <property name="label" translatable="yes">Previous</property>
-                    <property name="stock_id">gtk-go-back</property>
-                    <signal name="clicked" handler="on_prev_clicked"/>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="homogeneous">True</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkToolButton" id="home">
-                    <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="tooltip_text" translatable="yes">This week</property>
-                    <property name="label" translatable="yes">This Week</property>
-                    <property name="use_underline">True</property>
-                    <property name="stock_id">gtk-home</property>
-                    <signal name="clicked" handler="on_home_clicked"/>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="homogeneous">True</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkToolButton" id="next">
-                    <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="tooltip_text" translatable="yes">Next week</property>
-                    <property name="label" translatable="yes">Next</property>
-                    <property name="stock_id">gtk-go-forward</property>
-                    <signal name="clicked" handler="on_next_clicked"/>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="homogeneous">True</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkSeparatorToolItem" id="toolbutton3">
-                    <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>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkToolButton" id="add">
-                    <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="tooltip_text" translatable="yes">Add activity</property>
-                    <property name="label" translatable="yes">Add</property>
-                    <property name="stock_id">gtk-add</property>
-                    <signal name="clicked" handler="on_add_clicked"/>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="homogeneous">True</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkToolButton" id="remove">
-                    <property name="visible">True</property>
-                    <property name="sensitive">False</property>
-                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                    <property name="tooltip_text" translatable="yes">Remove activity</property>
-                    <property name="label" translatable="yes">Remove</property>
-                    <property name="stock_id">gtk-remove</property>
-                    <signal name="clicked" handler="on_remove_clicked"/>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="homogeneous">True</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkToolButton" id="edit">
-                    <property name="visible">True</property>
-                    <property name="sensitive">False</property>
-                    <property name="tooltip_text" translatable="yes">Edit activity</property>
-                    <property name="label" translatable="yes">Edit</property>
-                    <property name="stock_id">gtk-edit</property>
-                    <signal name="clicked" handler="on_edit_clicked"/>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="homogeneous">True</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkSeparatorToolItem" id="toolbutton1">
-                    <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>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkRadioToolButton" id="day">
-                    <property name="visible">True</property>
-                    <property name="tooltip_text" translatable="yes">Show single day</property>
-                    <property name="is_important">True</property>
-                    <property name="label" translatable="yes"> _Day</property>
-                    <property name="use_underline">True</property>
-                    <property name="icon_widget">day_icon</property>
-                    <property name="active">True</property>
-                    <signal name="toggled" handler="on_day_toggled"/>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="homogeneous">True</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkRadioToolButton" id="week">
-                    <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="tooltip_text" translatable="yes">Show week</property>
-                    <property name="is_important">True</property>
-                    <property name="label" translatable="yes"> _Week</property>
-                    <property name="use_underline">True</property>
-                    <property name="icon_widget">week_icon</property>
-                    <property name="active">True</property>
-                    <signal name="toggled" handler="on_week_toggled"/>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="homogeneous">True</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkRadioToolButton" id="month">
-                    <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="tooltip_text" translatable="yes">Show month</property>
-                    <property name="is_important">True</property>
-                    <property name="label" translatable="yes"> _Month</property>
-                    <property name="use_underline">True</property>
-                    <property name="icon_widget">month_icon</property>
-                    <property name="active">True</property>
-                    <signal name="toggled" handler="on_month_toggled"/>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="homogeneous">True</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkSeparatorToolItem" id="&lt;separator&gt;">
-                    <property name="visible">True</property>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="homogeneous">True</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkToolButton" id="report_button">
-                    <property name="visible">True</property>
-                    <property name="tooltip_text" translatable="yes">Save report</property>
-                    <property name="is_important">True</property>
-                    <property name="label" translatable="yes">Save Report</property>
-                    <property name="use_underline">True</property>
-                    <property name="stock_id">gtk-save</property>
-                    <signal name="clicked" handler="on_report_button_clicked"/>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="homogeneous">True</property>
-                  </packing>
-                </child>
-              </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="position">0</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkVBox" id="vbox6">
-                <property name="visible">True</property>
-                <property name="border_width">12</property>
-                <property name="orientation">vertical</property>
-                <property name="spacing">6</property>
-                <child>
-                  <object class="GtkLabel" id="overview_label">
-                    <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="xalign">0</property>
-                    <property name="label" translatable="yes">&lt;b&gt;Overview&lt;/b&gt;</property>
-                    <property name="use_markup">True</property>
-                    <property name="single_line_mode">True</property>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="position">0</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkHPaned" id="hpaned1">
-                    <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">300</property>
-                    <property name="position_set">True</property>
-                    <child>
-                      <object class="GtkScrolledWindow" id="scrolledwindow1">
-                        <property name="width_request">300</property>
-                        <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">automatic</property>
-                        <property name="vscrollbar_policy">automatic</property>
-                        <property name="shadow_type">in</property>
-                        <child>
-                          <object class="GtkTreeView" id="facts">
-                            <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="enable_search">False</property>
-                            <signal name="key_press_event" handler="on_key_pressed"/>
-                            <signal name="row_activated" handler="on_facts_row_activated"/>
-                          </object>
-                        </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">
-                            <property name="visible">True</property>
-                            <signal name="size_allocate" handler="on_graph_frame_size_allocate"/>
-                            <child>
-                              <object class="GtkVBox" id="vbox4">
-                                <property name="visible">True</property>
-                                <property name="orientation">vertical</property>
-                                <child>
-                                  <object class="GtkVBox" id="graphs">
-                                    <property name="width_request">390</property>
-                                    <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>
-                                    <child>
-                                      <object class="GtkFrame" id="fram1">
-                                        <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="GtkHBox" id="week_box">
-                                            <property name="visible">True</property>
-                                            <property name="border_width">9</property>
-                                            <property name="spacing">36</property>
-                                            <child>
-                                              <object class="GtkEventBox" id="totals_by_category">
-                                                <property name="visible">True</property>
-                                                <child>
-                                                  <placeholder/>
-                                                </child>
-                                              </object>
-                                              <packing>
-                                                <property name="expand">False</property>
-                                                <property name="position">0</property>
-                                              </packing>
-                                            </child>
-                                            <child>
-                                              <object class="GtkEventBox" id="totals_by_day">
-                                                <property name="visible">True</property>
-                                                <child>
-                                                  <placeholder/>
-                                                </child>
-                                              </object>
-                                              <packing>
-                                                <property name="position">1</property>
-                                              </packing>
-                                            </child>
-                                          </object>
-                                        </child>
-                                        <child type="label">
-                                          <object class="GtkLabel" id="dayview_caption">
-                                            <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="use_markup">True</property>
-                                          </object>
-                                        </child>
-                                      </object>
-                                      <packing>
-                                        <property name="position">0</property>
-                                      </packing>
-                                    </child>
-                                    <child>
-                                      <object class="GtkFrame" id="frame39">
-                                        <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">
-                                            <property name="visible">True</property>
-                                            <property name="border_width">12</property>
-                                            <child>
-                                              <placeholder/>
-                                            </child>
-                                          </object>
-                                        </child>
-                                        <child type="label">
-                                          <object class="GtkLabel" id="label5">
-                                            <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="use_markup">True</property>
-                                          </object>
-                                        </child>
-                                      </object>
-                                      <packing>
-                                        <property name="position">1</property>
-                                      </packing>
-                                    </child>
-                                  </object>
-                                  <packing>
-                                    <property name="position">0</property>
-                                  </packing>
-                                </child>
-                                <child>
-                                  <object class="GtkLabel" id="no_data_label">
-                                    <property name="label" translatable="yes">No data for this interval</property>
-                                  </object>
-                                  <packing>
-                                    <property name="position">1</property>
-                                  </packing>
-                                </child>
-                              </object>
-                            </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">1</property>
-                  </packing>
-                </child>
-              </object>
-              <packing>
-                <property name="position">1</property>
-              </packing>
-            </child>
-          </object>
-        </child>
-        <child type="tab">
-          <object class="GtkLabel" id="overview_labe">
-            <property name="visible">True</property>
-            <property name="label" translatable="yes">Overview</property>
-          </object>
-          <packing>
-            <property name="tab_fill">False</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkVBox" id="vbox2">
-            <property name="visible">True</property>
-            <property name="border_width">12</property>
-            <property name="orientation">vertical</property>
-            <property name="spacing">12</property>
-            <child>
-              <object class="GtkAlignment" id="alignment4">
-                <property name="visible">True</property>
-                <property name="yscale">0</property>
-                <child>
-                  <object class="GtkTable" id="explore_controls">
-                    <property name="visible">True</property>
-                    <property name="n_columns">2</property>
-                    <property name="column_spacing">12</property>
-                    <property name="row_spacing">6</property>
-                    <child>
-                      <object class="GtkLabel" id="label3">
-                        <property name="visible">True</property>
-                        <property name="xalign">0</property>
-                        <property name="label" translatable="yes">Year:</property>
-                      </object>
-                      <packing>
-                        <property name="x_options">GTK_FILL</property>
-                        <property name="y_options">GTK_FILL</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkAlignment" id="alignment5">
-                        <property name="visible">True</property>
-                        <property name="xalign">0</property>
-                        <property name="xscale">0</property>
-                        <child>
-                          <object class="GtkHBox" id="year_box">
-                            <property name="visible">True</property>
-                            <child>
-                              <placeholder/>
-                            </child>
-                            <child>
-                              <placeholder/>
-                            </child>
-                            <child>
-                              <placeholder/>
-                            </child>
-                          </object>
-                        </child>
-                      </object>
-                      <packing>
-                        <property name="left_attach">1</property>
-                        <property name="right_attach">2</property>
-                      </packing>
-                    </child>
-                  </object>
-                </child>
-              </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="position">0</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkFrame" id="frame2">
-                <property name="visible">True</property>
-                <property name="label_xalign">0</property>
-                <child>
-                  <object class="GtkEventBox" id="explore_frame">
-                    <property name="visible">True</property>
-                    <child>
-                      <object class="GtkAlignment" id="alignment7">
-                        <property name="visible">True</property>
-                        <property name="top_padding">12</property>
-                        <property name="bottom_padding">12</property>
-                        <property name="left_padding">12</property>
-                        <property name="right_padding">12</property>
-                        <child>
-                          <object class="GtkVBox" id="vbox3">
-                            <property name="visible">True</property>
-                            <property name="orientation">vertical</property>
-                            <child>
-                              <object class="GtkVBox" id="statistics_box">
-                                <property name="visible">True</property>
-                                <property name="orientation">vertical</property>
-                                <property name="spacing">12</property>
-                                <child>
-                                  <object class="GtkAlignment" id="explore_everything">
-                                    <property name="height_request">50</property>
-                                    <property name="visible">True</property>
-                                    <child>
-                                      <placeholder/>
-                                    </child>
-                                  </object>
-                                  <packing>
-                                    <property name="expand">False</property>
-                                    <property name="position">0</property>
-                                  </packing>
-                                </child>
-                                <child>
-                                  <object class="GtkHBox" id="vbox77">
-                                    <property name="visible">True</property>
-                                    <child>
-                                      <object class="GtkVBox" id="vbox5">
-                                        <property name="visible">True</property>
-                                        <property name="orientation">vertical</property>
-                                        <child>
-                                          <object class="GtkHBox" id="hbox2">
-                                            <property name="visible">True</property>
-                                            <property name="homogeneous">True</property>
-                                            <child>
-                                              <object class="GtkLabel" id="label7">
-                                                <property name="visible">True</property>
-                                                <property name="xalign">0</property>
-                                                <property name="ypad">8</property>
-                                                <property name="label" translatable="yes">&lt;b&gt;Starts and ends&lt;/b&gt;</property>
-                                                <property name="use_markup">True</property>
-                                              </object>
-                                              <packing>
-                                                <property name="position">0</property>
-                                              </packing>
-                                            </child>
-                                            <child>
-                                              <object class="GtkLabel" id="label8">
-                                                <property name="visible">True</property>
-                                                <property name="xalign">0</property>
-                                                <property name="label" translatable="yes">&lt;b&gt;Totals&lt;/b&gt;</property>
-                                                <property name="use_markup">True</property>
-                                              </object>
-                                              <packing>
-                                                <property name="position">1</property>
-                                              </packing>
-                                            </child>
-                                          </object>
-                                          <packing>
-                                            <property name="expand">False</property>
-                                            <property name="position">0</property>
-                                          </packing>
-                                        </child>
-                                        <child>
-                                          <object class="GtkHBox" id="hbox3">
-                                            <property name="height_request">160</property>
-                                            <property name="visible">True</property>
-                                            <property name="homogeneous">True</property>
-                                            <child>
-                                              <object class="GtkAlignment" id="explore_weekday_starts_ends">
-                                                <property name="visible">True</property>
-                                                <child>
-                                                  <placeholder/>
-                                                </child>
-                                              </object>
-                                              <packing>
-                                                <property name="position">0</property>
-                                              </packing>
-                                            </child>
-                                            <child>
-                                              <object class="GtkAlignment" id="explore_weekday_totals">
-                                                <property name="visible">True</property>
-                                                <child>
-                                                  <placeholder/>
-                                                </child>
-                                              </object>
-                                              <packing>
-                                                <property name="position">1</property>
-                                              </packing>
-                                            </child>
-                                          </object>
-                                          <packing>
-                                            <property name="expand">False</property>
-                                            <property name="position">1</property>
-                                          </packing>
-                                        </child>
-                                        <child>
-                                          <object class="GtkHBox" id="hbox4">
-                                            <property name="height_request">100</property>
-                                            <property name="visible">True</property>
-                                            <property name="homogeneous">True</property>
-                                            <child>
-                                              <object class="GtkAlignment" id="explore_category_starts_ends">
-                                                <property name="visible">True</property>
-                                                <child>
-                                                  <placeholder/>
-                                                </child>
-                                              </object>
-                                              <packing>
-                                                <property name="position">0</property>
-                                              </packing>
-                                            </child>
-                                            <child>
-                                              <object class="GtkAlignment" id="explore_category_totals">
-                                                <property name="visible">True</property>
-                                                <child>
-                                                  <placeholder/>
-                                                </child>
-                                              </object>
-                                              <packing>
-                                                <property name="position">1</property>
-                                              </packing>
-                                            </child>
-                                          </object>
-                                          <packing>
-                                            <property name="position">2</property>
-                                          </packing>
-                                        </child>
-                                      </object>
-                                      <packing>
-                                        <property name="position">0</property>
-                                      </packing>
-                                    </child>
-                                    <child>
-                                      <object class="GtkAlignment" id="explore_summary">
-                                        <property name="width_request">200</property>
-                                        <property name="visible">True</property>
-                                        <property name="xalign">0</property>
-                                        <property name="yalign">0</property>
-                                        <property name="top_padding">32</property>
-                                        <property name="left_padding">30</property>
-                                        <child>
-                                          <placeholder/>
-                                        </child>
-                                      </object>
-                                      <packing>
-                                        <property name="expand">False</property>
-                                        <property name="position">1</property>
-                                      </packing>
-                                    </child>
-                                  </object>
-                                  <packing>
-                                    <property name="position">1</property>
-                                  </packing>
-                                </child>
-                              </object>
-                              <packing>
-                                <property name="position">0</property>
-                              </packing>
-                            </child>
-                            <child>
-                              <object class="GtkLabel" id="not_enough_records_label">
-                                <property name="label">Text we say when there is not enough data</property>
-                                <property name="wrap">True</property>
-                              </object>
-                              <packing>
-                                <property name="position">1</property>
-                              </packing>
-                            </child>
-                          </object>
-                        </child>
-                      </object>
-                    </child>
-                  </object>
-                </child>
-                <child type="label_item">
-                  <placeholder/>
-                </child>
-              </object>
-              <packing>
-                <property name="position">1</property>
-              </packing>
-            </child>
-          </object>
-          <packing>
-            <property name="position">1</property>
-          </packing>
-        </child>
-        <child type="tab">
-          <object class="GtkLabel" id="statistics_label">
-            <property name="visible">True</property>
-            <property name="label" translatable="yes">Statistics</property>
-          </object>
-          <packing>
-            <property name="position">1</property>
-            <property name="tab_fill">False</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="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>
@@ -698,7 +15,7 @@
         <property name="orientation">vertical</property>
         <property name="spacing">2</property>
         <child>
-          <object class="GtkAlignment" id="alignment3">
+          <object class="GtkAlignment" id="alignment2">
             <property name="visible">True</property>
             <property name="top_padding">8</property>
             <property name="left_padding">8</property>
@@ -721,7 +38,7 @@
                   </packing>
                 </child>
                 <child>
-                  <object class="GtkLabel" id="label1">
+                  <object class="GtkLabel" id="label2">
                     <property name="visible">True</property>
                     <property name="xalign">0</property>
                     <property name="yalign">0</property>
@@ -734,12 +51,12 @@
                   </packing>
                 </child>
                 <child>
-                  <object class="GtkAlignment" id="alignment1">
+                  <object class="GtkAlignment" id="alignment6">
                     <property name="visible">True</property>
                     <property name="xalign">0</property>
                     <property name="xscale">0</property>
                     <child>
-                      <object class="GtkHBox" id="hbox1">
+                      <object class="GtkHBox" id="hbox2">
                         <property name="visible">True</property>
                         <child>
                           <object class="GtkAlignment" id="from_date_box">
@@ -753,7 +70,7 @@
                           </packing>
                         </child>
                         <child>
-                          <object class="GtkLabel" id="label2">
+                          <object class="GtkLabel" id="label11">
                             <property name="visible">True</property>
                             <property name="xpad">6</property>
                             <property name="label" translatable="yes">to</property>
@@ -783,7 +100,7 @@
                   </packing>
                 </child>
                 <child>
-                  <object class="GtkAlignment" id="alignment2">
+                  <object class="GtkAlignment" id="alignment8">
                     <property name="visible">True</property>
                     <property name="xalign">0</property>
                     <property name="xscale">0</property>
@@ -866,17 +183,76 @@
       <action-widget response="0">save_button</action-widget>
     </action-widgets>
   </object>
-  <object class="GtkImage" id="day_icon">
-    <property name="visible">True</property>
-    <property name="pixbuf">art/stock_calendar-view-day.png</property>
-  </object>
-  <object class="GtkImage" id="week_icon">
-    <property name="visible">True</property>
-    <property name="pixbuf">art/stock_calendar-view-week.png</property>
-  </object>
-  <object class="GtkImage" id="month_icon">
-    <property name="visible">True</property>
-    <property name="tooltip_text" translatable="yes">Show month</property>
-    <property name="pixbuf">art/stock_calendar-view-month.png</property>
+  <object class="GtkWindow" id="tabs_window">
+    <property name="border_width">12</property>
+    <property name="title" translatable="yes">Overview - Hamster</property>
+    <child>
+      <object class="GtkNotebook" id="window_tabs">
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="tab_hborder">8</property>
+        <property name="tab_vborder">4</property>
+        <signal name="switch_page" handler="on_window_tabs_switch_page"/>
+        <child>
+          <object class="GtkAlignment" id="overview_tab">
+            <property name="visible">True</property>
+            <child>
+              <placeholder/>
+            </child>
+          </object>
+        </child>
+        <child type="tab">
+          <object class="GtkLabel" id="overview_labe1">
+            <property name="visible">True</property>
+            <property name="label" translatable="yes">Overview</property>
+          </object>
+          <packing>
+            <property name="tab_fill">False</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkAlignment" id="reports_tab">
+            <property name="visible">True</property>
+            <child>
+              <placeholder/>
+            </child>
+          </object>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child type="tab">
+          <object class="GtkLabel" id="statistics_label1">
+            <property name="visible">True</property>
+            <property name="label" translatable="yes">Reports</property>
+          </object>
+          <packing>
+            <property name="position">2</property>
+            <property name="tab_fill">False</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkAlignment" id="stats_tab">
+            <property name="visible">True</property>
+            <child>
+              <placeholder/>
+            </child>
+          </object>
+          <packing>
+            <property name="position">2</property>
+          </packing>
+        </child>
+        <child type="tab">
+          <object class="GtkLabel" id="label17">
+            <property name="visible">True</property>
+            <property name="label" translatable="yes">Statistics</property>
+          </object>
+          <packing>
+            <property name="position">2</property>
+            <property name="tab_fill">False</property>
+          </packing>
+        </child>
+      </object>
+    </child>
   </object>
 </interface>
diff --git a/data/stats_overview.ui b/data/stats_overview.ui
new file mode 100644
index 0000000..72f74d1
--- /dev/null
+++ b/data/stats_overview.ui
@@ -0,0 +1,236 @@
+<?xml version="1.0"?>
+<interface>
+  <requires lib="gtk+" version="2.16"/>
+  <!-- interface-naming-policy project-wide -->
+  <object class="GtkWindow" id="overview_window">
+    <child>
+      <object class="GtkVBox" id="overview_box">
+        <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="orientation">vertical</property>
+        <child>
+          <object class="GtkToolbar" id="toolbar3">
+            <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>
+            <child>
+              <object class="GtkToolButton" id="prev2">
+                <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">Previous</property>
+                <property name="stock_id">gtk-go-back</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="homogeneous">True</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkToolButton" id="home2">
+                <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">This Week</property>
+                <property name="use_underline">True</property>
+                <property name="stock_id">gtk-home</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="homogeneous">True</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkToolButton" id="next2">
+                <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">Next</property>
+                <property name="stock_id">gtk-go-forward</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="homogeneous">True</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkSeparatorToolItem" id="toolbutton1">
+                <property name="visible">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="homogeneous">True</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkToolButton" id="add">
+                <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">Add</property>
+                <property name="stock_id">gtk-add</property>
+                <signal name="clicked" handler="on_add_clicked"/>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="homogeneous">True</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkToolButton" id="remove">
+                <property name="visible">True</property>
+                <property name="sensitive">False</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">Remove</property>
+                <property name="stock_id">gtk-remove</property>
+                <signal name="clicked" handler="on_remove_clicked"/>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="homogeneous">True</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkToolButton" id="edit">
+                <property name="visible">True</property>
+                <property name="sensitive">False</property>
+                <property name="label" translatable="yes">Edit</property>
+                <property name="stock_id">gtk-edit</property>
+                <signal name="clicked" handler="on_edit_clicked"/>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="homogeneous">True</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkHBox" id="hbox1">
+            <property name="visible">True</property>
+            <property name="border_width">12</property>
+            <property name="spacing">4</property>
+            <child>
+              <object class="GtkAlignment" id="alignment1">
+                <property name="width_request">600</property>
+                <property name="visible">True</property>
+                <child>
+                  <object class="GtkScrolledWindow" id="overview_facts_box">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="hscrollbar_policy">never</property>
+                    <property name="vscrollbar_policy">automatic</property>
+                    <property name="shadow_type">in</property>
+                    <child>
+                      <placeholder/>
+                    </child>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkFrame" id="frame4">
+                <property name="width_request">200</property>
+                <property name="visible">True</property>
+                <property name="label_xalign">0</property>
+                <property name="shadow_type">none</property>
+                <child>
+                  <object class="GtkAlignment" id="alignment4">
+                    <property name="visible">True</property>
+                    <property name="left_padding">12</property>
+                    <child>
+                      <object class="GtkVBox" id="vbox9">
+                        <property name="visible">True</property>
+                        <property name="orientation">vertical</property>
+                        <property name="spacing">8</property>
+                        <child>
+                          <object class="GtkVBox" id="vbox10">
+                            <property name="visible">True</property>
+                            <property name="orientation">vertical</property>
+                            <property name="spacing">4</property>
+                            <child>
+                              <object class="GtkLabel" id="label6">
+                                <property name="visible">True</property>
+                                <property name="xalign">0</property>
+                                <property name="label" translatable="yes">Categories</property>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkTreeView" id="treeview1">
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                              </object>
+                              <packing>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkVBox" id="vbox11">
+                            <property name="visible">True</property>
+                            <property name="orientation">vertical</property>
+                            <property name="spacing">4</property>
+                            <child>
+                              <object class="GtkLabel" id="label9">
+                                <property name="visible">True</property>
+                                <property name="xalign">0</property>
+                                <property name="label" translatable="yes">Tags</property>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkTreeView" id="treeview2">
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                              </object>
+                              <packing>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+                <child type="label">
+                  <object class="GtkLabel" id="label4">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">Filter</property>
+                    <property name="use_markup">True</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="position">1</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </object>
+</interface>
diff --git a/data/stats_reports.ui b/data/stats_reports.ui
new file mode 100644
index 0000000..68a2cd5
--- /dev/null
+++ b/data/stats_reports.ui
@@ -0,0 +1,335 @@
+<?xml version="1.0"?>
+<interface>
+  <requires lib="gtk+" version="2.16"/>
+  <!-- interface-naming-policy project-wide -->
+  <object class="GtkWindow" id="reports_window">
+    <child>
+      <object class="GtkVBox" id="reports_box">
+        <property name="visible">True</property>
+        <property name="orientation">vertical</property>
+        <child>
+          <object class="GtkToolbar" id="toolbar1">
+            <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>
+            <child>
+              <object class="GtkToolButton" id="reports_prev">
+                <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">Previous</property>
+                <property name="stock_id">gtk-go-back</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="homogeneous">True</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkToolButton" id="reports_home">
+                <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">This Week</property>
+                <property name="use_underline">True</property>
+                <property name="stock_id">gtk-home</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="homogeneous">True</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkToolButton" id="reports_next">
+                <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">Next</property>
+                <property name="stock_id">gtk-go-forward</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="homogeneous">True</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkSeparatorToolItem" id="toolbutton2">
+                <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>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkRadioToolButton" id="reports_day_view">
+                <property name="visible">True</property>
+                <property name="is_important">True</property>
+                <property name="label" translatable="yes"> _Day</property>
+                <property name="use_underline">True</property>
+                <property name="icon_widget">day_icon1</property>
+                <property name="active">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="homogeneous">True</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkRadioToolButton" id="reports_week_view">
+                <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="is_important">True</property>
+                <property name="label" translatable="yes"> _Week</property>
+                <property name="use_underline">True</property>
+                <property name="icon_widget">week_icon1</property>
+                <property name="active">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="homogeneous">True</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkRadioToolButton" id="reports_month_view">
+                <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="is_important">True</property>
+                <property name="label" translatable="yes"> _Month</property>
+                <property name="use_underline">True</property>
+                <property name="icon_widget">month_icon1</property>
+                <property name="active">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="homogeneous">True</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkSeparatorToolItem" id="&lt;separator&gt;1">
+                <property name="visible">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="homogeneous">True</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkToolButton" id="report_button">
+                <property name="visible">True</property>
+                <property name="is_important">True</property>
+                <property name="label" translatable="yes">Save Report</property>
+                <property name="use_underline">True</property>
+                <property name="stock_id">gtk-save</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="homogeneous">True</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkVBox" id="vbox6">
+            <property name="visible">True</property>
+            <property name="border_width">12</property>
+            <property name="orientation">vertical</property>
+            <property name="spacing">6</property>
+            <child>
+              <object class="GtkLabel" id="overview_label">
+                <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="xalign">0</property>
+                <property name="label" translatable="yes">&lt;b&gt;Overview&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+                <property name="single_line_mode">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkHPaned" id="hpaned1">
+                <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">300</property>
+                <property name="position_set">True</property>
+                <child>
+                  <object class="GtkScrolledWindow" id="scrolledwindow1">
+                    <property name="width_request">300</property>
+                    <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">automatic</property>
+                    <property name="vscrollbar_policy">automatic</property>
+                    <property name="shadow_type">in</property>
+                    <child>
+                      <object class="GtkTreeView" id="facts">
+                        <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="enable_search">False</property>
+                        <signal name="key_press_event" handler="on_key_pressed"/>
+                        <signal name="row_activated" handler="on_facts_row_activated"/>
+                      </object>
+                    </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">
+                        <property name="visible">True</property>
+                        <signal name="size_allocate" handler="on_graph_frame_size_allocate"/>
+                        <child>
+                          <object class="GtkVBox" id="vbox4">
+                            <property name="visible">True</property>
+                            <property name="orientation">vertical</property>
+                            <child>
+                              <object class="GtkVBox" id="graphs">
+                                <property name="width_request">390</property>
+                                <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>
+                                <child>
+                                  <object class="GtkFrame" id="fram1">
+                                    <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="GtkHBox" id="week_box">
+                                        <property name="visible">True</property>
+                                        <property name="border_width">9</property>
+                                        <property name="spacing">36</property>
+                                        <child>
+                                          <object class="GtkEventBox" id="totals_by_category">
+                                            <property name="visible">True</property>
+                                            <child>
+                                              <placeholder/>
+                                            </child>
+                                          </object>
+                                          <packing>
+                                            <property name="expand">False</property>
+                                            <property name="position">0</property>
+                                          </packing>
+                                        </child>
+                                        <child>
+                                          <object class="GtkEventBox" id="totals_by_day">
+                                            <property name="visible">True</property>
+                                            <child>
+                                              <placeholder/>
+                                            </child>
+                                          </object>
+                                          <packing>
+                                            <property name="position">1</property>
+                                          </packing>
+                                        </child>
+                                      </object>
+                                    </child>
+                                    <child type="label">
+                                      <object class="GtkLabel" id="dayview_caption">
+                                        <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="use_markup">True</property>
+                                      </object>
+                                    </child>
+                                  </object>
+                                  <packing>
+                                    <property name="position">0</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkFrame" id="frame39">
+                                    <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">
+                                        <property name="visible">True</property>
+                                        <property name="border_width">12</property>
+                                        <child>
+                                          <placeholder/>
+                                        </child>
+                                      </object>
+                                    </child>
+                                    <child type="label">
+                                      <object class="GtkLabel" id="label5">
+                                        <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="use_markup">True</property>
+                                      </object>
+                                    </child>
+                                  </object>
+                                  <packing>
+                                    <property name="position">1</property>
+                                  </packing>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkLabel" id="no_data_label">
+                                <property name="no_show_all">True</property>
+                                <property name="label" translatable="yes">No data for this interval</property>
+                              </object>
+                              <packing>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                          </object>
+                        </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">300</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </object>
+  <object class="GtkImage" id="day_icon1">
+    <property name="visible">True</property>
+    <property name="pixbuf">art/stock_calendar-view-day.png</property>
+  </object>
+  <object class="GtkImage" id="week_icon1">
+    <property name="visible">True</property>
+    <property name="pixbuf">art/stock_calendar-view-week.png</property>
+  </object>
+  <object class="GtkImage" id="month_icon1">
+    <property name="visible">True</property>
+    <property name="tooltip_text" translatable="yes">Show month</property>
+    <property name="pixbuf">art/stock_calendar-view-month.png</property>
+  </object>
+</interface>
diff --git a/data/stats_stats.ui b/data/stats_stats.ui
new file mode 100644
index 0000000..839dd1f
--- /dev/null
+++ b/data/stats_stats.ui
@@ -0,0 +1,273 @@
+<?xml version="1.0"?>
+<interface>
+  <requires lib="gtk+" version="2.16"/>
+  <!-- interface-naming-policy project-wide -->
+  <object class="GtkWindow" id="stats_window">
+    <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">12</property>
+    <property name="window_position">center</property>
+    <property name="default_width">800</property>
+    <property name="default_height">600</property>
+    <property name="icon_name">hamster-applet</property>
+    <signal name="key_press_event" handler="on_window_key_pressed"/>
+    <signal name="delete_event" handler="on_close"/>
+    <child>
+      <object class="GtkVBox" id="stats_box">
+        <property name="visible">True</property>
+        <property name="border_width">12</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">12</property>
+        <child>
+          <object class="GtkAlignment" id="alignment3">
+            <property name="visible">True</property>
+            <property name="yscale">0</property>
+            <child>
+              <object class="GtkTable" id="explore_controls">
+                <property name="visible">True</property>
+                <property name="n_columns">2</property>
+                <property name="column_spacing">12</property>
+                <property name="row_spacing">6</property>
+                <child>
+                  <object class="GtkLabel" id="label10">
+                    <property name="visible">True</property>
+                    <property name="xalign">0</property>
+                    <property name="label" translatable="yes">Year:</property>
+                  </object>
+                  <packing>
+                    <property name="x_options">GTK_FILL</property>
+                    <property name="y_options">GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkAlignment" id="alignment5">
+                    <property name="visible">True</property>
+                    <property name="xalign">0</property>
+                    <property name="xscale">0</property>
+                    <child>
+                      <object class="GtkHBox" id="year_box">
+                        <property name="visible">True</property>
+                        <child>
+                          <placeholder/>
+                        </child>
+                        <child>
+                          <placeholder/>
+                        </child>
+                        <child>
+                          <placeholder/>
+                        </child>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                  </packing>
+                </child>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkFrame" id="frame2">
+            <property name="visible">True</property>
+            <property name="label_xalign">0</property>
+            <child>
+              <object class="GtkEventBox" id="explore_frame">
+                <property name="visible">True</property>
+                <child>
+                  <object class="GtkAlignment" id="alignment7">
+                    <property name="visible">True</property>
+                    <property name="top_padding">12</property>
+                    <property name="bottom_padding">12</property>
+                    <property name="left_padding">12</property>
+                    <property name="right_padding">12</property>
+                    <child>
+                      <object class="GtkVBox" id="vbox3">
+                        <property name="visible">True</property>
+                        <property name="orientation">vertical</property>
+                        <child>
+                          <object class="GtkVBox" id="statistics_box">
+                            <property name="visible">True</property>
+                            <property name="orientation">vertical</property>
+                            <property name="spacing">12</property>
+                            <child>
+                              <object class="GtkAlignment" id="explore_everything">
+                                <property name="height_request">50</property>
+                                <property name="visible">True</property>
+                                <child>
+                                  <placeholder/>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkHBox" id="vbox77">
+                                <property name="visible">True</property>
+                                <child>
+                                  <object class="GtkVBox" id="vbox5">
+                                    <property name="visible">True</property>
+                                    <property name="orientation">vertical</property>
+                                    <child>
+                                      <object class="GtkHBox" id="hbox5">
+                                        <property name="visible">True</property>
+                                        <property name="homogeneous">True</property>
+                                        <child>
+                                          <object class="GtkLabel" id="label7">
+                                            <property name="visible">True</property>
+                                            <property name="xalign">0</property>
+                                            <property name="ypad">8</property>
+                                            <property name="label" translatable="yes">&lt;b&gt;Starts and ends&lt;/b&gt;</property>
+                                            <property name="use_markup">True</property>
+                                          </object>
+                                          <packing>
+                                            <property name="position">0</property>
+                                          </packing>
+                                        </child>
+                                        <child>
+                                          <object class="GtkLabel" id="label8">
+                                            <property name="visible">True</property>
+                                            <property name="xalign">0</property>
+                                            <property name="label" translatable="yes">&lt;b&gt;Totals&lt;/b&gt;</property>
+                                            <property name="use_markup">True</property>
+                                          </object>
+                                          <packing>
+                                            <property name="position">1</property>
+                                          </packing>
+                                        </child>
+                                      </object>
+                                      <packing>
+                                        <property name="expand">False</property>
+                                        <property name="position">0</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkHBox" id="hbox3">
+                                        <property name="height_request">160</property>
+                                        <property name="visible">True</property>
+                                        <property name="homogeneous">True</property>
+                                        <child>
+                                          <object class="GtkAlignment" id="explore_weekday_starts_ends">
+                                            <property name="visible">True</property>
+                                            <child>
+                                              <placeholder/>
+                                            </child>
+                                          </object>
+                                          <packing>
+                                            <property name="position">0</property>
+                                          </packing>
+                                        </child>
+                                        <child>
+                                          <object class="GtkAlignment" id="explore_weekday_totals">
+                                            <property name="visible">True</property>
+                                            <child>
+                                              <placeholder/>
+                                            </child>
+                                          </object>
+                                          <packing>
+                                            <property name="position">1</property>
+                                          </packing>
+                                        </child>
+                                      </object>
+                                      <packing>
+                                        <property name="expand">False</property>
+                                        <property name="position">1</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkHBox" id="hbox4">
+                                        <property name="height_request">100</property>
+                                        <property name="visible">True</property>
+                                        <property name="homogeneous">True</property>
+                                        <child>
+                                          <object class="GtkAlignment" id="explore_category_starts_ends">
+                                            <property name="visible">True</property>
+                                            <child>
+                                              <placeholder/>
+                                            </child>
+                                          </object>
+                                          <packing>
+                                            <property name="position">0</property>
+                                          </packing>
+                                        </child>
+                                        <child>
+                                          <object class="GtkAlignment" id="explore_category_totals">
+                                            <property name="visible">True</property>
+                                            <child>
+                                              <placeholder/>
+                                            </child>
+                                          </object>
+                                          <packing>
+                                            <property name="position">1</property>
+                                          </packing>
+                                        </child>
+                                      </object>
+                                      <packing>
+                                        <property name="position">2</property>
+                                      </packing>
+                                    </child>
+                                  </object>
+                                  <packing>
+                                    <property name="position">0</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkAlignment" id="explore_summary">
+                                    <property name="width_request">200</property>
+                                    <property name="visible">True</property>
+                                    <property name="xalign">0</property>
+                                    <property name="yalign">0</property>
+                                    <property name="top_padding">32</property>
+                                    <property name="left_padding">30</property>
+                                    <child>
+                                      <placeholder/>
+                                    </child>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="position">1</property>
+                                  </packing>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkLabel" id="not_enough_records_label">
+                            <property name="label">Text we say when there is not enough data</property>
+                            <property name="wrap">True</property>
+                          </object>
+                          <packing>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+            <child type="label_item">
+              <placeholder/>
+            </child>
+          </object>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </object>
+</interface>
diff --git a/hamster/Makefile.am b/hamster/Makefile.am
index a93c842..0773f3b 100644
--- a/hamster/Makefile.am
+++ b/hamster/Makefile.am
@@ -18,9 +18,12 @@ hamster_PYTHON = \
 	db.py \
 	eds.py \
 	stats.py \
+	stats_overview.py \
+	stats_reports.py \
+	stats_stats.py \
 	reports.py \
 	charting.py \
-    graphics.py \
+        graphics.py \
 	configuration.py \
 	KeyBinder.py \
 	preferences.py \
@@ -30,8 +33,8 @@ hamster_PYTHON = \
 	about.py \
 	hamsterdbus.py \
 	idle.py \
-    i18n.py \
-    pytweener.py \
+        i18n.py \
+        pytweener.py \
 	__init__.py
 
 BUILT_SOURCES = \
diff --git a/hamster/stats.py b/hamster/stats.py
index a529e23..678088a 100644
--- a/hamster/stats.py
+++ b/hamster/stats.py
@@ -26,1043 +26,52 @@ import gtk, gobject
 import pango
 
 import stuff
-import charting
-
-from edit_activity import CustomFactController
-import reports, graphics
 
 import widgets
 
 from configuration import runtime, GconfStore
-import webbrowser
-
-from itertools import groupby
-from gettext import ngettext
 
-import datetime as dt
-import calendar
-import time
-from hamster.i18n import C_
+from stats_overview import OverviewBox
+from stats_reports import ReportsBox
+from stats_stats import StatsBox
 
 
 class StatsViewer(object):
     def __init__(self, parent = None):
         self.parent = parent# determine if app should shut down on close
         self._gui = stuff.load_ui_file("stats.ui")
-        self.window = self.get_widget('stats_window')
-        self.stat_facts = None
-
-        #id, caption, duration, date (invisible), description, category
-        self.fact_store = gtk.TreeStore(int, str, str, str, str, str, gobject.TYPE_PYOBJECT) 
-        self.setup_tree()
-        
-        
-        #graphs
-        self.background = (0.975, 0.975, 0.975)
-        self.get_widget("graph_frame").modify_bg(gtk.STATE_NORMAL,
-                      gtk.gdk.Color(*[int(b*65536.0) for b in self.background]))
-        self.get_widget("explore_frame").modify_bg(gtk.STATE_NORMAL,
-                      gtk.gdk.Color(*[int(b*65536.0) for b in self.background]))
-
 
-        x_offset = 90 # align all graphs to the left edge
+        self.window = self.get_widget("tabs_window")
         
-        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.overview = OverviewBox()
+        self.get_widget("overview_tab").add(self.overview)
 
+        self.reports = ReportsBox()
+        self.get_widget("reports_tab").add(self.reports)
 
-        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.get_widget("totals_by_activity").add(self.activity_chart);
-
-        
-        self.view_date = dt.date.today()
-        
-        #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())
-        
-        self.end_date = self.start_date + dt.timedelta(6)
-
-        
-        self.week_view = self.get_widget("week")
-        self.month_view = self.get_widget("month")
-        self.month_view.set_group(self.week_view)
-        self.day_view = self.get_widget("day")
-        self.day_view.set_group(self.week_view)
-        
-        #initiate the form in the week view
-        self.week_view.set_active(True)
-
-
-        runtime.dispatcher.add_handler('activity_updated', self.after_activity_update)
-        runtime.dispatcher.add_handler('day_updated', self.after_fact_update)
-
-        selection = self.fact_tree.get_selection()
-        selection.connect('changed', self.on_fact_selection_changed,
-                          self.fact_store)
-        self.popular_categories = [cat[0] for cat in runtime.storage.get_popular_categories()]
+        self.stats = StatsBox()
+        self.get_widget("stats_tab").add(self.stats)
 
         self._gui.connect_signals(self)
-        self.fact_tree.grab_focus()
-
-        self.timeline = widgets.TimeLine()
-        self.get_widget("explore_everything").add(self.timeline)
-        self.get_widget("explore_everything").show_all()
-
-        
-        self.config = GconfStore()
-        runtime.dispatcher.add_handler('gconf_on_day_start_changed', self.on_day_start_changed)
-
-        self.report_chooser = None
-        self.do_graph()
-        self.init_stats()
-
-        
-    def on_day_start_changed(self, event, new_minutes):
-        self.do_graph()
-
-    def init_stats(self):
-        self.stat_facts = runtime.storage.get_facts(dt.date(1970, 1, 1), dt.date.today())
-        
-        by_year = stuff.totals(self.stat_facts,
-                               lambda fact: fact["start_time"].year,
-                               lambda fact: 1)
-        
-        year_box = self.get_widget("year_box")
-        class YearButton(gtk.ToggleButton):
-            def __init__(self, label, year, on_clicked):
-                gtk.ToggleButton.__init__(self, label)
-                self.year = year
-                self.connect("clicked", on_clicked)
-        
-        all_button = YearButton(C_("years", "All").encode("utf-8"),
-                                None,
-                                self.on_year_changed)
-        year_box.pack_start(all_button)
-        self.bubbling = True # TODO figure out how to properly work with togglebuttons as radiobuttons
-        all_button.set_active(True)
-        self.bubbling = False # TODO figure out how to properly work with togglebuttons as radiobuttons
-
-        years = sorted(by_year.keys())
-        for year in years:
-            year_box.pack_start(YearButton(str(year), year, self.on_year_changed))
-
-        year_box.show_all()
-
-        self.chart_category_totals = charting.HorizontalBarChart(value_format = "%.1f",
-                                                            bars_beveled = False,
-                                                            background = self.background,
-                                                            max_bar_width = 20,
-                                                            legend_width = 70)
-        self.get_widget("explore_category_totals").add(self.chart_category_totals)
-
-
-        self.chart_weekday_totals = charting.HorizontalBarChart(value_format = "%.1f",
-                                                            bars_beveled = False,
-                                                            background = self.background,
-                                                            max_bar_width = 20,
-                                                            legend_width = 70)
-        self.get_widget("explore_weekday_totals").add(self.chart_weekday_totals)
-
-        self.chart_weekday_starts_ends = charting.HorizontalDayChart(bars_beveled = False,
-                                                                animate = False,
-                                                                background = self.background,
-                                                                max_bar_width = 20,
-                                                                legend_width = 70)
-        self.get_widget("explore_weekday_starts_ends").add(self.chart_weekday_starts_ends)
         
-        self.chart_category_starts_ends = charting.HorizontalDayChart(bars_beveled = False,
-                                                                animate = False,
-                                                                background = self.background,
-                                                                max_bar_width = 20,
-                                                                legend_width = 70)
-        self.get_widget("explore_category_starts_ends").add(self.chart_category_starts_ends)
-
-
-        #ah, just want summary look just like all the other text on the page
-        class CairoText(graphics.Area):
-            def __init__(self, background = None, fontsize = 10):
-                graphics.Area.__init__(self)
-                self.background = background
-                self.text = ""
-                self.fontsize = fontsize
-                
-            def set_text(self, text):
-                self.text = text
-                self.redraw_canvas()
-                
-            def on_expose(self):
-                if self.background:
-                    self.fill_area(0, 0, self.width, self.height, self.background)
-
-                default_font = pango.FontDescription(gtk.Style().font_desc.to_string())
-                default_font.set_size(self.fontsize * pango.SCALE)
-                self.layout.set_font_description(default_font)
-                
-                #self.context.set_source_rgb(0,0,0)
-                self.layout.set_markup(self.text)
-
-                self.layout.set_width((self.width) * pango.SCALE)
-                self.context.move_to(0,0)
-                self.set_color(charting.graphics.Colors.aluminium[5])
-                
-                self.context.show_layout(self.layout)
-
-        self.explore_summary = CairoText(self.background)
-        self.get_widget("explore_summary").add(self.explore_summary)
-        self.get_widget("explore_summary").show_all()
-
-    def stats(self, year = None):
-        facts = self.stat_facts
-        if year:
-            facts = filter(lambda fact: fact["start_time"].year == year,
-                           facts)
-
-        if not facts or (facts[-1]["start_time"] - facts[0]["start_time"]) < dt.timedelta(days=6):
-            self.get_widget("statistics_box").hide()
-            self.get_widget("explore_controls").hide()
-            label = self.get_widget("not_enough_records_label")
-
-            if not facts:
-                label.set_text(_("""There is no data to generate statistics yet.
-A week of usage would be nice!"""))
-            else:
-                label.set_text(_("Still collecting data â?? check back after a week has passed!"))
-
-            label.show()
-            return
-        else:
-            self.get_widget("statistics_box").show()
-            self.get_widget("explore_controls").show()
-            self.get_widget("not_enough_records_label").hide()
-
-        # All dates in the scope
-        self.timeline.draw(facts)
-
-
-        # Totals by category
-        categories = stuff.totals(facts,
-                                  lambda fact: fact["category"],
-                                  lambda fact: fact['delta'].seconds / 60 / 60.0)
-        category_keys = sorted(categories.keys())
-        categories = [categories[key] for key in category_keys]
-        self.chart_category_totals.plot(category_keys, categories)
-        
-        # Totals by weekday
-        weekdays = stuff.totals(facts,
-                                lambda fact: (fact["start_time"].weekday(),
-                                              fact["start_time"].strftime("%a")),
-                                lambda fact: fact['delta'].seconds / 60 / 60.0)
-        
-        weekday_keys = sorted(weekdays.keys(), key = lambda x: x[0]) #sort 
-        weekdays = [weekdays[key] for key in weekday_keys] #get values in the order
-        weekday_keys = [key[1] for key in weekday_keys] #now remove the weekday and keep just the abbreviated one
-        self.chart_weekday_totals.plot(weekday_keys, weekdays)
-
-
-        split_minutes = 5 * 60 + 30 #the mystical hamster midnight
-        
-        # starts and ends by weekday
-        by_weekday = {}
-        for date, date_facts in groupby(facts, lambda fact: fact["start_time"].date()):
-            date_facts = list(date_facts)
-            weekday = (date_facts[0]["start_time"].weekday(),
-                       date_facts[0]["start_time"].strftime("%a"))
-            by_weekday.setdefault(weekday, [])
-            
-            start_times, end_times = [], []
-            for fact in date_facts:
-                start_time = fact["start_time"].time()
-                start_time = start_time.hour * 60 + start_time.minute
-                if fact["end_time"]:
-                    end_time = fact["end_time"].time()
-                    end_time = end_time.hour * 60 + end_time.minute
-                
-                    if start_time < split_minutes:
-                        start_time += 24 * 60
-                    if end_time < start_time:
-                        end_time += 24 * 60
-                    
-                    start_times.append(start_time)
-                    end_times.append(end_time)
-            if start_times and end_times:            
-                by_weekday[weekday].append((min(start_times), max(end_times)))
-
-
-        for day in by_weekday:
-            by_weekday[day] = (sum([fact[0] for fact in by_weekday[day]]) / len(by_weekday[day]),
-                               sum([fact[1] for fact in by_weekday[day]]) / len(by_weekday[day]))
-
-        min_weekday = min([by_weekday[day][0] for day in by_weekday])
-        max_weekday = max([by_weekday[day][1] for day in by_weekday])
-
-
-        weekday_keys = sorted(by_weekday.keys(), key = lambda x: x[0])
-        weekdays = [by_weekday[key] for key in weekday_keys]
-        weekday_keys = [key[1] for key in weekday_keys] # get rid of the weekday number as int
+        self.window.show_all()
 
         
-        # starts and ends by category
-        by_category = {}
-        for date, date_facts in groupby(facts, lambda fact: fact["start_time"].date()):
-            date_facts = sorted(list(date_facts), key = lambda x: x["category"])
-            
-            for category, category_facts in groupby(date_facts, lambda x: x["category"]):
-                category_facts = list(category_facts)
-                by_category.setdefault(category, [])
-                
-                start_times, end_times = [], []
-                for fact in category_facts:
-                    start_time = fact["start_time"]
-                    start_time = start_time.hour * 60 + start_time.minute
-                    if fact["end_time"]:
-                        end_time = fact["end_time"].time()
-                        end_time = end_time.hour * 60 + end_time.minute
-                        
-                        if start_time < split_minutes:
-                            start_time += 24 * 60
-                        if end_time < start_time:
-                            end_time += 24 * 60
-
-                        start_times.append(start_time)
-                        end_times.append(end_time)
-
-                if start_times and end_times:            
-                    by_category[category].append((min(start_times), max(end_times)))
-
-        for cat in by_category:
-            by_category[cat] = (sum([fact[0] for fact in by_category[cat]]) / len(by_category[cat]),
-                                sum([fact[1] for fact in by_category[cat]]) / len(by_category[cat]))
-
-        min_category = min([by_category[day][0] for day in by_category])
-        max_category = max([by_category[day][1] for day in by_category])
-
-        category_keys = sorted(by_category.keys(), key = lambda x: x[0])
-        categories = [by_category[key] for key in category_keys]
-
-
-        #get starting and ending hours for graph and turn them into exact hours that divide by 3
-        min_hour = min([min_weekday, min_category]) / 60 * 60
-        max_hour = max([max_weekday, max_category]) / 60 * 60
-
-        self.chart_weekday_starts_ends.plot_day(weekday_keys, weekdays, min_hour, max_hour)
-        self.chart_category_starts_ends.plot_day(category_keys, categories, min_hour, max_hour)
-
-
-        #now the factoids!
-        summary = ""
-
-        # first record        
-        if not year:
-            # date format for the first record if the year has not been selected
-            # Using python datetime formatting syntax. See:
-            # http://docs.python.org/library/time.html#time.strftime
-            first_date = facts[0]["start_time"].strftime(C_("first record", "%b %d, %Y"))
-        else:
-            # date of first record when year has been selected
-            # Using python datetime formatting syntax. See:
-            # http://docs.python.org/library/time.html#time.strftime
-            first_date = facts[0]["start_time"].strftime(C_("first record", "%b %d"))
-
-        summary += _("First activity was recorded on %s.") % \
-                                                     ("<b>%s</b>" % first_date)
-        
-        # total time tracked
-        total_delta = dt.timedelta(days=0)
-        for fact in facts:
-            total_delta += fact["delta"]
-        
-        if total_delta.days > 1:
-            human_years_str = ngettext("%(num)s year",
-                                       "%(num)s years",
-                                       total_delta.days / 365) % {
-                              'num': "<b>%.2f</b>" % (total_delta.days / 365.0)}
-            working_years_str = ngettext("%(num)s year",
-                                         "%(num)s years",
-                                         total_delta.days * 3 / 365) % {
-                         'num': "<b>%.2f</b>" % (total_delta.days * 3 / 365.0) }
-            #FIXME: difficult string to properly pluralize
-            summary += " " + _("""Time tracked so far is %(human_days)s human days \
-(%(human_years)s) or %(working_days)s working days (%(working_years)s).""") % {
-              "human_days": ("<b>%d</b>" % total_delta.days),
-              "human_years": human_years_str,
-              "working_days": ("<b>%d</b>" % (total_delta.days * 3)), # 8 should be pretty much an average working day
-              "working_years": working_years_str }
-        
-
-        # longest fact
-        max_fact = None
-        for fact in facts:
-            if not max_fact or fact["delta"] > max_fact["delta"]:
-                max_fact = fact
-
-        longest_date = max_fact["start_time"].strftime(
-            # How the date of the longest activity should be displayed in statistics
-            # Using python datetime formatting syntax. See:
-            # http://docs.python.org/library/time.html#time.strftime
-            C_("date of the longest activity", "%b %d, %Y"))
-        
-        num_hours = max_fact["delta"].seconds / 60 / 60.0 + max_fact["delta"].days * 24
-        hours = "<b>%.1f</b>" % (num_hours)
-        
-        summary += "\n" + ngettext("Longest continuous work happened on \
-%(date)s and was %(hours)s hour.",
-                                  "Longest continuous work happened on \
-%(date)s and was %(hours)s hours.",
-                                  int(num_hours)) % {"date": longest_date,
-                                                     "hours": hours}
-
-        # total records (in selected scope)
-        summary += " " + ngettext("There is %s record.",
-                                  "There are %s records.",
-                                  len(facts)) % ("<b>%d</b>" % len(facts))
-
-
-        early_start, early_end = dt.time(5,0), dt.time(9,0)
-        late_start, late_end = dt.time(20,0), dt.time(5,0)
-        
-        
-        fact_count = len(facts)
-        def percent(condition):
-            matches = [fact for fact in facts if condition(fact)]
-            return round(len(matches) / float(fact_count) * 100)
-        
-        
-        early_percent = percent(lambda fact: early_start < fact["start_time"].time() < early_end)
-        late_percent = percent(lambda fact: fact["start_time"].time() > late_start or fact["start_time"].time() < late_end)
-        short_percent = percent(lambda fact: fact["delta"] <= dt.timedelta(seconds = 60 * 15))
-
-        if fact_count < 100:
-            summary += "\n\n" + _("Hamster would like to observe you some more!")
-        elif early_percent >= 20:
-            summary += "\n\n" + _("With %s percent of all facts starting before \
-9am you seem to be an early bird." % ("<b>%d</b>" % early_percent))
-        elif late_percent >= 20:
-            summary += "\n\n" + _("With %s percent of all facts starting after \
-11pm you seem to be a night owl." % ("<b>%d</b>" % late_percent))
-        elif short_percent >= 20:
-            summary += "\n\n" + _("With %s percent of all tasks being shorter \
-than 15 minutes you seem to be a busy bee." % ("<b>%d</b>" % short_percent))
-
-        self.explore_summary.set_text(summary)
-
-    def setup_tree(self):
-        def parent_painter(column, cell, model, iter):
-            cell_text = model.get_value(iter, 1)
-            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:
-                activity_name = stuff.escape_pango(cell_text)
-                description = stuff.escape_pango(model.get_value(iter, 4))
-                category = stuff.escape_pango(model.get_value(iter, 5))
-
-                markup = stuff.format_activity(activity_name,
-                                               category,
-                                               description,
-                                               pad_description = True)            
-                cell.set_property('markup', markup)
-
-        def duration_painter(column, cell, model, iter):
-            cell.set_property('xalign', 1)
-            cell.set_property('yalign', 0)
-    
-
-            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)
-    
-
-        self.fact_tree = self.get_widget("facts")
-        self.fact_tree.set_headers_visible(False)
-        self.fact_tree.set_tooltip_column(1)
-        self.fact_tree.set_property("show-expanders", False)
-
-        # name
-        nameColumn = gtk.TreeViewColumn()
-        nameColumn.set_expand(True)
-        nameCell = gtk.CellRendererText()
-        nameCell.set_property("ellipsize", pango.ELLIPSIZE_END)
-        nameColumn.pack_start(nameCell, True)
-        nameColumn.set_cell_data_func(nameCell, parent_painter)
-        self.fact_tree.append_column(nameColumn)
-
-        # duration
-        timeColumn = gtk.TreeViewColumn()
-        timeCell = gtk.CellRendererText()
-        timeColumn.pack_end(timeCell, True)
-        timeColumn.set_cell_data_func(timeCell, duration_painter)
-
-
-
-
-        self.fact_tree.append_column(timeColumn)
-        
-        self.fact_tree.set_model(self.fact_store)
-    
-    def on_graph_frame_size_allocate(self, widget, new_size):
-        w = min(new_size.width / 4, 200)
-        
-        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 fill_tree(self, facts):
-        day_dict = {}
-        for day, facts in groupby(facts, lambda fact: fact["date"]):
-            day_dict[day] = sorted(list(facts),
-                                   key=lambda fact: fact["start_time"])
-        
-        for i in range((self.end_date - self.start_date).days  + 1):
-            current_date = self.start_date + dt.timedelta(i)
-            
-            # Date format for the label in overview window fact listing
-            # Using python datetime formatting syntax. See:
-            # http://docs.python.org/library/time.html#time.strftime
-            fact_date = current_date.strftime(C_("overview list", "%A, %b %d"))
-            
-            day_total = dt.timedelta()
-            for fact in day_dict.get(current_date, []):
-                day_total += fact["delta"]
-
-            day_row = self.fact_store.append(None,
-                                             [-1,
-                                              fact_date,
-                                              stuff.format_duration(day_total),
-                                              current_date.strftime('%Y-%m-%d'),
-                                              "",
-                                              "",
-                                              None])
-
-            for fact in day_dict.get(current_date, []):
-                self.fact_store.append(day_row,
-                                       [fact["id"],
-                                        fact["start_time"].strftime('%H:%M') + " " +
-                                        fact["name"],
-                                        stuff.format_duration(fact["delta"]),
-                                        fact["start_time"].strftime('%Y-%m-%d'),
-                                        fact["description"],
-                                        fact["category"],
-                                        fact
-                                        ])
-
-        self.fact_tree.expand_all()
-
-        
-    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)]
-        
-        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]
-        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 set_title(self):
-        if self.day_view.get_active():
-            # date format for overview label when only single day is visible
-            # Using python datetime formatting syntax. See:
-            # http://docs.python.org/library/time.html#time.strftime
-            start_date_str = self.view_date.strftime(C_("single day overview",
-                                                        "%B %d, %Y"))
-            # Overview label if looking on single day
-            overview_label = _(u"Overview for %(date)s") % \
-                                                      ({"date": start_date_str})
-        else:
-            dates_dict = stuff.dateDict(self.start_date, "start_")
-            dates_dict.update(stuff.dateDict(self.end_date, "end_"))
-            
-            if self.start_date.year != self.end_date.year:
-                # overview label if start and end years don't match
-                # letter after prefixes (start_, end_) is the one of
-                # standard python date formatting ones- you can use all of them
-                # see http://docs.python.org/library/time.html#time.strftime
-                overview_label = _(u"Overview for %(start_B)s %(start_d)s, %(start_Y)s â?? %(end_B)s %(end_d)s, %(end_Y)s") % dates_dict
-            elif self.start_date.month != self.end_date.month:
-                # overview label if start and end month do not match
-                # letter after prefixes (start_, end_) is the one of
-                # standard python date formatting ones- you can use all of them
-                # see http://docs.python.org/library/time.html#time.strftime
-                overview_label = _(u"Overview for %(start_B)s %(start_d)s â?? %(end_B)s %(end_d)s, %(end_Y)s") % dates_dict
-            else:
-                # overview label for interval in same month
-                # letter after prefixes (start_, end_) is the one of
-                # standard python date formatting ones- you can use all of them
-                # see http://docs.python.org/library/time.html#time.strftime
-                overview_label = _(u"Overview for %(start_B)s %(start_d)s â?? %(end_d)s, %(end_Y)s") % dates_dict
-
-        if self.week_view.get_active():
-            dayview_caption = _("Week")
-        elif self.month_view.get_active():
-            dayview_caption = _("Month")
-        else:
-            dayview_caption = _("Day")
-        
-        self.get_widget("overview_label").set_markup("<b>%s</b>" % overview_label)
-        self.get_widget("dayview_caption").set_markup("%s" % (dayview_caption))
-        
-
-    def do_graph(self):
-        self.set_title()
-        
-        if self.day_view.get_active():
-            facts = runtime.storage.get_facts(self.view_date)
-        else:
-            facts = runtime.storage.get_facts(self.start_date, self.end_date)
-
-
-        self.get_widget("report_button").set_sensitive(len(facts) > 0)
-        self.fact_store.clear()
-        
-        self.fill_tree(facts)
-
-        if not facts:
-            self.get_widget("graphs").hide()
-            self.get_widget("no_data_label").show()
-            return 
-
-
-        self.get_widget("no_data_label").hide()
-        self.get_widget("graphs").show()
-        self.do_charts(facts)
-            
-
-
     def get_widget(self, name):
         """ skip one variable (huh) """
         return self._gui.get_object(name)
 
-    def on_pages_switch_page(self, notebook, page, pagenum):
-        if pagenum == 1:
+    def on_window_tabs_switch_page(self, notebook, page, pagenum):
+        if pagenum == 2:
             year = None
-            for child in self.get_widget("year_box").get_children():
+            for child in self.stats.get_widget("year_box").get_children():
                 if child.get_active():
                     year = child.year
             
-            self.stats(year)
-        else:
-            self.do_graph()
-        
-    def on_year_changed(self, button):
-        if self.bubbling: return
-        
-        for child in button.parent.get_children():
-            if child != button and child.get_active():
-                self.bubbling = True
-                child.set_active(False)
-                self.bubbling = False
-        
-        self.stats(button.year)
-
-    def on_prev_clicked(self, button):
-        if self.day_view.get_active():
-            self.view_date -= dt.timedelta(1)
-            if self.view_date < self.start_date:
-                self.start_date -= dt.timedelta(7)
-                self.end_date -= dt.timedelta(7)
-        else:
-            if self.week_view.get_active():
-                self.start_date -= dt.timedelta(7)
-                self.end_date -= dt.timedelta(7)
-            
-            elif self.month_view.get_active():
-                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)
-
-            self.view_date = self.start_date
-
-        self.do_graph()
-
-    def on_next_clicked(self, button):
-        if self.day_view.get_active():
-            self.view_date += dt.timedelta(1)
-            if self.view_date > self.end_date:
-                self.start_date += dt.timedelta(7)
-                self.end_date += dt.timedelta(7)
-        else:
-            if self.week_view.get_active():
-                self.start_date += dt.timedelta(7)
-                self.end_date += dt.timedelta(7)        
-            elif self.month_view.get_active():
-                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)
-        
-            self.view_date = self.start_date
-
-        self.do_graph()
-    
-    def on_home_clicked(self, button):
-        self.view_date = dt.date.today()
-        if self.week_view.get_active():
-            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.month_view.get_active():
-            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)
-        
-        self.do_graph()
-        
-    def on_day_toggled(self, button):
-        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)
-        
-        self.get_widget("prev").set_tooltip_text(_("Previous day"))
-        self.get_widget("next").set_tooltip_text(_("Next day"))
-        self.get_widget("home").set_tooltip_text(_("Today"))
-        self.get_widget("home").set_label(_("Today"))
-        
-        self.do_graph()
-
-    def on_week_toggled(self, button):
-        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)
-
-        self.get_widget("prev").set_tooltip_text(_("Previous week"))
-        self.get_widget("next").set_tooltip_text(_("Next week"))
-        self.get_widget("home").set_tooltip_text(_("This week"))
-        self.get_widget("home").set_label(_("This Week"))
-        self.do_graph()
-
-        
-    def on_month_toggled(self, button):
-        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)
-
-        self.get_widget("prev").set_tooltip_text(_("Previous month"))
-        self.get_widget("next").set_tooltip_text(_("Next month"))
-        self.get_widget("home").set_tooltip_text(_("This month"))
-        self.get_widget("home").set_label(_("This Month"))
-        self.do_graph()
-        
-    def on_remove_clicked(self, button):
-        self.delete_selected()
-
-    def on_edit_clicked(self, button):
-        selection = self.fact_tree.get_selection()
-        (model, iter) = selection.get_selected()
-
-        if model[iter][0] == -1:
-            return #not a fact
-
-        custom_fact = CustomFactController(self, None, model[iter][0])
-        custom_fact.show()
-
-    def delete_selected(self):
-        selection = self.fact_tree.get_selection()
-        (model, iter) = selection.get_selected()
-
-        if model[iter][0] == -1:
-            return #not a fact
-
-        next_row = model.iter_next(iter)
-
-        if next_row:
-            selection.select_iter(next_row)
-        else:
-            path = model.get_path(iter)[0] - 1
-            if path > 0:
-                selection.select_path(path)
-
-        runtime.storage.remove_fact(model[iter][0])
-
-    def copy_selected(self):
-        selection = self.fact_tree.get_selection()
-        (model, iter) = selection.get_selected()
-
-        fact = model[iter][6]
-        if not fact:
-            return #not a fact
-
-        fact_str = "%s-%s %s" % (fact["start_time"].strftime("%H:%M"),
-                               (fact["end_time"] or dt.datetime.now()).strftime("%H:%M"),
-                               fact["name"])
-
-        if fact["category"]:
-            fact_str += "@%s" % fact["category"]
-
-        if fact["description"]:
-            fact_str += ", %s" % fact["description"]
-
-        clipboard = gtk.Clipboard()
-        clipboard.set_text(fact_str)
-    
-    def check_clipboard(self):
-        clipboard = gtk.Clipboard()
-        clipboard.request_text(self.on_clipboard_text)
-    
-    def on_clipboard_text(self, clipboard, text, data):
-        # first check that we have a date selected
-        selection = self.fact_tree.get_selection()
-        (model, iter) = selection.get_selected()
-
-        selected_date = self.view_date
-        if iter:
-            selected_date = model[iter][3].split("-")
-            selected_date = dt.date(int(selected_date[0]),
-                                    int(selected_date[1]),
-                                    int(selected_date[2]))
-        if not selected_date:
-            return
-        
-        res = stuff.parse_activity_input(text)
-
-        if res.start_time is None or res.end_time is None:
-            return
-        
-        start_time = res.start_time.replace(year = selected_date.year,
-                                            month = selected_date.month,
-                                            day = selected_date.day)
-        end_time = res.end_time.replace(year = selected_date.year,
-                                               month = selected_date.month,
-                                               day = selected_date.day)
-    
-        activity_name = res.activity_name
-        if res.category_name:
-            activity_name += "@%s" % res.category_name
-            
-        if res.description:
-            activity_name += ", %s" % res.description
-
-        activity_name = activity_name.decode("utf-8")
+            self.stats.stats(year)
+        elif pagenum == 1:
+            self.reports.do_graph()
 
-        # TODO - set cursor to the pasted entry when done
-        # TODO - revisit parsing of selected date
-        added_fact = runtime.storage.add_fact(activity_name, start_time, end_time)
-        
-
-    """keyboard events"""
-    def on_key_pressed(self, tree, event):
-        if (event.keyval == gtk.keysyms.Delete):
-            self.delete_selected()
-        elif event.keyval == gtk.keysyms.c and event.state & gtk.gdk.CONTROL_MASK:
-            self.copy_selected()
-        elif event.keyval == gtk.keysyms.v and event.state & gtk.gdk.CONTROL_MASK:
-            self.check_clipboard()
-    
-    def on_fact_selection_changed(self, selection, model):
-        """ enables and disables action buttons depending on selected item """
-        (model, iter) = selection.get_selected()
-
-        id = -1
-        if iter:
-            id = model[iter][0]
-
-        self.get_widget('remove').set_sensitive(id != -1)
-        self.get_widget('edit').set_sensitive(id != -1)
-
-        return True
-
-    def on_facts_row_activated(self, tree, path, column):
-        selection = tree.get_selection()
-        (model, iter) = selection.get_selected()
-        custom_fact = CustomFactController(self, None, model[iter][0])
-        custom_fact.show()
-        
-    def on_add_clicked(self, button):
-        selection = self.fact_tree.get_selection()
-        (model, iter) = selection.get_selected()
-
-        selected_date = self.view_date
-        if iter:
-            selected_date = model[iter][3].split("-")
-            selected_date = dt.date(int(selected_date[0]),
-                                    int(selected_date[1]),
-                                    int(selected_date[2]))
-
-        custom_fact = CustomFactController(self, selected_date)
-        custom_fact.show()
-        
-    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, start_date, end_date,
-                                                                    categories):
-        self.report_chooser = None
-        
-        facts = runtime.storage.get_facts(start_date, end_date, category_id = categories)
-        reports.simple(facts,
-                       start_date,
-                       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 after_activity_update(self, widget, renames):
-        self.do_graph()
-    
-    def after_fact_update(self, event, date):
-        self.stat_facts = runtime.storage.get_facts(dt.date(1970, 1, 1), dt.date.today())
-        self.popular_categories = [cat[0] for cat in runtime.storage.get_popular_categories()]
-        
-        if self.get_widget("pages").get_current_page() == 0:
-            self.do_graph()
-        else:
-            self.stats()
-        
     def on_close(self, widget, event):
         runtime.dispatcher.del_handler('activity_updated',
                                        self.after_activity_update)
diff --git a/hamster/stats_overview.py b/hamster/stats_overview.py
new file mode 100644
index 0000000..ea356da
--- /dev/null
+++ b/hamster/stats_overview.py
@@ -0,0 +1,204 @@
+# - coding: utf-8 -
+
+# Copyright (C) 2008-2009 Toms Bauģis <toms.baugis at gmail.com>
+
+# This file is part of Project Hamster.
+
+# Project Hamster is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# Project Hamster is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with Project Hamster.  If not, see <http://www.gnu.org/licenses/>.
+
+
+import pygtk
+pygtk.require('2.0')
+
+import os
+import gtk, gobject
+import pango
+
+import stuff
+import charting
+
+from edit_activity import CustomFactController
+import reports, graphics
+
+import widgets
+
+from configuration import runtime, GconfStore
+import webbrowser
+
+from itertools import groupby
+from gettext import ngettext
+
+import datetime as dt
+import calendar
+import time
+from hamster.i18n import C_
+
+
+
+class OverviewBox(gtk.VBox):
+    def __init__(self):
+        gtk.VBox.__init__(self)
+        
+        self._gui = stuff.load_ui_file("stats_overview.ui")
+
+        
+        self.get_widget("overview_box").reparent(self) #mine!
+
+
+
+        self.view_date = dt.date.today()
+        
+        #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())
+        
+        self.end_date = self.start_date + dt.timedelta(6)
+
+
+
+        facts_tree = widgets.FactTree()
+        self.get_widget("overview_facts_box").add(facts_tree)
+        
+        facts = runtime.storage.get_facts(self.start_date, self.end_date)
+
+
+        #create list of all required dates
+        dates = [(self.start_date + dt.timedelta(i), []) for i in range((self.end_date - self.start_date).days  + 1)]
+        
+        #update with facts for the day
+        for date, facts in groupby(facts, lambda fact: fact["date"]):
+            dates[dates.index((date, []))] = (date, list(facts))
+
+        # push them in tree
+        for date, facts in dates:
+            fact_date = date.strftime(C_("overview list", "%A, %b %d"))
+
+            facts_tree.add_group(fact_date, facts)
+
+    def on_remove_clicked(self, button):
+        self.delete_selected()
+
+    def on_edit_clicked(self, button):
+        selection = self.fact_tree.get_selection()
+        (model, iter) = selection.get_selected()
+
+        if model[iter][0] == -1:
+            return #not a fact
+
+        custom_fact = CustomFactController(self, None, model[iter][0])
+        custom_fact.show()
+
+    def delete_selected(self):
+        selection = self.fact_tree.get_selection()
+        (model, iter) = selection.get_selected()
+
+        if model[iter][0] == -1:
+            return #not a fact
+
+        next_row = model.iter_next(iter)
+
+        if next_row:
+            selection.select_iter(next_row)
+        else:
+            path = model.get_path(iter)[0] - 1
+            if path > 0:
+                selection.select_path(path)
+
+        runtime.storage.remove_fact(model[iter][0])
+
+    def copy_selected(self):
+        selection = self.fact_tree.get_selection()
+        (model, iter) = selection.get_selected()
+
+        fact = model[iter][6]
+        if not fact:
+            return #not a fact
+
+        fact_str = "%s-%s %s" % (fact["start_time"].strftime("%H:%M"),
+                               (fact["end_time"] or dt.datetime.now()).strftime("%H:%M"),
+                               fact["name"])
+
+        if fact["category"]:
+            fact_str += "@%s" % fact["category"]
+
+        if fact["description"]:
+            fact_str += ", %s" % fact["description"]
+
+        clipboard = gtk.Clipboard()
+        clipboard.set_text(fact_str)
+    
+    def check_clipboard(self):
+        clipboard = gtk.Clipboard()
+        clipboard.request_text(self.on_clipboard_text)
+    
+    def on_clipboard_text(self, clipboard, text, data):
+        # first check that we have a date selected
+        selection = self.fact_tree.get_selection()
+        (model, iter) = selection.get_selected()
+
+        selected_date = self.view_date
+        if iter:
+            selected_date = model[iter][3].split("-")
+            selected_date = dt.date(int(selected_date[0]),
+                                    int(selected_date[1]),
+                                    int(selected_date[2]))
+        if not selected_date:
+            return
+        
+        res = stuff.parse_activity_input(text)
+
+        if res.start_time is None or res.end_time is None:
+            return
+        
+        start_time = res.start_time.replace(year = selected_date.year,
+                                            month = selected_date.month,
+                                            day = selected_date.day)
+        end_time = res.end_time.replace(year = selected_date.year,
+                                               month = selected_date.month,
+                                               day = selected_date.day)
+    
+        activity_name = res.activity_name
+        if res.category_name:
+            activity_name += "@%s" % res.category_name
+            
+        if res.description:
+            activity_name += ", %s" % res.description
+
+        activity_name = activity_name.decode("utf-8")
+
+        # TODO - set cursor to the pasted entry when done
+        # TODO - revisit parsing of selected date
+        added_fact = runtime.storage.add_fact(activity_name, start_time, end_time)
+        
+
+    """keyboard events"""
+    def on_key_pressed(self, tree, event):
+        if (event.keyval == gtk.keysyms.Delete):
+            self.delete_selected()
+        elif event.keyval == gtk.keysyms.c and event.state & gtk.gdk.CONTROL_MASK:
+            self.copy_selected()
+        elif event.keyval == gtk.keysyms.v and event.state & gtk.gdk.CONTROL_MASK:
+            self.check_clipboard()
+    
+
+    def get_widget(self, name):
+        """ skip one variable (huh) """
+        return self._gui.get_object(name)
+
+
+
+
diff --git a/hamster/stats_reports.py b/hamster/stats_reports.py
new file mode 100644
index 0000000..c20487e
--- /dev/null
+++ b/hamster/stats_reports.py
@@ -0,0 +1,612 @@
+# - coding: utf-8 -
+
+# Copyright (C) 2008-2009 Toms Bauģis <toms.baugis at gmail.com>
+
+# This file is part of Project Hamster.
+
+# Project Hamster is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# Project Hamster is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with Project Hamster.  If not, see <http://www.gnu.org/licenses/>.
+
+
+import pygtk
+pygtk.require('2.0')
+
+import os
+import gtk, gobject
+import pango
+
+import stuff
+import charting
+
+from edit_activity import CustomFactController
+import reports, graphics
+
+import widgets
+
+from configuration import runtime, GconfStore
+import webbrowser
+
+from itertools import groupby
+from gettext import ngettext
+
+import datetime as dt
+import calendar
+import time
+from hamster.i18n import C_
+
+
+
+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.view_date = dt.date.today()
+        
+        #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())
+        
+        self.end_date = self.start_date + dt.timedelta(6)
+
+
+
+        self.fact_store = gtk.TreeStore(int, str, str, str, str, str, gobject.TYPE_PYOBJECT) 
+        self.setup_tree()
+        
+        
+        #graphs
+        self.background = (0.975, 0.975, 0.975)
+        self.get_widget("graph_frame").modify_bg(gtk.STATE_NORMAL,
+                      gtk.gdk.Color(*[int(b*65536.0) for b in self.background]))
+
+
+        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.get_widget("totals_by_activity").add(self.activity_chart);
+
+        
+        
+        self.week_view = self.get_widget("reports_week_view")
+        self.month_view = self.get_widget("reports_month_view")
+        self.month_view.set_group(self.week_view)
+        self.day_view = self.get_widget("reports_day_view")
+        self.day_view.set_group(self.week_view)
+        
+        #initiate the form in the week view
+        self.week_view.set_active(True)
+
+
+        runtime.dispatcher.add_handler('activity_updated', self.after_activity_update)
+        runtime.dispatcher.add_handler('day_updated', self.after_fact_update)
+
+        selection = self.fact_tree.get_selection()
+        selection.connect('changed', self.on_fact_selection_changed,
+                          self.fact_store)
+        self.popular_categories = [cat[0] for cat in runtime.storage.get_popular_categories()]
+
+        self._gui.connect_signals(self)
+        self.fact_tree.grab_focus()
+
+        
+        self.config = GconfStore()
+        runtime.dispatcher.add_handler('gconf_on_day_start_changed', self.on_day_start_changed)
+
+        self.report_chooser = None
+        self.do_graph()
+
+    def setup_tree(self):
+        def parent_painter(column, cell, model, iter):
+            cell_text = model.get_value(iter, 1)
+            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:
+                activity_name = stuff.escape_pango(cell_text)
+                description = stuff.escape_pango(model.get_value(iter, 4))
+                category = stuff.escape_pango(model.get_value(iter, 5))
+
+                markup = stuff.format_activity(activity_name,
+                                               category,
+                                               description,
+                                               pad_description = True)            
+                cell.set_property('markup', markup)
+
+        def duration_painter(column, cell, model, iter):
+            cell.set_property('xalign', 1)
+            cell.set_property('yalign', 0)
+    
+
+            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)
+    
+
+        self.fact_tree = self.get_widget("facts")
+        self.fact_tree.set_headers_visible(False)
+        self.fact_tree.set_tooltip_column(1)
+        self.fact_tree.set_property("show-expanders", False)
+
+        # name
+        nameColumn = gtk.TreeViewColumn()
+        nameColumn.set_expand(True)
+        nameCell = gtk.CellRendererText()
+        nameCell.set_property("ellipsize", pango.ELLIPSIZE_END)
+        nameColumn.pack_start(nameCell, True)
+        nameColumn.set_cell_data_func(nameCell, parent_painter)
+        self.fact_tree.append_column(nameColumn)
+
+        # duration
+        timeColumn = gtk.TreeViewColumn()
+        timeCell = gtk.CellRendererText()
+        timeColumn.pack_end(timeCell, True)
+        timeColumn.set_cell_data_func(timeCell, duration_painter)
+
+
+
+
+        self.fact_tree.append_column(timeColumn)
+        
+        self.fact_tree.set_model(self.fact_store)
+    
+    def on_graph_frame_size_allocate(self, widget, new_size):
+        w = min(new_size.width / 4, 200)
+        
+        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 fill_tree(self, facts):
+        day_dict = {}
+        for day, facts in groupby(facts, lambda fact: fact["date"]):
+            day_dict[day] = sorted(list(facts),
+                                   key=lambda fact: fact["start_time"])
+        
+        for i in range((self.end_date - self.start_date).days  + 1):
+            current_date = self.start_date + dt.timedelta(i)
+            
+            # Date format for the label in overview window fact listing
+            # Using python datetime formatting syntax. See:
+            # http://docs.python.org/library/time.html#time.strftime
+            fact_date = current_date.strftime(C_("overview list", "%A, %b %d"))
+            
+            day_total = dt.timedelta()
+            for fact in day_dict.get(current_date, []):
+                day_total += fact["delta"]
+
+            day_row = self.fact_store.append(None,
+                                             [-1,
+                                              fact_date,
+                                              stuff.format_duration(day_total),
+                                              current_date.strftime('%Y-%m-%d'),
+                                              "",
+                                              "",
+                                              None])
+
+            for fact in day_dict.get(current_date, []):
+                self.fact_store.append(day_row,
+                                       [fact["id"],
+                                        fact["start_time"].strftime('%H:%M') + " " +
+                                        fact["name"],
+                                        stuff.format_duration(fact["delta"]),
+                                        fact["start_time"].strftime('%Y-%m-%d'),
+                                        fact["description"],
+                                        fact["category"],
+                                        fact
+                                        ])
+
+        self.fact_tree.expand_all()
+
+        
+    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)]
+        
+        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]
+        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 set_title(self):
+        if self.day_view.get_active():
+            # date format for overview label when only single day is visible
+            # Using python datetime formatting syntax. See:
+            # http://docs.python.org/library/time.html#time.strftime
+            start_date_str = self.view_date.strftime(C_("single day overview",
+                                                        "%B %d, %Y"))
+            # Overview label if looking on single day
+            overview_label = _(u"Overview for %(date)s") % \
+                                                      ({"date": start_date_str})
+        else:
+            dates_dict = stuff.dateDict(self.start_date, "start_")
+            dates_dict.update(stuff.dateDict(self.end_date, "end_"))
+            
+            if self.start_date.year != self.end_date.year:
+                # overview label if start and end years don't match
+                # letter after prefixes (start_, end_) is the one of
+                # standard python date formatting ones- you can use all of them
+                # see http://docs.python.org/library/time.html#time.strftime
+                overview_label = _(u"Overview for %(start_B)s %(start_d)s, %(start_Y)s â?? %(end_B)s %(end_d)s, %(end_Y)s") % dates_dict
+            elif self.start_date.month != self.end_date.month:
+                # overview label if start and end month do not match
+                # letter after prefixes (start_, end_) is the one of
+                # standard python date formatting ones- you can use all of them
+                # see http://docs.python.org/library/time.html#time.strftime
+                overview_label = _(u"Overview for %(start_B)s %(start_d)s â?? %(end_B)s %(end_d)s, %(end_Y)s") % dates_dict
+            else:
+                # overview label for interval in same month
+                # letter after prefixes (start_, end_) is the one of
+                # standard python date formatting ones- you can use all of them
+                # see http://docs.python.org/library/time.html#time.strftime
+                overview_label = _(u"Overview for %(start_B)s %(start_d)s â?? %(end_d)s, %(end_Y)s") % dates_dict
+
+        if self.week_view.get_active():
+            dayview_caption = _("Week")
+        elif self.month_view.get_active():
+            dayview_caption = _("Month")
+        else:
+            dayview_caption = _("Day")
+        
+        self.get_widget("overview_label").set_markup("<b>%s</b>" % overview_label)
+        self.get_widget("dayview_caption").set_markup("%s" % (dayview_caption))
+        
+
+    def do_graph(self):
+        self.set_title()
+        
+        if self.day_view.get_active():
+            facts = runtime.storage.get_facts(self.view_date)
+        else:
+            facts = runtime.storage.get_facts(self.start_date, self.end_date)
+
+
+        self.get_widget("report_button").set_sensitive(len(facts) > 0)
+        self.fact_store.clear()
+        
+        self.fill_tree(facts)
+
+        if not facts:
+            self.get_widget("graphs").hide()
+            self.get_widget("no_data_label").show()
+            return 
+
+
+        self.get_widget("no_data_label").hide()
+        self.get_widget("graphs").show()
+        self.do_charts(facts)
+            
+
+
+
+
+    def get_widget(self, name):
+        """ skip one variable (huh) """
+        return self._gui.get_object(name)
+
+
+
+
+    def after_activity_update(self, widget, renames):
+        self.do_graph()
+    
+    def after_fact_update(self, event, date):
+        self.stat_facts = runtime.storage.get_facts(dt.date(1970, 1, 1), dt.date.today())
+        self.popular_categories = [cat[0] for cat in runtime.storage.get_popular_categories()]
+        
+        if self.get_widget("pages").get_current_page() == 0:
+            self.do_graph()
+        else:
+            self.stats()
+        
+    def on_fact_selection_changed(self, selection, model):
+        """ enables and disables action buttons depending on selected item """
+        (model, iter) = selection.get_selected()
+
+        id = -1
+        if iter:
+            id = model[iter][0]
+
+        self.get_widget('remove').set_sensitive(id != -1)
+        self.get_widget('edit').set_sensitive(id != -1)
+
+        return True
+
+    def on_facts_row_activated(self, tree, path, column):
+        selection = tree.get_selection()
+        (model, iter) = selection.get_selected()
+        custom_fact = CustomFactController(self, None, model[iter][0])
+        custom_fact.show()
+        
+    def on_add_clicked(self, button):
+        selection = self.fact_tree.get_selection()
+        (model, iter) = selection.get_selected()
+
+        selected_date = self.view_date
+        if iter:
+            selected_date = model[iter][3].split("-")
+            selected_date = dt.date(int(selected_date[0]),
+                                    int(selected_date[1]),
+                                    int(selected_date[2]))
+
+        custom_fact = CustomFactController(self, selected_date)
+        custom_fact.show()
+
+    def on_prev_clicked(self, button):
+        if self.day_view.get_active():
+            self.view_date -= dt.timedelta(1)
+            if self.view_date < self.start_date:
+                self.start_date -= dt.timedelta(7)
+                self.end_date -= dt.timedelta(7)
+        else:
+            if self.week_view.get_active():
+                self.start_date -= dt.timedelta(7)
+                self.end_date -= dt.timedelta(7)
+            
+            elif self.month_view.get_active():
+                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)
+
+            self.view_date = self.start_date
+
+        self.do_graph()
+
+    def on_next_clicked(self, button):
+        if self.day_view.get_active():
+            self.view_date += dt.timedelta(1)
+            if self.view_date > self.end_date:
+                self.start_date += dt.timedelta(7)
+                self.end_date += dt.timedelta(7)
+        else:
+            if self.week_view.get_active():
+                self.start_date += dt.timedelta(7)
+                self.end_date += dt.timedelta(7)        
+            elif self.month_view.get_active():
+                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)
+        
+            self.view_date = self.start_date
+
+        self.do_graph()
+    
+    def on_home_clicked(self, button):
+        self.view_date = dt.date.today()
+        if self.week_view.get_active():
+            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.month_view.get_active():
+            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)
+        
+        self.do_graph()
+        
+    def on_day_toggled(self, button):
+        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)
+        
+        self.get_widget("prev").set_tooltip_text(_("Previous day"))
+        self.get_widget("next").set_tooltip_text(_("Next day"))
+        self.get_widget("home").set_tooltip_text(_("Today"))
+        self.get_widget("home").set_label(_("Today"))
+        
+        self.do_graph()
+
+    def on_week_toggled(self, button):
+        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)
+
+        self.get_widget("prev").set_tooltip_text(_("Previous week"))
+        self.get_widget("next").set_tooltip_text(_("Next week"))
+        self.get_widget("home").set_tooltip_text(_("This week"))
+        self.get_widget("home").set_label(_("This Week"))
+        self.do_graph()
+
+        
+    def on_month_toggled(self, button):
+        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)
+
+        self.get_widget("prev").set_tooltip_text(_("Previous month"))
+        self.get_widget("next").set_tooltip_text(_("Next month"))
+        self.get_widget("home").set_tooltip_text(_("This month"))
+        self.get_widget("home").set_label(_("This Month"))
+        self.do_graph()
+        
+        
+    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, start_date, end_date,
+                                                                    categories):
+        self.report_chooser = None
+        
+        facts = runtime.storage.get_facts(start_date, end_date, category_id = categories)
+        reports.simple(facts,
+                       start_date,
+                       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()
+
diff --git a/hamster/stats_stats.py b/hamster/stats_stats.py
new file mode 100644
index 0000000..10988c1
--- /dev/null
+++ b/hamster/stats_stats.py
@@ -0,0 +1,416 @@
+# - coding: utf-8 -
+
+# Copyright (C) 2008-2009 Toms Bauģis <toms.baugis at gmail.com>
+
+# This file is part of Project Hamster.
+
+# Project Hamster is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# Project Hamster is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with Project Hamster.  If not, see <http://www.gnu.org/licenses/>.
+
+
+import pygtk
+pygtk.require('2.0')
+
+import os
+import gtk, gobject
+import pango
+
+import stuff
+import charting
+
+from edit_activity import CustomFactController
+import reports, graphics
+
+import widgets
+
+from configuration import runtime, GconfStore
+import webbrowser
+
+from itertools import groupby
+from gettext import ngettext
+
+import datetime as dt
+import calendar
+import time
+from hamster.i18n import C_
+
+
+
+class StatsBox(gtk.VBox):
+    def __init__(self):
+        gtk.VBox.__init__(self)
+        
+        self._gui = stuff.load_ui_file("stats_stats.ui")
+        self.get_widget("stats_box").reparent(self) #mine!
+        
+        self.background = (0.975, 0.975, 0.975)
+        self.get_widget("explore_frame").modify_bg(gtk.STATE_NORMAL,
+                      gtk.gdk.Color(*[int(b*65536.0) for b in self.background]))
+
+        self.stat_facts = None
+
+        self.timeline = widgets.TimeLine()
+        self.get_widget("explore_everything").add(self.timeline)
+        self.get_widget("explore_everything").show_all()
+
+
+        self.init_stats()
+
+
+
+    def init_stats(self):
+        self.stat_facts = runtime.storage.get_facts(dt.date(1970, 1, 1), dt.date.today())
+        
+        by_year = stuff.totals(self.stat_facts,
+                               lambda fact: fact["start_time"].year,
+                               lambda fact: 1)
+        
+        year_box = self.get_widget("year_box")
+        class YearButton(gtk.ToggleButton):
+            def __init__(self, label, year, on_clicked):
+                gtk.ToggleButton.__init__(self, label)
+                self.year = year
+                self.connect("clicked", on_clicked)
+        
+        all_button = YearButton(C_("years", "All").encode("utf-8"),
+                                None,
+                                self.on_year_changed)
+        year_box.pack_start(all_button)
+        self.bubbling = True # TODO figure out how to properly work with togglebuttons as radiobuttons
+        all_button.set_active(True)
+        self.bubbling = False # TODO figure out how to properly work with togglebuttons as radiobuttons
+
+        years = sorted(by_year.keys())
+        for year in years:
+            year_box.pack_start(YearButton(str(year), year, self.on_year_changed))
+
+        year_box.show_all()
+
+        self.chart_category_totals = charting.HorizontalBarChart(value_format = "%.1f",
+                                                            bars_beveled = False,
+                                                            background = self.background,
+                                                            max_bar_width = 20,
+                                                            legend_width = 70)
+        self.get_widget("explore_category_totals").add(self.chart_category_totals)
+
+
+        self.chart_weekday_totals = charting.HorizontalBarChart(value_format = "%.1f",
+                                                            bars_beveled = False,
+                                                            background = self.background,
+                                                            max_bar_width = 20,
+                                                            legend_width = 70)
+        self.get_widget("explore_weekday_totals").add(self.chart_weekday_totals)
+
+        self.chart_weekday_starts_ends = charting.HorizontalDayChart(bars_beveled = False,
+                                                                animate = False,
+                                                                background = self.background,
+                                                                max_bar_width = 20,
+                                                                legend_width = 70)
+        self.get_widget("explore_weekday_starts_ends").add(self.chart_weekday_starts_ends)
+        
+        self.chart_category_starts_ends = charting.HorizontalDayChart(bars_beveled = False,
+                                                                animate = False,
+                                                                background = self.background,
+                                                                max_bar_width = 20,
+                                                                legend_width = 70)
+        self.get_widget("explore_category_starts_ends").add(self.chart_category_starts_ends)
+
+
+        #ah, just want summary look just like all the other text on the page
+        class CairoText(graphics.Area):
+            def __init__(self, background = None, fontsize = 10):
+                graphics.Area.__init__(self)
+                self.background = background
+                self.text = ""
+                self.fontsize = fontsize
+                
+            def set_text(self, text):
+                self.text = text
+                self.redraw_canvas()
+                
+            def on_expose(self):
+                if self.background:
+                    self.fill_area(0, 0, self.width, self.height, self.background)
+
+                default_font = pango.FontDescription(gtk.Style().font_desc.to_string())
+                default_font.set_size(self.fontsize * pango.SCALE)
+                self.layout.set_font_description(default_font)
+                
+                #self.context.set_source_rgb(0,0,0)
+                self.layout.set_markup(self.text)
+
+                self.layout.set_width((self.width) * pango.SCALE)
+                self.context.move_to(0,0)
+                self.set_color(charting.graphics.Colors.aluminium[5])
+                
+                self.context.show_layout(self.layout)
+
+        self.explore_summary = CairoText(self.background)
+        self.get_widget("explore_summary").add(self.explore_summary)
+        self.get_widget("explore_summary").show_all()
+
+    def stats(self, year = None):
+        facts = self.stat_facts
+        if year:
+            facts = filter(lambda fact: fact["start_time"].year == year,
+                           facts)
+
+        if not facts or (facts[-1]["start_time"] - facts[0]["start_time"]) < dt.timedelta(days=6):
+            self.get_widget("statistics_box").hide()
+            self.get_widget("explore_controls").hide()
+            label = self.get_widget("not_enough_records_label")
+
+            if not facts:
+                label.set_text(_("""There is no data to generate statistics yet.
+A week of usage would be nice!"""))
+            else:
+                label.set_text(_("Still collecting data â?? check back after a week has passed!"))
+
+            label.show()
+            return
+        else:
+            self.get_widget("statistics_box").show()
+            self.get_widget("explore_controls").show()
+            self.get_widget("not_enough_records_label").hide()
+
+        # All dates in the scope
+        self.timeline.draw(facts)
+
+
+        # Totals by category
+        categories = stuff.totals(facts,
+                                  lambda fact: fact["category"],
+                                  lambda fact: fact['delta'].seconds / 60 / 60.0)
+        category_keys = sorted(categories.keys())
+        categories = [categories[key] for key in category_keys]
+        self.chart_category_totals.plot(category_keys, categories)
+        
+        # Totals by weekday
+        weekdays = stuff.totals(facts,
+                                lambda fact: (fact["start_time"].weekday(),
+                                              fact["start_time"].strftime("%a")),
+                                lambda fact: fact['delta'].seconds / 60 / 60.0)
+        
+        weekday_keys = sorted(weekdays.keys(), key = lambda x: x[0]) #sort 
+        weekdays = [weekdays[key] for key in weekday_keys] #get values in the order
+        weekday_keys = [key[1] for key in weekday_keys] #now remove the weekday and keep just the abbreviated one
+        self.chart_weekday_totals.plot(weekday_keys, weekdays)
+
+
+        split_minutes = 5 * 60 + 30 #the mystical hamster midnight
+        
+        # starts and ends by weekday
+        by_weekday = {}
+        for date, date_facts in groupby(facts, lambda fact: fact["start_time"].date()):
+            date_facts = list(date_facts)
+            weekday = (date_facts[0]["start_time"].weekday(),
+                       date_facts[0]["start_time"].strftime("%a"))
+            by_weekday.setdefault(weekday, [])
+            
+            start_times, end_times = [], []
+            for fact in date_facts:
+                start_time = fact["start_time"].time()
+                start_time = start_time.hour * 60 + start_time.minute
+                if fact["end_time"]:
+                    end_time = fact["end_time"].time()
+                    end_time = end_time.hour * 60 + end_time.minute
+                
+                    if start_time < split_minutes:
+                        start_time += 24 * 60
+                    if end_time < start_time:
+                        end_time += 24 * 60
+                    
+                    start_times.append(start_time)
+                    end_times.append(end_time)
+            if start_times and end_times:            
+                by_weekday[weekday].append((min(start_times), max(end_times)))
+
+
+        for day in by_weekday:
+            by_weekday[day] = (sum([fact[0] for fact in by_weekday[day]]) / len(by_weekday[day]),
+                               sum([fact[1] for fact in by_weekday[day]]) / len(by_weekday[day]))
+
+        min_weekday = min([by_weekday[day][0] for day in by_weekday])
+        max_weekday = max([by_weekday[day][1] for day in by_weekday])
+
+
+        weekday_keys = sorted(by_weekday.keys(), key = lambda x: x[0])
+        weekdays = [by_weekday[key] for key in weekday_keys]
+        weekday_keys = [key[1] for key in weekday_keys] # get rid of the weekday number as int
+
+        
+        # starts and ends by category
+        by_category = {}
+        for date, date_facts in groupby(facts, lambda fact: fact["start_time"].date()):
+            date_facts = sorted(list(date_facts), key = lambda x: x["category"])
+            
+            for category, category_facts in groupby(date_facts, lambda x: x["category"]):
+                category_facts = list(category_facts)
+                by_category.setdefault(category, [])
+                
+                start_times, end_times = [], []
+                for fact in category_facts:
+                    start_time = fact["start_time"]
+                    start_time = start_time.hour * 60 + start_time.minute
+                    if fact["end_time"]:
+                        end_time = fact["end_time"].time()
+                        end_time = end_time.hour * 60 + end_time.minute
+                        
+                        if start_time < split_minutes:
+                            start_time += 24 * 60
+                        if end_time < start_time:
+                            end_time += 24 * 60
+
+                        start_times.append(start_time)
+                        end_times.append(end_time)
+
+                if start_times and end_times:            
+                    by_category[category].append((min(start_times), max(end_times)))
+
+        for cat in by_category:
+            by_category[cat] = (sum([fact[0] for fact in by_category[cat]]) / len(by_category[cat]),
+                                sum([fact[1] for fact in by_category[cat]]) / len(by_category[cat]))
+
+        min_category = min([by_category[day][0] for day in by_category])
+        max_category = max([by_category[day][1] for day in by_category])
+
+        category_keys = sorted(by_category.keys(), key = lambda x: x[0])
+        categories = [by_category[key] for key in category_keys]
+
+
+        #get starting and ending hours for graph and turn them into exact hours that divide by 3
+        min_hour = min([min_weekday, min_category]) / 60 * 60
+        max_hour = max([max_weekday, max_category]) / 60 * 60
+
+        self.chart_weekday_starts_ends.plot_day(weekday_keys, weekdays, min_hour, max_hour)
+        self.chart_category_starts_ends.plot_day(category_keys, categories, min_hour, max_hour)
+
+
+        #now the factoids!
+        summary = ""
+
+        # first record        
+        if not year:
+            # date format for the first record if the year has not been selected
+            # Using python datetime formatting syntax. See:
+            # http://docs.python.org/library/time.html#time.strftime
+            first_date = facts[0]["start_time"].strftime(C_("first record", "%b %d, %Y"))
+        else:
+            # date of first record when year has been selected
+            # Using python datetime formatting syntax. See:
+            # http://docs.python.org/library/time.html#time.strftime
+            first_date = facts[0]["start_time"].strftime(C_("first record", "%b %d"))
+
+        summary += _("First activity was recorded on %s.") % \
+                                                     ("<b>%s</b>" % first_date)
+        
+        # total time tracked
+        total_delta = dt.timedelta(days=0)
+        for fact in facts:
+            total_delta += fact["delta"]
+        
+        if total_delta.days > 1:
+            human_years_str = ngettext("%(num)s year",
+                                       "%(num)s years",
+                                       total_delta.days / 365) % {
+                              'num': "<b>%.2f</b>" % (total_delta.days / 365.0)}
+            working_years_str = ngettext("%(num)s year",
+                                         "%(num)s years",
+                                         total_delta.days * 3 / 365) % {
+                         'num': "<b>%.2f</b>" % (total_delta.days * 3 / 365.0) }
+            #FIXME: difficult string to properly pluralize
+            summary += " " + _("""Time tracked so far is %(human_days)s human days \
+(%(human_years)s) or %(working_days)s working days (%(working_years)s).""") % {
+              "human_days": ("<b>%d</b>" % total_delta.days),
+              "human_years": human_years_str,
+              "working_days": ("<b>%d</b>" % (total_delta.days * 3)), # 8 should be pretty much an average working day
+              "working_years": working_years_str }
+        
+
+        # longest fact
+        max_fact = None
+        for fact in facts:
+            if not max_fact or fact["delta"] > max_fact["delta"]:
+                max_fact = fact
+
+        longest_date = max_fact["start_time"].strftime(
+            # How the date of the longest activity should be displayed in statistics
+            # Using python datetime formatting syntax. See:
+            # http://docs.python.org/library/time.html#time.strftime
+            C_("date of the longest activity", "%b %d, %Y"))
+        
+        num_hours = max_fact["delta"].seconds / 60 / 60.0 + max_fact["delta"].days * 24
+        hours = "<b>%.1f</b>" % (num_hours)
+        
+        summary += "\n" + ngettext("Longest continuous work happened on \
+%(date)s and was %(hours)s hour.",
+                                  "Longest continuous work happened on \
+%(date)s and was %(hours)s hours.",
+                                  int(num_hours)) % {"date": longest_date,
+                                                     "hours": hours}
+
+        # total records (in selected scope)
+        summary += " " + ngettext("There is %s record.",
+                                  "There are %s records.",
+                                  len(facts)) % ("<b>%d</b>" % len(facts))
+
+
+        early_start, early_end = dt.time(5,0), dt.time(9,0)
+        late_start, late_end = dt.time(20,0), dt.time(5,0)
+        
+        
+        fact_count = len(facts)
+        def percent(condition):
+            matches = [fact for fact in facts if condition(fact)]
+            return round(len(matches) / float(fact_count) * 100)
+        
+        
+        early_percent = percent(lambda fact: early_start < fact["start_time"].time() < early_end)
+        late_percent = percent(lambda fact: fact["start_time"].time() > late_start or fact["start_time"].time() < late_end)
+        short_percent = percent(lambda fact: fact["delta"] <= dt.timedelta(seconds = 60 * 15))
+
+        if fact_count < 100:
+            summary += "\n\n" + _("Hamster would like to observe you some more!")
+        elif early_percent >= 20:
+            summary += "\n\n" + _("With %s percent of all facts starting before \
+9am you seem to be an early bird." % ("<b>%d</b>" % early_percent))
+        elif late_percent >= 20:
+            summary += "\n\n" + _("With %s percent of all facts starting after \
+11pm you seem to be a night owl." % ("<b>%d</b>" % late_percent))
+        elif short_percent >= 20:
+            summary += "\n\n" + _("With %s percent of all tasks being shorter \
+than 15 minutes you seem to be a busy bee." % ("<b>%d</b>" % short_percent))
+
+        self.explore_summary.set_text(summary)
+
+
+        
+    def on_year_changed(self, button):
+        if self.bubbling: return
+        
+        for child in button.parent.get_children():
+            if child != button and child.get_active():
+                self.bubbling = True
+                child.set_active(False)
+                self.bubbling = False
+        
+        self.stats(button.year)
+
+
+    def get_widget(self, name):
+        """ skip one variable (huh) """
+        return self._gui.get_object(name)
+
+
+
+
diff --git a/hamster/widgets/facttree.py b/hamster/widgets/facttree.py
new file mode 100644
index 0000000..b44c7c5
--- /dev/null
+++ b/hamster/widgets/facttree.py
@@ -0,0 +1,189 @@
+# - coding: utf-8 -
+
+# Copyright (C) 2008-2009 Toms Bauģis <toms.baugis at gmail.com>
+
+# This file is part of Project Hamster.
+
+# Project Hamster is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# Project Hamster is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with Project Hamster.  If not, see <http://www.gnu.org/licenses/>.
+
+import gtk, gobject
+import datetime as dt
+
+from hamster.configuration import runtime
+
+from hamster import stuff
+from hamster.stuff import format_duration, format_activity
+from tags import TagCellRenderer
+
+import pango
+
+class ActivityColumn(gtk.TreeViewColumn):
+    def __init__(self, name, description, category = None):
+        gtk.TreeViewColumn.__init__(self)
+        
+        self.name, self.description, self.category = name, description, category
+        self.set_expand(True)
+        cell = gtk.CellRendererText()
+        self.pack_start(cell, True)
+        cell.set_property("ellipsize", pango.ELLIPSIZE_END)
+        self.set_cell_data_func(cell, self.activity_painter)
+
+    def activity_painter(self, column, cell, model, iter):
+        activity_name = model.get_value(iter, self.name)
+        description = model.get_value(iter, self.description)
+        category = model.get_value(iter, self.category)
+        
+        markup = format_activity(activity_name, category, description)            
+        cell.set_property('markup', markup)
+        return
+
+def parent_painter(column, cell, model, iter):
+    cell_text = model.get_value(iter, 1)
+    
+    if model.get_value(iter, 6) 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:
+        activity_name = stuff.escape_pango(cell_text)
+        description = stuff.escape_pango(model.get_value(iter, 4))
+        category = stuff.escape_pango(model.get_value(iter, 5))
+
+        markup = stuff.format_activity(activity_name,
+                                       category,
+                                       description,
+                                       pad_description = True)            
+        cell.set_property('markup', markup)
+
+def duration_painter(column, cell, model, iter):
+    cell.set_property('xalign', 1)
+
+
+    text = model.get_value(iter, 2)
+    if model.get_value(iter, 6) 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)
+
+def action_painter(column, cell, model, iter):
+    cell.set_property('xalign', 1)
+
+
+    text = model.get_value(iter, 2)
+    if model.get_value(iter, 6) is None:
+        cell.set_property("stock_id", "")
+    else:
+        cell.set_property("stock_id", "gtk-edit")
+
+
+class FactTree(gtk.TreeView):
+    __gsignals__ = {
+        'value-entered': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()),
+    }
+
+
+    def __init__(self):
+        gtk.TreeView.__init__(self)
+        
+        self.set_headers_visible(False)
+        self.set_show_expanders(False)
+
+        #id, caption, duration, date (invisible), description, category
+        self.set_model(gtk.TreeStore(int, str, str, str, str, str, gobject.TYPE_PYOBJECT))
+
+
+        # name
+        nameColumn = gtk.TreeViewColumn()
+        nameColumn.set_expand(True)
+        nameCell = gtk.CellRendererText()
+        nameCell.set_property("ellipsize", pango.ELLIPSIZE_END)
+        nameColumn.pack_start(nameCell, True)
+        nameColumn.set_cell_data_func(nameCell, parent_painter)
+        self.append_column(nameColumn)
+
+        tag_cell = TagCellRenderer()
+        tag_cell.font_size = 8;
+        self.append_column(gtk.TreeViewColumn("", tag_cell, data=6))
+        
+
+        # duration
+        timeColumn = gtk.TreeViewColumn()
+        timeCell = gtk.CellRendererText()
+        timeColumn.pack_end(timeCell, True)
+        timeColumn.set_cell_data_func(timeCell, duration_painter)
+        self.append_column(timeColumn)
+
+        edit_cell = gtk.CellRendererPixbuf()
+        edit_cell.set_property("mode", gtk.CELL_RENDERER_MODE_ACTIVATABLE)
+        self.edit_column = gtk.TreeViewColumn("", edit_cell)
+        self.edit_column.set_cell_data_func(edit_cell, action_painter)
+        self.append_column(self.edit_column)
+
+
+        runtime.dispatcher.add_handler('activity_updated', self.after_activity_update)
+        runtime.dispatcher.add_handler('fact_updated', self.after_activity_update)
+
+        self.show()
+    
+    def clear(self):
+        self.model.clear()
+        
+    @property
+    def model(self):
+        return self.get_model()
+        
+    def add_fact(self, fact, parent = None):
+        duration = 24 * 60 * fact["delta"].days + fact["delta"].seconds / 60
+
+        if fact["end_time"]:
+            fact_time = "%s - %s " % (fact["start_time"].strftime("%H:%M"),
+                                   fact["end_time"].strftime("%H:%M"))
+        else:
+            fact_time = fact["start_time"].strftime("%H:%M ")
+
+        self.model.append(parent, [fact["id"],
+                                   "%s %s" % (fact_time, fact["name"]),
+                                   stuff.format_duration(fact["delta"]),
+                                   fact["start_time"].strftime('%Y-%m-%d'),
+                                   fact["description"],
+                                   fact["category"],
+                                   fact])
+
+    def add_group(self, group_label, facts):
+        total = sum([fact["delta"].seconds for fact in facts]) / 60.0
+        
+        # adds group of facts with the given label
+        group_row = self.model.append(None,
+                                    [-1,
+                                     group_label,
+                                     stuff.format_duration(total),
+                                     "",
+                                     "",
+                                     "",
+                                     None])
+        
+        for fact in facts:
+            self.add_fact(fact, group_row)
+
+        self.expand_all()
+
+
+    def after_activity_update(self, event, whatnot):
+        print "catch me!"
\ No newline at end of file
diff --git a/po/POTFILES.in b/po/POTFILES.in
index d5c4d87..0ef5579 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -7,6 +7,9 @@ data/Hamster_Applet.xml
 data/hamster-applet.schemas.in
 [type: gettext/glade]data/applet.ui
 [type: gettext/glade]data/stats.ui
+[type: gettext/glade]data/stats_overview.ui
+[type: gettext/glade]data/stats_reports.ui
+[type: gettext/glade]data/stats_stats.ui
 hamster/about.py
 hamster/applet.py
 hamster/db.py
@@ -14,5 +17,8 @@ hamster/edit_activity.py
 hamster/preferences.py
 hamster/reports.py
 hamster/stats.py
+hamster/stats_overview.py
+hamster/stats_reports.py
+hamster/stats_stats.py
 hamster/stuff.py
 hamster/widgets/reportchooserdialog.py



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]