=== added file 'data/generate_report.glade'
--- data/generate_report.glade	1970-01-01 00:00:00 +0000
+++ data/generate_report.glade	2008-11-25 17:02:58 +0000
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--Generated with glade3 3.4.5 on Tue Nov 25 16:34:15 2008 -->
+<glade-interface>
+  <widget class="GtkDialog" id="report_dialog">
+    <property name="border_width">5</property>
+    <property name="title" translatable="yes">Generate Report</property>
+    <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+    <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+    <property name="has_separator">False</property>
+    <child internal-child="vbox">
+      <widget class="GtkVBox" id="dialog-vbox1">
+        <property name="visible">True</property>
+        <property name="spacing">2</property>
+        <child>
+          <widget class="GtkFrame" id="frame1">
+            <property name="visible">True</property>
+            <property name="label_xalign">0</property>
+            <property name="shadow_type">GTK_SHADOW_NONE</property>
+            <child>
+              <widget class="GtkComboBox" id="report_combo">
+                <property name="visible">True</property>
+              </widget>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="report_label">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">&lt;b&gt;Report Type&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+              </widget>
+              <packing>
+                <property name="type">label_item</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <widget class="GtkHButtonBox" id="dialog-action_area1">
+            <property name="visible">True</property>
+            <property name="layout_style">GTK_BUTTONBOX_END</property>
+            <child>
+              <widget class="GtkButton" id="cancel_button">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="label" translatable="yes">gtk-cancel</property>
+                <property name="use_stock">True</property>
+                <property name="response_id">0</property>
+                <signal name="clicked" handler="on_cancel_button_clicked"/>
+              </widget>
+            </child>
+            <child>
+              <widget class="GtkButton" id="ok_button">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="label" translatable="yes">gtk-ok</property>
+                <property name="use_stock">True</property>
+                <property name="response_id">0</property>
+                <signal name="clicked" handler="on_ok_button_clicked"/>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">GTK_PACK_END</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
+</glade-interface>

