Refactor Fremantule UI code and implement logging
authorRyan Campbell <campbellr@gmail.com>
Tue, 14 Sep 2010 02:39:14 +0000 (20:39 -0600)
committerRyan Campbell <campbellr@gmail.com>
Sun, 17 Oct 2010 23:31:17 +0000 (17:31 -0600)
- the fremantle ui code was refactor to be more modular
- start using python 'logging' library to log errors (to file and
  console)

package/src/mevemon.py
package/src/ui/fremantle/base.py [deleted file]
package/src/ui/fremantle/characterSheet.py
package/src/ui/fremantle/dialogs.py [new file with mode: 0644]
package/src/ui/fremantle/gui.py
package/src/ui/fremantle/menu.py [new file with mode: 0644]

index 600f058..af2e701 100755 (executable)
 #
 
 
-import hildon
-import gtk
-from eveapi import eveapi
-import fetchimg
-import apicache
 import os.path
 import traceback
 import time
-
-#conic is used for connection handling
-import conic
+import sys
 #import socket for handling socket exceptions
 import socket
+import logging
+import logging.handlers
 
+import hildon
+import gtk
+#conic is used for connection handling
+import conic
 # we will store our preferences in gconf
 import gnome.gconf
 
+from eveapi import eveapi
+import fetchimg
+import apicache
+
 #ugly hack to check maemo version. any better way?
 if hasattr(hildon, "StackableWindow"):
     from ui.fremantle import gui
 else:
     from ui.diablo import gui
 
-class mEveMon():
-    """
-    The controller class for mEvemon. The intent is to help
-    abstract the EVE API and settings code from the UI code.
+LOGNAME = "mevemon.log"
+CONFIG_DIR = os.path.expanduser("~/.mevemon/")
+LOGPATH = os.path.join(CONFIG_DIR, LOGNAME)
 
+
+class mEveMon():
+    """ The controller class for mEvemon. The intent is to help
+        abstract the EVE API and settings code from the UI code.
     """
 
     about_name = 'mEveMon'
@@ -78,9 +84,8 @@ class mEveMon():
         gtk.main_quit()
 
     def update_settings(self):
-        """
-        Update from the old pre 0.3 settings to the new settings layout.
-        We should remove this eventually, once no one is using pre-0.3 mEveMon
+        """ Update from the old pre 0.3 settings to the new settings layout.
+            We should remove this eventually, once no one is using pre-0.3 mEveMon
         """
         uid = self.gconf.get_string("%s/eve_uid" % self.GCONF_DIR)
         
@@ -92,8 +97,7 @@ class mEveMon():
 
 
     def get_accounts(self):
-        """
-        Returns a dictionary containing uid:api_key pairs gathered from gconf
+        """ Returns a dictionary containing uid:api_key pairs gathered from gconf
         """
         accounts = {}
         entries = self.gconf.all_entries("%s/accounts" % self.GCONF_DIR)
@@ -106,14 +110,12 @@ class mEveMon():
         return accounts
         
     def get_api_key(self, uid):
-        """
-        Returns the api key associated with the given uid.
+        """ Returns the api key associated with the given uid.
         """
         return self.gconf.get_string("%s/accounts/%s" % (self.GCONF_DIR, uid)) or ''
 
     def remove_account(self, uid):
-        """
-        Removes the provided uid key from gconf
+        """ Removes the provided uid key from gconf
         """
         self.gconf.unset("%s/accounts/%s" % (self.GCONF_DIR, uid))
 
@@ -124,9 +126,8 @@ class mEveMon():
         self.gconf.set_string("%s/accounts/%s" % (self.GCONF_DIR, uid), api_key)
 
     def get_auth(self, uid):
-        """
-        Returns an authentication object to be used for eveapi calls
-        that require authentication.
+        """ Returns an authentication object to be used for eveapi calls
+            that require authentication.
         """
         api_key = self.get_api_key(uid)
 
@@ -140,9 +141,8 @@ class mEveMon():
         return auth
 
     def get_char_sheet(self, uid, char_id):
