From 6858d3b64e03da3dbb786c1eb3a13d63cc1b797e Mon Sep 17 00:00:00 2001 From: Ryan Campbell Date: Mon, 13 Sep 2010 20:39:14 -0600 Subject: [PATCH] Refactor Fremantule UI code and implement logging - 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 | 161 +++++++++++--------- package/src/ui/fremantle/base.py | 223 ---------------------------- package/src/ui/fremantle/characterSheet.py | 27 +++- package/src/ui/fremantle/dialogs.py | 160 ++++++++++++++++++++ package/src/ui/fremantle/gui.py | 71 +++++---- package/src/ui/fremantle/menu.py | 47 ++++++ 6 files changed, 351 insertions(+), 338 deletions(-) delete mode 100644 package/src/ui/fremantle/base.py create mode 100644 package/src/ui/fremantle/dialogs.py create mode 100644 package/src/ui/fremantle/menu.py diff --git a/package/src/mevemon.py b/package/src/mevemon.py index 600f058..af2e701 100755 --- a/package/src/mevemon.py +++ b/package/src/mevemon.py @@ -18,34 +18,40 @@ # -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 index d773256..0000000 --- a/package/src/ui/fremantle/base.py +++ /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 . -# - -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 diff --git a/package/src/ui/fremantle/characterSheet.py b/package/src/ui/fremantle/characterSheet.py index ccfa390..133cb01 100644 --- a/package/src/ui/fremantle/characterSheet.py +++ b/package/src/ui/fremantle/characterSheet.py @@ -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("Skill in Training:", vbox, align="normal") + self.add_label("Skill in Training:", 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("Skills:", vbox, align="normal") + self.add_label("Skills:", 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 (Level %d)" % (skill_name, skill.trainingToLevel), - vbox, align="normal") + vbox, align='normal') self.add_label("start time: %s\t\tend time: %s" %(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("No skills are currently being trained", - 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 index 0000000..af1ce18 --- /dev/null +++ b/package/src/ui/fremantle/dialogs.py @@ -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() + + + diff --git a/package/src/ui/fremantle/gui.py b/package/src/ui/fremantle/gui.py index 8a1ceab..7e4a4f7 100644 --- a/package/src/ui/fremantle/gui.py +++ b/package/src/ui/fremantle/gui.py @@ -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 index 0000000..ec2966e --- /dev/null +++ b/package/src/ui/fremantle/menu.py @@ -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) -- 1.7.9.5