=== added directory 'hamster/report_plugins'
=== added file 'hamster/report_plugins/__init__.py'
=== added file 'hamster/report_plugins/simple.py'
--- hamster/report_plugins/simple.py	1970-01-01 00:00:00 +0000
+++ hamster/report_plugins/simple.py	2008-11-25 17:02:58 +0000
@@ -0,0 +1,226 @@
+# - coding: utf-8 -
+
+# Copyright (C) 2008 Toms Bauģis <toms.baugis at gmail.com>
+# Copyright (C) 2008 Nathan Samson <nathansamson at gmail dot com>
+# Copyright (C) 2008 Giorgos Logiotatidis  <seadog at sealabs dot net>
+
+# 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 datetime as dt
+import os
+import webbrowser
+
+from hamster import stuff, storage
+
+
+class SimpleReporter(object):
+
+    description = "Simple HTML report"
+
+    def __init__(self, facts, start_date, end_date):
+        self.facts = facts
+        self.start_date = start_date
+        self.end_date = end_date
+
+    def output(self):
+        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:
+            title = _(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:
+            title = _(u"Overview for %(start_B)s %(start_d)s – %(end_B)s"
+                       " %(end_d)s, %(end_Y)s") % dates_dict
+        else:
+            title = _(u"Overview for %(start_B)s %(start_d)s – %(end_d)s,"
+                       " %(end_Y)s") % dates_dict
+
+        if self.start_date == self.end_date:
+            title = _(u"Overview for %(start_B)s %(start_d)s,"
+                       " %(start_Y)s") % dates_dict
+
+
+        report_path = os.path.join(os.path.expanduser("~"), "%s.html" % title)
+        report = open(report_path, "w")
+        report.write("""\
+            <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+                "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+            <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+            <head>
+                <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+                <meta name="author" content="hamster-applet" />
+                <title>%s</title>
+                <style type="text/css">
+                    body {
+                        font-family: "Sans" ;
+                        font-size: 12px;
+                        padding: 12px;
+                        color: #303030;
+
+                    }
+                    h1 {
+                        border-bottom: 2px solid #303030;
+                        padding-bottom: 4px;
+                    }
+                    h2 {
+                        margin-top: 2em;
+                        border-bottom: 2px solid #303030;
+                    }
+                    table {
+                        width:800px;
+                    }
+                    th {
+                        font-size: 14px;
+                        text-align: center;
+                        padding-bottom: 6px;
+                    }
+
+                    .smallCell {
+                        text-align: center;
+                        width: 100px;
+                        padding: 3px;
+                    }
+
+                    .largeCell {
+                        text-align: left;
+                        padding: 3px 3px 3px 5px;
+                    }
+                    .row1 {
+                        background-color: #EAE8E3;
+                    }
+
+                    .row2 {
+                        background-color: #ffffff;
+                    }
+
+                </style>
+            </head>
+            <body>""" % title)
+
+
+        report.write("<h1>%s</h1>" % title)
+
+        report.write("""<table>
+            <tr>
+                <th>Date</th>
+                <th class="largeCell">Activity</th>
+                <th>Category</th>
+                <th>Start</th>
+                <th>End</th>
+                <th>Duration</th>
+                <th class="largeCell">Description</th>
+            </tr>""")
+
+        #get id of last activity so we know when to show current duration
+        last_activity = storage.get_last_activity()
+        sum_time = {}
+        rowcount = 1
+
+        for fact in self.facts:
+            duration = None
+            end_time = fact["end_time"]
+
+            # ongoing task in current day
+            if (not end_time and last_activity
+                    and fact["id"] == last_activity["id"]):
+                end_time = dt.datetime.now()
+
+            end_time_str = ""
+            if end_time:
+                delta = end_time - fact["start_time"]
+                duration = 24 * 60 * delta.days + delta.seconds / 60
+                end_time_str = end_time.strftime('%H:%M')
+
+            # do not print "unsorted" in list
+            category = ""
+            if fact["category"] != _("Unsorted"):
+                category = fact["category"]
+
+            description = fact["description"] or ""
+
+            # fact date column in HTML report
+            report.write("""\
+                <tr class="row%s">
+                    <td class="smallCell">%s</td>
+                    <td class="largeCell">%s</td>
+                    <td class="smallCell">%s</td>
+                    <td class="smallCell">%s</td>
+                    <td class="smallCell">%s</td>
+                    <td class="smallCell">%s</td>
+                    <td class="largeCell">%s</td>
+                </tr>
+               """ % (rowcount,
+                      _("%(report_b)s %(report_d)s, %(report_Y)s")
+                            % stuff.dateDict(fact["start_time"], "report_"),
+                     fact["name"],
+                     category,
+                     fact["start_time"].strftime('%H:%M'),
+                     end_time_str,
+                     stuff.format_duration(duration) or "",
+                     description))
+
+            if rowcount == 1:
+                rowcount = 2
+            else:
+                rowcount = 1
+
+
+            # save data for summary table
+            if duration:
+                id_string = ("<td class=\"smallCell\">%s</td><td class=\""
+                             "largeCell\">%s</td>" % (fact["category"],
+                                                      fact["name"]))
+                if id_string in sum_time:
+                    sum_time[id_string] += duration
+                else:
+                    sum_time[id_string] = duration
+
+        report.write("</table>")
+
+        # summary table
+        report.write("\n<h2>%s</h2>\n" % _("Totals"))
+        report.write("""<table>
+        <tr>
+            <th class="smallCell">""" + _("Category") + """</th>
+            <th class="largeCell">""" + _("Activity") + """</th>
+            <th class="smallCell">""" + _("Duration") + """</th>
+        </tr>\n""")
+        tot_time = 0
+        rowcount = 1
+        for key in sorted(sum_time.keys()):
+            report.write("    <tr class=\"row%s\">%s<td class=\"smallCell\">%s"
+                         "</td></tr>\n" % (rowcount, key,
+                                           stuff.format_duration(sum_time[key])))
+            tot_time += sum_time[key]
+
+            if rowcount == 1:
+                rowcount = 2
+            else:
+                rowcount = 1
+        report.write("    <tr><th colspan=\"2\" style=\"text-align:right;\">"
+                     "Total Time:</th><th>%s</th></tr>\n"
+                        % (stuff.format_duration(tot_time)))
+        report.write("</table>\n")
+
+        report.write("</body>\n</html>")
+
+
+        report.close()
+
+        webbrowser.open_new("file://"+report_path)

=== modified file 'hamster/reports.py'
--- hamster/reports.py	2008-11-21 17:52:14 +0000
+++ hamster/reports.py	2008-11-25 17:02:58 +0000
@@ -1,8 +1,6 @@
 # - coding: utf-8 -
 
-# Copyright (C) 2008 Toms Bauģis <toms.baugis at gmail.com>
-# Copyright (C) 2008 Nathan Samson <nathansamson at gmail dot com>
-# Copyright (C) 2008 Giorgos Logiotatidis  <seadog at sealabs dot net>
+# Copyright (C) 2008 Daniel Watkins  <daniel at daniel-watkins dot co dot uk>
 
 # This file is part of Project Hamster.
 
@@ -18,181 +16,61 @@
 
 # You should have received a copy of the GNU General Public License
 # along with Project Hamster.  If not, see <http://www.gnu.org/licenses/>.
-from hamster import stuff, storage
+
+
 import os
-import datetime as dt
-import webbrowser
-
-def simple(facts, start_date, end_date):
-    dates_dict = stuff.dateDict(start_date, "start_")
-    dates_dict.update(stuff.dateDict(end_date, "end_"))
-    
-    
-    if start_date.year != end_date.year:
-        title = _(u"Overview for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s") % dates_dict
-    elif start_date.month != end_date.month:
-        title = _(u"Overview for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s") % dates_dict
-    else:
-        title = _(u"Overview for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s") % dates_dict
-
-    if start_date == end_date:
-        title = _("Overview for %(start_B)s %(start_d)s, %(start_Y)s") % dates_dict
-    
-
-    report_path = os.path.join(os.path.expanduser("~"), "%s.html" % title)
-    report = open(report_path, "w")    
-    report.write("""<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
-        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
-<head>
-    <meta http-equiv="content-type" content="text/html; charset=utf-8" />
-    <meta name="author" content="hamster-applet" />
-    <title>%s</title>
-    <style type="text/css">
-        body {
-            font-family: "Sans" ;
-            font-size: 12px;
-            padding: 12px;
-            color: #303030;
-            
-        }
-        h1 {
-            border-bottom: 2px solid #303030;
-            padding-bottom: 4px;
-        }
-        h2 {
-            margin-top: 2em;
-            border-bottom: 2px solid #303030;
-        }
-        table {
-            width:800px;
-        }
-        th {
-            font-size: 14px;
-            text-align: center;
-            padding-bottom: 6px;
-        }
-  
-        .smallCell {
-            text-align: center;
-            width: 100px;
-            padding: 3px;
-        }
-
-        .largeCell {
-            text-align: left;
-            padding: 3px 3px 3px 5px;
-        }     
-        .row1 {
-        	background-color: #EAE8E3;
-        }
-
-        .row2 {
-        	background-color: #ffffff;
-        }   
-
-    </style>
-</head>
-<body>""" % title)    
-  
-    
-    report.write("<h1>%s</h1>" % title)
-    
-    report.write("""<table>
-        <tr>
-            <th>Date</th>
-            <th class="largeCell">Activity</th>
-            <th>Category</th>
-            <th>Start</th>
-            <th>End</th>
-            <th>Duration</th>
-            <th class="largeCell">Description</th>
-        </tr>""")
-    
-    #get id of last activity so we know when to show current duration
-    last_activity = storage.get_last_activity()
-    sum_time = {}
-    rowcount = 1
-    
-    for fact in facts:
-        duration = None
-        end_time = fact["end_time"]
-        
-        # ongoing task in current day
-        if not end_time and last_activity and fact["id"] == last_activity["id"]:
-            end_time = dt.datetime.now()
-
-        end_time_str = ""
-        if end_time:
-            delta = end_time - fact["start_time"]
-            duration = 24 * 60 * delta.days + delta.seconds / 60
-            end_time_str = end_time.strftime('%H:%M')
-
-        category = ""
-        if fact["category"] != _("Unsorted"): #do not print "unsorted" in list
-            category = fact["category"]
-
-        description = fact["description"] or ""            
-            
-        # fact date column in HTML report
-        report.write("""<tr class="row%s">
-                            <td class="smallCell">%s</td>
-                            <td class="largeCell">%s</td>
-                            <td class="smallCell">%s</td>
-                            <td class="smallCell">%s</td>
-                            <td class="smallCell">%s</td>
-                            <td class="smallCell">%s</td>
-                            <td class="largeCell">%s</td>
-                        </tr>
-                       """ % (rowcount, _("%(report_b)s %(report_d)s, %(report_Y)s") % stuff.dateDict(fact["start_time"], "report_"),
-            fact["name"],
-            category, 
-            fact["start_time"].strftime('%H:%M'),
-            end_time_str,
-            stuff.format_duration(duration) or "",
-            description))
-            
-        if rowcount == 1:
-            rowcount = 2
-        else:
-            rowcount = 1
-
-
-        # save data for summary table
-        if duration:
-            id_string = "<td class=\"smallCell\">%s</td><td class=\"largeCell\">%s</td>" % (fact["category"], fact["name"])
-            if id_string in sum_time:
-                sum_time[id_string] += duration
-            else:
-                sum_time[id_string] = duration
-     
-    report.write("</table>")
-
-    # summary table
-    report.write("\n<h2>%s</h2>\n" % _("Totals"))
-    report.write("""<table>
-    <tr>
-        <th class="smallCell">""" + _("Category") + """</th>
-        <th class="largeCell">""" + _("Activity") + """</th>
-        <th class="smallCell">""" + _("Duration") + """</th>
-    </tr>\n""")
-    tot_time = 0
-    rowcount = 1
-    for key in sorted(sum_time.keys()):
-        report.write("    <tr class=\"row%s\">%s<td class=\"smallCell\">%s</td></tr>\n" % (rowcount, key, stuff.format_duration(sum_time[key])))
-        tot_time += sum_time[key]
-      
-        if rowcount == 1:
-            rowcount = 2
-        else:
-            rowcount = 1       
-    report.write("    <tr><th colspan=\"2\" style=\"text-align:right;\">Total Time:</th><th>%s</th></tr>\n" % (stuff.format_duration(tot_time)))
-    report.write("</table>\n")
-
-    report.write("</body>\n</html>")
-
-    
-    report.close()
-
-    webbrowser.open_new("file://"+report_path)
-    
+
+import gobject
+import gtk
+
+from hamster import SHARED_DATA_DIR
+from hamster.report_plugins.simple import SimpleReporter
+
+
+GLADE_FILE = 'generate_report.glade'
+
+
+class ReportController(object):
+
+    def __init__(self, facts, start_date, end_date):
+        self.facts = facts
+        self.start_date = start_date
+        self.end_date = end_date
+        self.setup_gui()
+
+    def setup_gui(self):
+        self.glade = gtk.glade.XML(os.path.join(SHARED_DATA_DIR, GLADE_FILE))
+        self.dialog = self.glade.get_widget('report_dialog')
+
+        report_types = report_registry.keys()
+        reports_model = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
+        for report_type in report_types:
+            reports_model.append((report_registry[report_type].description,
+                                  report_type))
+        report_combo = self.glade.get_widget('report_combo')
+        report_combo.set_model(reports_model)
+        cell = gtk.CellRendererText()
+        report_combo.pack_start(cell, True)
+        report_combo.add_attribute(cell, 'text', 0)
+        report_combo.set_active(0)
+
+        self.glade.signal_autoconnect(self)
+
+    def show(self):
+        self.dialog.show()
+
+    def on_ok_button_clicked(self, button):
+        report_combo = self.glade.get_widget('report_combo')
+        iter = report_combo.get_active_iter()
+        report_type = report_combo.get_model().get(iter, 1)[0]
+        reporter = report_registry[report_type]
+        reporter(self.facts, self.start_date, self.end_date).output()
+        self.dialog.destroy()
+
+    def on_cancel_button_clicked(self, button):
+        self.dialog.destroy()
+
+
+report_registry = {
+    'simple': SimpleReporter,
+}

=== modified file 'hamster/stats.py'
--- hamster/stats.py	2008-11-21 17:58:05 +0000
+++ hamster/stats.py	2008-11-25 17:02:58 +0000
@@ -469,7 +469,10 @@
     def on_report_button_clicked(self, widget):
         from hamster import reports
         facts = storage.get_facts(self.start_date, self.end_date)
-        reports.simple(facts, self.start_date, self.end_date)
+        report_dialog = reports.ReportController(facts,
+                                                 self.start_date,
+                                                 self.end_date)
+        report_dialog.show()
 
     def after_activity_update(self, widget, renames):
         self.do_graph()