-        """
-        Returns an object containing information about the character specified
-        by the provided character ID.
+        """ Returns an object containing information about the character specified
+            by the provided character ID.
         """
         try:
             sheet = self.get_auth(uid).character(char_id).CharacterSheet()
@@ -155,11 +155,10 @@ class mEveMon():
         return sheet
 
     def charid2uid(self, char_id):
-        """
-        Takes a character ID and returns the user ID of the account containing
-        the character.
+        """ Takes a character ID and returns the user ID of the account containing
+            the character.
 
-        Returns None if the character isn't found in any of the registered accounts.
+            Returns None if the character isn't found in any of the registered accounts.
 
         """
         acct_dict = self.get_accounts()
@@ -180,11 +179,10 @@ class mEveMon():
         return None
     
     def char_id2name(self, char_id):
-        """
-        Takes a character ID and returns the character name associated with
-        that ID.
-        The EVE API accepts a comma-separated list of IDs, but for now we
-        will just handle a single ID.
+        """ Takes a character ID and returns the character name associated with
+            that ID.
+            The EVE API accepts a comma-separated list of IDs, but for now we
+            will just handle a single ID.
         """
         try:
             chars = self.cached_api.eve.CharacterName(ids=char_id).characters
@@ -197,11 +195,10 @@ class mEveMon():
         return name
 
     def char_name2id(self, name):
-        """
-        Takes the name of an EVE character and returns the characterID.
+        """ Takes the name of an EVE character and returns the characterID.
         
-        The EVE api accepts a comma separated list of names, but for now
-        we will just handle single names/
+            The EVE api accepts a comma separated list of names, but for now
+            we will just handle single names/
         """
         try:
             chars = self.cached_api.eve.CharacterID(names=name).characters
@@ -215,8 +212,7 @@ class mEveMon():
         return char_id
 
     def get_chars_from_acct(self, uid):
-        """
-        Returns a list of characters associated with the provided user ID.
+        """ Returns a list of characters associated with the provided user ID.
         """
         auth = self.get_auth(uid)
         if not auth:
@@ -233,13 +229,11 @@ class mEveMon():
         return char_list
 
     def get_characters(self):
-        """
-        Returns a list of (character_name, image_path, uid) tuples from all the
-        accounts that are registered to mEveMon.
+        """ Returns a list of (character_name, image_path, uid) tuples from all the
+            accounts that are registered to mEveMon.
         
-        If there is an authentication issue, then instead of adding a valid
-        pair to the list, it appends an 'error message' 
-
+            If there is an authentication issue, then instead of adding a valid
+            pair to the list, it appends an 'error message' 
         """
 
         ui_char_list = []
@@ -266,16 +260,14 @@ class mEveMon():
         return ui_char_list
 
     def get_portrait(self, char_name, size):
-        """
-        Returns the file path of the retrieved portrait
+        """ Returns the file path of the retrieved portrait
         """
         char_id = self.char_name2id(char_name)
         
         return fetchimg.portrait_filename(char_id, size)
 
     def get_skill_tree(self):
-        """
-        Returns an object from eveapi containing skill tree info
+        """ Returns an object from eveapi containing skill tree info
         """
         try:
             tree = self.cached_api.eve.SkillTree()
@@ -287,9 +279,8 @@ class mEveMon():
         return tree
 
     def get_skill_in_training(self, uid, char_id):
-        """
-        Returns an object from eveapi containing information about the
-        current skill in training
+        """ Returns an object from eveapi containing information about the
+            current skill in training
         """
         try:
             skill = self.get_auth(uid).character(char_id).SkillInTraining()
@@ -301,19 +292,17 @@ class mEveMon():
         return skill
 
     def connection_cb(self, connection, event, mgc):
-        """
-        I'm not sure why we need this, but connection.connect() won't work
-        without it, even empty.
+        """ I'm not sure why we need this, but connection.connect() won't work
+            without it, even empty.
         """
         pass    
 
 
     def connect_to_network(self):
-        """
-        This will connect to the default network if avaliable, or pop up the
-        connection dialog to select a connection.
-        Running this when we start the program ensures we are connected to a
-        network.
+        """ This will connect to the default network if avaliable, or pop up the
+            connection dialog to select a connection.
+            Running this when we start the program ensures we are connected to a
+            network.
         """
         connection = conic.Connection()
         #why 0xAA55?
@@ -322,9 +311,8 @@ class mEveMon():
 
 
     def get_sp(self, uid, char_id):
-        """
-        Adds up the SP for all known skills, then calculates the SP gained
-        from an in-training skill.
+        """ Adds up the SP for all known skills, then calculates the SP gained
+            from an in-training skill.
         """
         actual_sp = 0
         
@@ -337,8 +325,7 @@ class mEveMon():
         return live_sp
 
     def get_spps(self, uid, char_id):
-        """
-        Calculate and returns the skill points per hour for the given character.
+        """ Calculate and returns the skill points per hour for the given character.
         """
         skill = self.get_skill_in_training(uid, char_id)
         
@@ -353,8 +340,7 @@ class mEveMon():
         return (spps, skill.trainingStartTime)
 
     def get_training_sp(self, uid, char_id):
-        """
-        returns the additional SP that the in-training skill has acquired
+        """ returns the additional SP that the in-training skill has acquired
         """
         spps_tuple = self.get_spps(uid, char_id)
         
@@ -367,6 +353,39 @@ class mEveMon():
         return (spps * time_diff) 
 
 
+def excepthook(ex_type, value, tb):
+    """ a replacement for the default exception handler that logs errors"""
+    #tb2 = "".join(traceback.format_exception(ex_type, value, tb))
+    #print tb2
+    logging.getLogger('meEveMon').error('Uncaught exception:', 
+                      exc_info=(ex_type, value, tb))
+
+def setupLogger():
+    """ sets up the logging """
+    MAXBYTES = 1 * 1000 * 1000 # 1MB
+    LOGCOUNT = 10
+
+    logger = logging.getLogger("mEveMon")
+    logger.setLevel(logging.DEBUG)
+    
+    fileHandler = logging.handlers.RotatingFileHandler(LOGPATH,
+                                                    maxBytes=MAXBYTES,
+                                                    backupCount=LOGCOUNT)
+    logger.addHandler(fileHandler)
+
+    #create console handler
+    console = logging.StreamHandler()
+    console.setLevel(logging.DEBUG)
+    #formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
+    #console.setFormatter(formatter)
+    logger.addHandler(console)
+
+
 if __name__ == "__main__":
+    setupLogger()
+    sys.excepthook = excepthook
     app = mEveMon()
-    app.run()
+    try:
+        app.run()
+    except KeyboardInterrupt:
+        sys.exit(0)
diff --git a/package/src/ui/fremantle/base.py b/package/src/ui/fremantle/base.py
deleted file mode 100644 (file)
index d773256..0000000
+++ /dev/null
@@ -1,223 +0,0 @@
-#
-# mEveMon - A character monitor for EVE Online
-# Copyright (c) 2010  Ryan and Danny Campbell, and the mEveMon Team
-#
-# mEveMon 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.
-#
-# mEveMon 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 this program.  If not, see <http://www.gnu.org/licenses/>.
-#
-
-import hildon
-import gtk
-
-import ui.models as models
-
-class BaseUI():
-    menu_items = ("Settings", "About", "Refresh")
-
-    def create_menu(self, window):
-        menu = hildon.AppMenu()
-
-        for command in self.menu_items:
-            # Create menu entries
-            button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
-            button.set_label(command)
-
-            if command == "About":
-                button.connect("clicked", self.about_clicked)
-            elif command == "Settings":
-                button.connect("clicked", self.settings_clicked, window)
-            elif command == "Refresh":
-                button.connect("clicked", self.refresh_clicked)
-            else:
-                assert False, command
-
-            # Add entry to the view menu
-            menu.append(button)
-
-        menu.show_all()
-
-        return menu
-
-    def settings_clicked(self, button, window):
-
-        RESPONSE_NEW, RESPONSE_EDIT, RESPONSE_DELETE = range(3)
-
-        dialog = gtk.Dialog()
-        dialog.set_transient_for(window)
-        dialog.set_title("Settings")
-
-        pannable_area = hildon.PannableArea()
-
-        dialog_vbox = dialog.vbox
-
-        vbox = gtk.VBox(False, 1)
-
-        self.accounts_model = models.AccountsModel(self.controller)
-        
-        accounts_treeview = hildon.GtkTreeView(gtk.HILDON_UI_MODE_NORMAL)
-        accounts_treeview.set_model(self.accounts_model)
-        accounts_treeview.set_headers_visible(True)
-        self.add_columns_to_accounts(accounts_treeview)
-        vbox.pack_start(accounts_treeview, False, False, 1)
-
-        # all stock responses are negative, so we can use any positive value
-        new_button = dialog.add_button("New", RESPONSE_NEW)
-        #TODO: get edit button working
-        #edit_button = dialog.add_button("Edit", RESPONSE_EDIT)
-        delete_button = dialog.add_button("Delete", RESPONSE_DELETE)
-        ok_button = dialog.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
-        
-        pannable_area.add_with_viewport(vbox)
-        
-        dialog_vbox.pack_start(pannable_area, True, True, 1)
-      
-      
-        dialog.show_all()
-
-        result = dialog.run()
-
-        while(result != gtk.RESPONSE_DELETE_EVENT):
-            if result == RESPONSE_NEW:
-                self.new_account_clicked(window)
-            #elif result == RESPONSE_EDIT:
-            #    # get the selected treeview item and pop up the account_box
-            #    self.edit_account(accounts_treeview)
-            elif result == RESPONSE_DELETE:
-                # get the selected treeview item, and delete the gconf keys
-                self.delete_account(accounts_treeview)
-            elif result == gtk.RESPONSE_OK:
-                self.char_model.get_characters()
-                break
-        
-            result = dialog.run()
-
-        dialog.destroy()
-
-
-
-    def get_selected_item(self, treeview, column):
-        selection = treeview.get_selection()
-        model, miter = selection.get_selected()
-
-        value = model.get_value(miter, column)
-
-        return value
-
-    def edit_account(self, treeview):
-        uid = self.get_selected_item(treeview, 0)
-        # pop up the account dialog
-
-        self.accounts_model.get_accounts()
-
-    def delete_account(self, treeview):
-        uid = self.get_selected_item(treeview, 0)
-        self.controller.remove_account(uid)
-        # refresh model
-        self.accounts_model.get_accounts()
-
-
-    def add_columns_to_accounts(self, treeview):
-        #Column 0 for the treeview
-        renderer = gtk.CellRendererText()
-        column = gtk.TreeViewColumn('User ID', renderer, 
-                text=models.AccountsModel.C_UID)
-        column.set_property("expand", True)
-        treeview.append_column(column)
-
-        #Column 2 (characters) for the treeview
-        column = gtk.TreeViewColumn('Characters', renderer, 
-                markup=models.AccountsModel.C_CHARS)
-        column.set_property("expand", True)
-        treeview.append_column(column)
-
-
-    def new_account_clicked(self, window):
-        dialog = gtk.Dialog()
-    
-        #get the vbox to pack all the settings into
-        vbox = dialog.vbox
-    
-        dialog.set_transient_for(window)
-        dialog.set_title("New Account")
-
-        uidLabel = gtk.Label("User ID:")
-        uidLabel.set_justify(gtk.JUSTIFY_LEFT)
-        vbox.add(uidLabel)
-        
-        uidEntry = hildon.Entry(gtk.HILDON_SIZE_FINGER_HEIGHT)
-        uidEntry.set_placeholder("User ID")
-        uidEntry.set_property('is_focus', False)
-        
-        vbox.add(uidEntry)
-
-        apiLabel = gtk.Label("API key:")
-        apiLabel.set_justify(gtk.JUSTIFY_LEFT)
-        vbox.add(apiLabel)
-        
-        apiEntry = hildon.Entry(gtk.HILDON_SIZE_FINGER_HEIGHT)
-        apiEntry.set_placeholder("API Key")
-        apiEntry.set_property('is_focus', False)
-
-        vbox.add(apiEntry)
-       
-        ok_button = dialog.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
-
-        dialog.show_all()
-        result = dialog.run()
-        
-        valid_credentials = False
-
-        while not valid_credentials:
-            if result == gtk.RESPONSE_OK:
-                uid = uidEntry.get_text()
-                api_key = apiEntry.get_text()
-                try:
-                    validation.uid(uid)
-                    validation.api_key(api_key)
-                except validation.ValidationError, e:
-                    self.report_error(e.message)
-                    result = dialog.run()
-                else:
-                    valid_credentials = True
-                    self.controller.add_account(uid, api_key)
-                    self.accounts_model.get_accounts()
-            else:
-                break
-
-        dialog.destroy()
-
-
-    def report_error(self, error):
-        hildon.hildon_banner_show_information(self.win, '', error)
-    
-    def about_clicked(self, button):
-        dialog = gtk.AboutDialog()
-        dialog.set_website(self.controller.about_website)
-        dialog.set_website_label(self.controller.about_website)
-        dialog.set_name(self.controller.about_name)
-        dialog.set_authors(self.controller.about_authors)
-        dialog.set_comments(self.controller.about_text)
-        dialog.set_version(self.controller.app_version)
-        dialog.run()
-        dialog.destroy()
-
-    def add_label(self, text, box, markup=True, align="left", padding=1):
-        label = gtk.Label(text)
-        if markup:
-            label.set_use_markup(True)
-        if align == "left":
-            label.set_alignment(0, 0.5)
-
-        box.pack_start(label, False, False, padding)
-
-        return label
index ccfa390..133cb01 100644 (file)
@@ -22,10 +22,10 @@ import gtk
 import gobject
 
 import util
-import ui.fremantle.base as base
 import ui.models as models
+from menu import Menu
 
-class CharacterSheetUI(base.BaseUI):
+class CharacterSheetUI:
     UPDATE_INTERVAL = 1
 
     def __init__(self, controller, char_name, uid):
@@ -49,7 +49,7 @@ class CharacterSheetUI(base.BaseUI):
         # Create menu
         # NOTE: we probably want a window-specific menu for this page, but the
         # main appmenu works for now
-        menu = self.create_menu(self.win)
+        menu = Menu(self.win, self.controller)
         # Attach menu to the window
         self.win.set_app_menu(menu)
 
@@ -85,7 +85,7 @@ class CharacterSheetUI(base.BaseUI):
         separator.show()
 
         
-        self.add_label("<big>Skill in Training:</big>", vbox, align="normal")
+        self.add_label("<big>Skill in Training:</big>", vbox, align='normal')
 
         self.display_skill_in_training(vbox)
 
@@ -93,7 +93,7 @@ class CharacterSheetUI(base.BaseUI):
         vbox.pack_start(separator, False, False, 0)
         separator.show()
         
-        self.add_label("<big>Skills:</big>", vbox, align="normal")
+        self.add_label("<big>Skills:</big>", vbox, align='normal')
 
         skills_treeview = hildon.GtkTreeView(gtk.HILDON_UI_MODE_NORMAL)
         self.skills_model = models.CharacterSkillsModel(self.controller, self.char_id)
@@ -131,10 +131,10 @@ class CharacterSheetUI(base.BaseUI):
                     break
                 
             self.add_label("%s <small>(Level %d)</small>" % (skill_name, skill.trainingToLevel),
-                    vbox, align="normal")
+                    vbox, align='normal')
             self.add_label("<small>start time: %s\t\tend time: %s</small>" 
                     %(time.ctime(skill.trainingStartTime),
-                time.ctime(skill.trainingEndTime)), vbox, align="normal")
+                time.ctime(skill.trainingEndTime)), vbox, align='normal')
 
             progressbar = gtk.ProgressBar()
             fraction_completed = (time.time() - skill.trainingStartTime) / \
@@ -148,7 +148,7 @@ class CharacterSheetUI(base.BaseUI):
             progressbar.show()
         else:
             self.add_label("<small>No skills are currently being trained</small>",
-                    vbox, align="normal")
+                    vbox, align='normal')
 
 
 
@@ -216,3 +216,14 @@ class CharacterSheetUI(base.BaseUI):
                                 util.comma(int(self.live_sp_val)))
 
         return True
+    
+    def add_label(self, text, box, markup=True, align='left'):
+        label = gtk.Label(text)
+        if markup:
+            label.set_use_markup(True)
+        if align == 'left':
+            label.set_alignment(0, 0.5)
+           
+        box.pack_start(label, False, False)
+
+        return label
diff --git a/package/src/ui/fremantle/dialogs.py b/package/src/ui/fremantle/dialogs.py
new file mode 100644 (file)
index 0000000..af1ce18
--- /dev/null
@@ -0,0 +1,160 @@
+import hildon
+import gtk
+
+import ui.models as models
+import validation
+
+class SettingsDialog(gtk.Dialog):
+    RESPONSE_NEW, RESPONSE_EDIT, RESPONSE_DELETE = range(3)
+    def __init__(self, window, controller):
+        self.win = window
+        self.controller = controller
+        gtk.Dialog.__init__(self)
+        self.set_transient_for(self.win)
+        self.set_title("Settings")
+
+        pannable_area = hildon.PannableArea()
+        vbox = gtk.VBox(False, 1)
+        pannable_area.add_with_viewport(vbox)
+        self.vbox.pack_start(pannable_area, True, True, 1)
+
+        self.accounts = AccountsTreeView(gtk.HILDON_UI_MODE_NORMAL, self.controller)
+        vbox.pack_start(self.accounts, False, False, 1)
+        
+        # add butttons
+        # all stock responses are negative, so we can use any positive value
+        new_button = self.add_button("New", self.RESPONSE_NEW)
+        #TODO: get edit button working
+        #edit_button = self.add_button("Edit", RESPONSE_EDIT)
+        delete_button = self.add_button("Delete", self.RESPONSE_DELETE)
+        ok_button = self.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
+
+        self.show_all()
+        
+        result = self.run()
+
+        while(result != gtk.RESPONSE_DELETE_EVENT):
+            if result == self.RESPONSE_NEW:
+                self.on_new_account_clicked()
+            elif result == self.RESPONSE_DELETE:
+                # get the selected treeview item, and delete the gconf keys
+                self.on_delete_account_clicked()
+            elif result == gtk.RESPONSE_OK:
+                self.accounts.refresh()
+                break
+        
+            result = self.run()
+
+        self.destroy()
+
+    def on_new_account_clicked(self):
+        NewAccountDialog(self.win, self.controller)
+        self.accounts.refresh()
+
+    
+    def on_delete_account_clicked(self):
+        uid = self._get_selected_item(0)
+        self.controller.remove_account(uid)
+        self.accounts.refresh()
+    
+    def _get_selected_item(self, column):
+        selection = self.accounts.get_selection()
+        model, miter = selection.get_selected()
+        value = model.get_value(miter, column)
+
+        return value
+
+    def report_error(self, error):
+        hildon.hildon_banner_show_information(self.get_toplevel(), '', error)
+
+class NewAccountDialog(gtk.Dialog):
+    def __init__(self, parent, controller):
+        self.controller = controller
+        gtk.Dialog.__init__(self, parent=parent)
+        self.build()
+        
+        result = self.run()
+        
+        valid_credentials = False
+
+        while not valid_credentials:
+            if result == gtk.RESPONSE_OK:
+                uid = self.uidEntry.get_text()
+                api_key = self.apiEntry.get_text()
+                try:
+                    validation.uid(uid)
+                    validation.api_key(api_key)
+                except validation.ValidationError, e:
+                    self.report_error(e.message)
+                    result = self.run()
+                else:
+                    valid_credentials = True
+                    self.controller.add_account(uid, api_key)
+            else:
+                break
+
+        self.destroy()
+
+
+    def build(self):
+        #get the vbox to pack all the settings into
+        vbox = self.vbox
+    
+        self.set_title("New Account")
+
+        uidLabel = gtk.Label("User ID:")
+        uidLabel.set_justify(gtk.JUSTIFY_LEFT)
+        vbox.add(uidLabel)
+        
+        self.uidEntry = hildon.Entry(gtk.HILDON_SIZE_FINGER_HEIGHT)
+        self.uidEntry.set_placeholder("User ID")
+        self.uidEntry.set_property('is_focus', False)
+        
+        vbox.add(self.uidEntry)
+
+        apiLabel = gtk.Label("API key:")
+        apiLabel.set_justify(gtk.JUSTIFY_LEFT)
+        vbox.add(apiLabel)
+        
+        self.apiEntry = hildon.Entry(gtk.HILDON_SIZE_FINGER_HEIGHT)
+        self.apiEntry.set_placeholder("API Key")
+        self.apiEntry.set_property('is_focus', False)
+
+        vbox.add(self.apiEntry)
+       
+        ok_button = self.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
+
+        self.show_all()
+
+    def report_error(self, error):
+        hildon.hildon_banner_show_information(self.get_toplevel(), '', error)
+
+class AccountsTreeView(hildon.GtkTreeView):
+    def __init__(self, mode, controller):
+        self.controller = controller
+        hildon.GtkTreeView.__init__(self, mode)
+        
+        self.accounts_model = models.AccountsModel(self.controller)
+        self.set_model(self.accounts_model)
+        self.set_headers_visible(True)
+        self.add_columns()
+
+    def add_columns(self):
+        #Column 0 for the treeview
+        renderer = gtk.CellRendererText()
+        column = gtk.TreeViewColumn('User ID', renderer, 
+                text=models.AccountsModel.C_UID)
+        column.set_property("expand", True)
+        self.append_column(column)
+
+        #Column 2 (characters) for the treeview
+        column = gtk.TreeViewColumn('Characters', renderer, 
+                markup=models.AccountsModel.C_CHARS)
+        column.set_property("expand", True)
+        self.append_column(column)
+
+    def refresh(self):
+        self.accounts_model.get_accounts()
+
+
+
index 8a1ceab..7e4a4f7 100644 (file)
@@ -20,18 +20,16 @@ import gtk
 import hildon
 import gobject
 
-from characterSheet import CharacterSheetUI
+from ui.fremantle.characterSheet import CharacterSheetUI
 import ui.models as models
 import validation
-import ui.fremantle.base as base
-
-class mEveMonUI(base.BaseUI):
+from ui.fremantle.menu import Menu
 
+class mEveMonUI:
     def __init__(self, controller):
         self.controller = controller
         gtk.set_application_name("mEveMon")
 
-
     def run(self):
         # create the main window
         self.win = hildon.StackableWindow()
@@ -40,54 +38,29 @@ class mEveMonUI(base.BaseUI):
         hildon.hildon_gtk_window_set_progress_indicator(self.win, 1)
 
         # Create menu
-        menu = self.create_menu(self.win)
+        menu = Menu(self.win, self.controller)
         # Attach menu to the window
         self.win.set_app_menu(menu)
 
         pannable_area = hildon.PannableArea()
-
-
+        
         # gtk.HILDON_UI_MODE_NORMAL -> not selection in the treeview
         # gtk.HILDON_UI_MODE_EDIT -> selection in the treeview
-        treeview = hildon.GtkTreeView(gtk.HILDON_UI_MODE_NORMAL)
-        treeview.connect('row-activated', self.do_charactersheet)
-
-        self.char_model = models.CharacterListModel(self.controller)
-        treeview.set_model(self.char_model)
-        self.add_columns_to_treeview(treeview)
-
-        pannable_area.add(treeview)
+        self.treeview = CharactersTreeView(gtk.HILDON_UI_MODE_NORMAL, self.controller)
+        self.treeview.connect('row-activated', self.do_charactersheet)
 
+        pannable_area.add(self.treeview)
         self.win.add(pannable_area);
-        
         self.win.show_all()
 
         hildon.hildon_gtk_window_set_progress_indicator(self.win, 0)
 
-    def add_columns_to_treeview(self, treeview):
-        #Column 0 for the treeview
-        renderer = gtk.CellRendererPixbuf()
-        column = gtk.TreeViewColumn()
-        column.pack_start(renderer, True)
-        column.add_attribute(renderer, "pixbuf", 
-                models.CharacterListModel.C_PORTRAIT)
-        treeview.append_column(column)
-
-        #Column 1 for the treeview
-        renderer = gtk.CellRendererText()
-        column = gtk.TreeViewColumn('Character Name', renderer, 
-                text=models.CharacterListModel.C_NAME)
-        column.set_property("expand", True)
-        treeview.append_column(column)
     def refresh_clicked(self, button):
         hildon.hildon_gtk_window_set_progress_indicator(self.win, 1)
-        self.char_model.get_characters()
+        self.treeview.refresh()
         hildon.hildon_gtk_window_set_progress_indicator(self.win, 0)
-    
 
     def do_charactersheet(self, treeview, path, view_column):
-
         model = treeview.get_model()
         miter = model.get_iter(path)
         
@@ -101,4 +74,30 @@ class mEveMonUI(base.BaseUI):
             pass
 
 
+class CharactersTreeView(hildon.GtkTreeView):
+    def __init__(self, mode, controller):
+        self.controller = controller
+        hildon.GtkTreeView.__init__(self, mode)
+
+        self.char_model = models.CharacterListModel(self.controller)
+        self.set_model(self.char_model)
+        self.add_columns()
+
+    def add_columns(self):
+        #Column 0 for the treeview
+        renderer = gtk.CellRendererPixbuf()
+        column = gtk.TreeViewColumn()
+        column.pack_start(renderer, True)
+        column.add_attribute(renderer, "pixbuf", 
+                models.CharacterListModel.C_PORTRAIT)
+        self.append_column(column)
+
+        #Column 1 for the treeview
+        renderer = gtk.CellRendererText()
+        column = gtk.TreeViewColumn('Character Name', renderer, 
+                text=models.CharacterListModel.C_NAME)
+        column.set_property("expand", True)
+        self.append_column(column)
 
+    def refresh():
+        self.char_model.get_characters()
diff --git a/package/src/ui/fremantle/menu.py b/package/src/ui/fremantle/menu.py
new file mode 100644 (file)
index 0000000..ec2966e
--- /dev/null
@@ -0,0 +1,47 @@
+import hildon
+import gtk
+
+import ui.models as models
+import ui.fremantle.dialogs as dialogs
+
+class Menu(hildon.AppMenu):
+    MENU_ITEMS = { "Settings": 'on_settings_clicked', 
+                   "About": 'on_about_clicked', 
+                   "Refresh": 'on_refresh_clicked' }
+    def __init__(self, win, controller):
+        hildon.AppMenu.__init__(self)
+        self.win = win
+        self.controller = controller
+        self.build_buttons()
+
+    def build_buttons(self):
+        for button_name in self.MENU_ITEMS:
+            self.create_menu_button(button_name)
+        self.show_all()
+
+    def create_menu_button(self, name):
+        button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
+        button.set_label(name)
+        button.connect("clicked", getattr(self, self.MENU_ITEMS[name]))
+        self.append(button)
+
+    def on_refresh_clicked(self, button):
+        pass
+
+    def on_settings_clicked(self, button):
+        setting_dialog = dialogs.SettingsDialog(self.win, self.controller)
+
+    
+    def on_about_clicked(self, button):
+        dialog = gtk.AboutDialog()
+        dialog.set_website(self.controller.about_website)
+        dialog.set_website_label(self.controller.about_website)
+        dialog.set_name(self.controller.about_name)
+        dialog.set_authors(self.controller.about_authors)
+        dialog.set_comments(self.controller.about_text)
+        dialog.set_version(self.controller.app_version)
+        dialog.run()
+        dialog.destroy()
+
+    def report_error(self, error):
+        hildon.hildon_banner_show_information(self.win, '', error)