X-Git-Url: http://git.maemo.org/git/?p=gonvert;a=blobdiff_plain;f=src%2Fgonvert_glade.py;h=e42b1e49264199a71d6ff88f555e75f944051ae8;hp=3d13fb2ff01c7ebcebe7a62825a936d4c78d9f17;hb=1e2010632954ab734663bbc674b621b33c1d4374;hpb=1cdc08a95be548b35c1745a61bbddb3a297399e8 diff --git a/src/gonvert_glade.py b/src/gonvert_glade.py index 3d13fb2..e42b1e4 100755 --- a/src/gonvert_glade.py +++ b/src/gonvert_glade.py @@ -1,26 +1,38 @@ #!/usr/bin/env python # -*- coding: UTF8 -*- +from __future__ import with_statement + import os +import math import pickle -import string -import gettext import logging +import pango import gobject import gtk import gtk.glade import gtk.gdk import constants +import hildonize +import gtk_toolbox import unit_data +try: + import gettext +except ImportError: + _ = lambda x: x + gettext = None +else: + _ = gettext.gettext + _moduleLogger = logging.getLogger("gonvert_glade") -gettext.bindtextdomain('gonvert', '/usr/share/locale') -gettext.textdomain('gonvert') -_ = gettext.gettext +if gettext is not None: + gettext.bindtextdomain('gonvert', '/usr/share/locale') + gettext.textdomain('gonvert') def change_menu_label(widgets, labelname, newtext): @@ -28,27 +40,60 @@ def change_menu_label(widgets, labelname, newtext): item_label.set_text(newtext) +def split_number(number): + try: + fractional, integer = math.modf(number) + except TypeError: + integerDisplay = number + fractionalDisplay = "" + else: + integerDisplay = str(integer) + fractionalDisplay = str(fractional) + if "e+" in integerDisplay: + integerDisplay = number + fractionalDisplay = "" + elif "e-" in fractionalDisplay and 0.0 < integer: + integerDisplay = number + fractionalDisplay = "" + elif "e-" in fractionalDisplay: + integerDisplay = "" + fractionalDisplay = number + else: + integerDisplay = integerDisplay.split(".", 1)[0] + "." + fractionalDisplay = fractionalDisplay.rsplit(".", 1)[-1] + + return integerDisplay, fractionalDisplay + + class Gonvert(object): _glade_files = [ os.path.join(os.path.dirname(__file__), "gonvert.glade"), os.path.join(os.path.dirname(__file__), "../data/gonvert.glade"), os.path.join(os.path.dirname(__file__), "../lib/gonvert.glade"), + '/usr/share/gonvert/gonvert.glade', '/usr/lib/gonvert/gonvert.glade', ] + UNITS_NAME_IDX = 0 + UNITS_VALUE_IDX = 1 + UNITS_SYMBOL_IDX = 2 + UNITS_INTEGER_IDX = 3 + UNITS_FRACTION_IDX = 4 + def __init__(self): self._unitDataInCategory = None - self._calcsuppress = False self._unit_sort_direction = False self._value_sort_direction = False self._units_sort_direction = False + self.__isPortrait = False self._isFullScreen = False + self._clipboard = gtk.clipboard_get() self._find_result = [] # empty find result list self._findIndex = 0 # default to find result number zero - self._selectedCategory = '' # preset to no selected category + self._selectedCategoryName = '' # preset to no selected category self._defaultUnitForCategory = {} # empty dictionary for later use #check to see if glade file is in current directory (user must be @@ -65,19 +110,15 @@ class Gonvert(object): return self._mainWindow = widgets.get_widget('mainWindow') + self._app = hildonize.get_app_class()() + self._mainWindow = hildonize.hildonize_window(self._app, self._mainWindow) change_menu_label(widgets, 'fileMenuItem', _('File')) change_menu_label(widgets, 'exitMenuItem', _('Exit')) - change_menu_label(widgets, 'toolsMenuItem', _('Tools')) - change_menu_label(widgets, 'clearSelectionMenuItem', _('Clear selections')) - change_menu_label(widgets, 'writeUnitsMenuItem', _('Write Units')) change_menu_label(widgets, 'helpMenuItem', _('Help')) change_menu_label(widgets, 'aboutMenuItem', _('About')) - change_menu_label(widgets, 'findButton', _('Find')) - - self._shortlistcheck = widgets.get_widget('shortlistcheck') - self._toggleShortList = widgets.get_widget('toggleShortList') + self._categorySelectionButton = widgets.get_widget("categorySelectionButton") self._categoryView = widgets.get_widget('categoryView') self._unitsView = widgets.get_widget('unitsView') @@ -88,8 +129,6 @@ class Gonvert(object): self._unitValue = widgets.get_widget('unitValue') self._previousUnitName = widgets.get_widget('previousUnitName') self._previousUnitValue = widgets.get_widget('previousUnitValue') - messagebox = widgets.get_widget('msgbox') - messageboxtext = widgets.get_widget('msgboxtext') self._unitSymbol = widgets.get_widget('unitSymbol') self._previousUnitSymbol = widgets.get_widget('previousUnitSymbol') @@ -101,33 +140,59 @@ class Gonvert(object): self._findEntry = widgets.get_widget('findEntry') self._findLabel = widgets.get_widget('findLabel') self._findButton = widgets.get_widget('findButton') - ToolTips = gtk.Tooltips() - ToolTips.set_tip(self._findButton, _(u'Find unit (F6)')) - - #insert a self._categoryColumnumn into the units list even though the heading will not be seen - renderer = gtk.CellRendererText() - self._unitNameColumn = gtk.TreeViewColumn(_('Unit Name'), renderer) - self._unitNameColumn.set_property('resizable', 1) - self._unitNameColumn.add_attribute(renderer, 'text', 0) + self._closeSearchButton = widgets.get_widget('closeSearchButton') + + self._unitsNameRenderer = gtk.CellRendererText() + self._unitsNameRenderer.set_property("scale", 0.75) + if constants.FORCE_HILDON_LIKE: + self._unitsNameRenderer.set_property("ellipsize", pango.ELLIPSIZE_END) + self._unitsNameRenderer.set_property("width-chars", 5) + self._unitNameColumn = gtk.TreeViewColumn(_('Name'), self._unitsNameRenderer) + self._unitNameColumn.set_property('resizable', True) + self._unitNameColumn.add_attribute(self._unitsNameRenderer, 'text', self.UNITS_NAME_IDX) self._unitNameColumn.set_clickable(True) self._unitNameColumn.connect("clicked", self._on_click_unit_column) self._unitsView.append_column(self._unitNameColumn) - self._unitValueColumn = gtk.TreeViewColumn(_('Value'), renderer) - self._unitValueColumn.set_property('resizable', 1) - self._unitValueColumn.add_attribute(renderer, 'text', 1) - self._unitValueColumn.set_clickable(True) - self._unitValueColumn.connect("clicked", self._on_click_unit_column) - self._unitsView.append_column(self._unitValueColumn) + renderer = gtk.CellRendererText() + renderer.set_property("xalign", 1.0) + renderer.set_property("alignment", pango.ALIGN_RIGHT) + hildonize.set_cell_thumb_selectable(renderer) + self._unitIntegerColumn = gtk.TreeViewColumn(_('Value'), renderer) + self._unitIntegerColumn.set_property('resizable', True) + self._unitIntegerColumn.add_attribute(renderer, 'text', self.UNITS_INTEGER_IDX) + self._unitIntegerColumn.set_clickable(True) + self._unitIntegerColumn.connect("clicked", self._on_click_unit_column) + self._unitsView.append_column(self._unitIntegerColumn) + + renderer = gtk.CellRendererText() + renderer.set_property("xalign", 0.0) + renderer.set_property("alignment", pango.ALIGN_LEFT) + renderer.set_property("scale", 0.75) + self._unitFractionalColumn = gtk.TreeViewColumn(_(''), renderer) + self._unitFractionalColumn.set_property('resizable', True) + self._unitFractionalColumn.add_attribute(renderer, 'text', self.UNITS_FRACTION_IDX) + self._unitFractionalColumn.set_clickable(True) + self._unitFractionalColumn.connect("clicked", self._on_click_unit_column) + self._unitsView.append_column(self._unitFractionalColumn) + renderer = gtk.CellRendererText() + renderer.set_property("ellipsize", pango.ELLIPSIZE_END) + #renderer.set_property("scale", 0.5) self._unitSymbolColumn = gtk.TreeViewColumn(_('Units'), renderer) - self._unitSymbolColumn.set_property('resizable', 1) - self._unitSymbolColumn.add_attribute(renderer, 'text', 2) + self._unitSymbolColumn.set_property('resizable', True) + self._unitSymbolColumn.add_attribute(renderer, 'text', self.UNITS_SYMBOL_IDX) self._unitSymbolColumn.set_clickable(True) self._unitSymbolColumn.connect("clicked", self._on_click_unit_column) self._unitsView.append_column(self._unitSymbolColumn) - self._unitModel = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING) + self._unitModel = gtk.ListStore( + gobject.TYPE_STRING, # UNITS_NAME_IDX + gobject.TYPE_STRING, # UNITS_VALUE_IDX + gobject.TYPE_STRING, # UNITS_SYMBOL_IDX + gobject.TYPE_STRING, # UNITS_INTEGER_IDX + gobject.TYPE_STRING, # UNITS_FRACTION_IDX + ) self._sortedUnitModel = gtk.TreeModelSort(self._unitModel) columns = self._get_column_sort_stuff() for columnIndex, (column, sortDirection, col_cmp) in enumerate(columns): @@ -148,32 +213,82 @@ class Gonvert(object): #Populate the catagories list for key in unit_data.UNIT_CATEGORIES: - iter = self._categoryModel.append() - self._categoryModel.set(iter, 0, key) + row = (key, ) + self._categoryModel.append(row) #--------- connections to GUI ---------------- - dic = { - "on_exit_menu_activate": self._on_user_exit, - "on_main_window_destroy": self._on_user_exit, - "on_categoryView_select_row": self._on_click_category, - "on_unitValue_changed": self._on_unit_value_changed, - "on_previousUnitValue_changed": self._on_previous_unit_value_changed, - "on_writeUnitsMenuItem_activate": self._on_user_write_units, - "on_findButton_clicked": self._on_find_activate, - "on_findEntry_activated": self._on_find_activate, - "on_findEntry_changed": self._on_findEntry_changed, - "on_aboutMenuItem_activate": self._on_about_clicked, - "on_messagebox_ok_clicked": self.messagebox_ok_clicked, - "on_clearSelectionMenuItem_activate": self._on_user_clear_selections, - "on_unitsView_cursor_changed": self._on_click_unit, - "on_shortlistcheck_toggled": self._on_shortlist_changed, - "on_toggleShortList_activate": self._on_edit_shortlist, - } - widgets.signal_autoconnect(dic) + self._mainWindow.connect("destroy", self._on_user_exit) self._mainWindow.connect("key-press-event", self._on_key_press) self._mainWindow.connect("window-state-event", self._on_window_state_change) + self._categorySelectionButton.connect("clicked", self._on_category_selector_clicked) + self._categoryView.connect("cursor-changed", self._on_click_category) + self._findButton.connect("clicked", self._on_find_activate) + self._findEntry.connect("activate", self._on_find_activate) + self._findEntry.connect("changed", self._on_findEntry_changed) + self._closeSearchButton.connect("clicked", self._on_toggle_search) + self._previousUnitValue.connect("changed", self._on_previous_unit_value_changed) + self._unitValue.connect("changed", self._on_unit_value_changed) + self._unitValue.connect("key-press-event", self._on_browse_key_press) + self._unitsView.connect("cursor-changed", self._on_click_unit) + self._unitsView.connect("key-press-event", self._on_browse_key_press) + if hildonize.GTK_MENU_USED: + widgets.get_widget("aboutMenuItem").connect("activate", self._on_about_clicked) + widgets.get_widget("searchMenuItem").connect("activate", self._on_toggle_search) + widgets.get_widget("exitMenuItem").connect("activate", self._on_user_exit) + + for scrollingWidgetName in ( + "unitsViewScrolledWindow", + ): + scrollingWidget = widgets.get_widget(scrollingWidgetName) + assert scrollingWidget is not None, scrollingWidgetName + scroller = hildonize.hildonize_scrollwindow(scrollingWidget) + scroller.show_all() + + # Simplify the UI + if hildonize.IS_HILDON_SUPPORTED or constants.FORCE_HILDON_LIKE: + self._categoryView.get_parent().hide() + self._unitsView.set_headers_visible(False) + self._previousUnitName.get_parent().hide() + self._unitDescription.get_parent().get_parent().hide() + else: + self._categorySelectionButton.hide() - self._mainWindow.set_title('gonvert- %s - Unit Conversion Utility' % constants.__version__) + menu = hildonize.hildonize_menu( + self._mainWindow, + widgets.get_widget("mainMenuBar"), + ) + if not hildonize.GTK_MENU_USED: + button = gtk.Button("Search") + button.connect("clicked", self._on_toggle_search) + menu.append(button) + + button = hildonize.hildon.GtkRadioButton(gtk.HILDON_SIZE_AUTO, None) + button.set_label("Name") + menu.add_filter(button) + button.connect("clicked", self._on_click_menu_filter, self._unitNameColumn) + button.set_mode(False) + filterGroup = button + + button = hildonize.hildon.GtkRadioButton(gtk.HILDON_SIZE_AUTO, filterGroup) + button.set_label("Value") + menu.add_filter(button) + button.connect("clicked", self._on_click_menu_filter, self._unitIntegerColumn) + button.set_mode(False) + + button = hildonize.hildon.GtkRadioButton(gtk.HILDON_SIZE_AUTO, filterGroup) + button.set_label("Unit") + menu.add_filter(button) + button.connect("clicked", self._on_click_menu_filter, self._unitSymbolColumn) + button.set_mode(False) + + menu.show_all() + + if not hildonize.IS_HILDON_SUPPORTED: + _moduleLogger.info("No hildonization support") + + hildonize.set_application_name( + "%s - Unit Conversion Utility" % constants.__pretty_app_name__ + ) iconPath = pixmapspath + '/gonvert.png' if os.path.exists(iconPath): self._mainWindow.set_icon(gtk.gdk.pixbuf_new_from_file(iconPath)) @@ -181,52 +296,62 @@ class Gonvert(object): _moduleLogger.warn("Error: Could not find gonvert icon: %s" % iconPath) self._load_settings() + self._mainWindow.show() def _load_settings(self): #Restore window size from previously saved settings if it exists and is valid. windowDatPath = "/".join((constants._data_path_, "window.dat")) if os.path.exists(windowDatPath): - #Retrieving previous window settings from ~/.gonvert/window.dat saved_window = pickle.load(open(windowDatPath, "r")) - #If the 'size' has been stored, then extract size from saved_window. - if 'size' in saved_window: + try: a, b = saved_window['size'] + except KeyError: + pass + else: self._mainWindow.resize(a, b) + try: + isFullscreen = saved_window["isFullscreen"] + except KeyError: + pass else: - #Maximize if no previous size was found - #self._mainWindow.maximize() + if isFullscreen: + self._mainWindow.fullscreen() + try: + isPortrait = saved_window["isPortrait"] + except KeyError: pass - else: - #Maximize if no previous window.dat file was found - #self._mainWindow.maximize() - pass + else: + if isPortrait ^ self.__isPortrait: + if isPortrait: + orientation = gtk.ORIENTATION_VERTICAL + else: + orientation = gtk.ORIENTATION_HORIZONTAL + self.set_orientation(orientation) #Restore selections from previously saved settings if it exists and is valid. - historical_catergory_found = False + categoryIndex = 0 + selectedCategoryName = unit_data.UNIT_CATEGORIES[0] selectionsDatPath = "/".join((constants._data_path_, "selections.dat")) if os.path.exists(selectionsDatPath): - #Retrieving previous selections from ~/.gonvert/selections.dat selections = pickle.load(open(selectionsDatPath, 'r')) - #Restoring previous selections. - #If the 'selected_unts' has been stored, then extract self._defaultUnitForCategory from selections. - if 'selected_units' in selections: + try: self._defaultUnitForCategory = selections['selected_units'] - #Make sure that the 'self._selectedCategory' has been stored. - if 'selected_category' in selections: - #Match an available category to the previously selected category. - for counter in range(len(unit_data.UNIT_CATEGORIES)): - if selections['selected_category'] == unit_data.UNIT_CATEGORIES[counter]: - # Restore the previously selected category. - self._categoryView.set_cursor(counter, self._categoryColumn, False) - self._categoryView.grab_focus() - historical_catergory_found = True - - if not historical_catergory_found: - print "Couldn't find saved category, using default." - #If historical records were not kept then default to - # put the focus on the first category - self._categoryView.set_cursor(0, self._categoryColumn, False) - self._categoryView.grab_focus() + except KeyError: + pass + + try: + selectedCategoryName = selections['selected_category'] + except KeyError: + pass + else: + try: + categoryIndex = unit_data.UNIT_CATEGORIES.index(selectedCategoryName) + except ValueError: + _moduleLogger.warn("Unknown category: %s" % selectedCategoryName) + + self._categorySelectionButton.get_child().set_markup("%s" % selectedCategoryName) + self._categoryView.set_cursor(categoryIndex, self._categoryColumn, False) + self._categoryView.grab_focus() self._select_default_unit() @@ -236,16 +361,16 @@ class Gonvert(object): should therefore only be called when exiting the program. Update selections dictionary which consists of the following keys: - 'self._selectedCategory': full name of selected category + 'self._selectedCategoryName': full name of selected category 'self._defaultUnitForCategory': self._defaultUnitForCategory dictionary which contains: [categoryname: #1 displayed unit, #2 displayed unit] """ #Determine the contents of the selected category row selected, iter = self._categoryView.get_selection().get_selected() - self._selectedCategory = self._categoryModel.get_value(iter, 0) + self._selectedCategoryName = self._categoryModel.get_value(iter, 0) selections = { - 'selected_category': self._selectedCategory, + 'selected_category': self._selectedCategoryName, 'selected_units': self._defaultUnitForCategory } selectionsDatPath = "/".join((constants._data_path_, "selections.dat")) @@ -253,11 +378,24 @@ class Gonvert(object): #Get last size of app and save it window_settings = { - 'size': self._mainWindow.get_size() + 'size': self._mainWindow.get_size(), + "isFullscreen": self._isFullScreen, + "isPortrait": self.__isPortrait, } windowDatPath = "/".join((constants._data_path_, "window.dat")) pickle.dump(window_settings, open(windowDatPath, 'w')) + def _refresh_columns(self): + self._unitsView.remove_column(self._unitNameColumn) + self._unitsView.remove_column(self._unitIntegerColumn) + self._unitsView.remove_column(self._unitFractionalColumn) + self._unitsView.remove_column(self._unitSymbolColumn) + + self._unitsView.append_column(self._unitNameColumn) + self._unitsView.append_column(self._unitIntegerColumn) + self._unitsView.append_column(self._unitFractionalColumn) + self._unitsView.append_column(self._unitSymbolColumn) + def _clear_find(self): # switch to "new find" state self._find_result = [] @@ -269,7 +407,7 @@ class Gonvert(object): def _find_first(self): assert len(self._find_result) == 0 assert self._findIndex == 0 - findString = string.lower(string.strip(self._findEntry.get_text())) + findString = self._findEntry.get_text().strip().lower() if not findString: return @@ -285,7 +423,9 @@ class Gonvert(object): assert 0 < len(self._find_result) #check if next find is in a new category (prevent category changes when unnecessary - if self._selectedCategory != self._find_result[self._findIndex][0]: + searchCategoryName = self._find_result[self._findIndex][0] + if self._selectedCategoryName != searchCategoryName: + self._categorySelectionButton.get_child().set_markup("%s" % searchCategoryName) self._categoryView.set_cursor( self._find_result[self._findIndex][2], self._categoryColumn, False ) @@ -295,18 +435,6 @@ class Gonvert(object): ) def _find_next(self): - """ - check if 'new find' or 'last find' or 'next-find' - - new-find = run the find algorithm which also selects the first found unit - = self._findIndex = 0 and self._find_result = [] - - last-find = restart from top again - = self._findIndex = len(self._find_result) - - next-find = continue to next found location - = self._findIndex = 0 and len(self._find_result)>0 - """ if len(self._find_result) == 0: self._find_first() else: @@ -325,18 +453,6 @@ class Gonvert(object): ) def _find_previous(self): - """ - check if 'new find' or 'last find' or 'next-find' - - new-find = run the find algorithm which also selects the first found unit - = self._findIndex = 0 and self._find_result = [] - - last-find = restart from top again - = self._findIndex = len(self._find_result) - - next-find = continue to next found location - = self._findIndex = 0 and len(self._find_result)>0 - """ if len(self._find_result) == 0: self._find_first() else: @@ -357,51 +473,62 @@ class Gonvert(object): def _toggle_find(self): if self._searchLayout.get_property("visible"): self._searchLayout.hide() + self._unitsView.grab_focus() else: self._searchLayout.show() + self._findEntry.grab_focus() def _unit_model_cmp(self, sortedModel, leftItr, rightItr): - leftUnitText = self._unitModel.get_value(leftItr, 0) - rightUnitText = self._unitModel.get_value(rightItr, 0) + leftUnitText = self._unitModel.get_value(leftItr, self.UNITS_NAME_IDX) + rightUnitText = self._unitModel.get_value(rightItr, self.UNITS_NAME_IDX) return cmp(leftUnitText, rightUnitText) def _symbol_model_cmp(self, sortedModel, leftItr, rightItr): - leftSymbolText = self._unitModel.get_value(leftItr, 2) - rightSymbolText = self._unitModel.get_value(rightItr, 2) + leftSymbolText = self._unitModel.get_value(leftItr, self.UNITS_SYMBOL_IDX) + rightSymbolText = self._unitModel.get_value(rightItr, self.UNITS_SYMBOL_IDX) return cmp(leftSymbolText, rightSymbolText) def _value_model_cmp(self, sortedModel, leftItr, rightItr): #special sorting exceptions for ascii values (instead of float values) - if self._selectedCategory == "Computer Numbers": - leftValue = self._unitModel.get_value(leftItr, 1) - rightValue = self._unitModel.get_value(rightItr, 1) + if self._selectedCategoryName == "Computer Numbers": + leftValue = self._unitModel.get_value(leftItr, self.UNITS_VALUE_IDX) + rightValue = self._unitModel.get_value(rightItr, self.UNITS_VALUE_IDX) else: - leftValueText = self._unitModel.get_value(leftItr, 1) + leftValueText = self._unitModel.get_value(leftItr, self.UNITS_VALUE_IDX) leftValue = float(leftValueText) if leftValueText else 0.0 - rightValueText = self._unitModel.get_value(rightItr, 1) + rightValueText = self._unitModel.get_value(rightItr, self.UNITS_VALUE_IDX) rightValue = float(rightValueText) if rightValueText else 0.0 return cmp(leftValue, rightValue) def _get_column_sort_stuff(self): columns = ( (self._unitNameColumn, "_unit_sort_direction", self._unit_model_cmp), - (self._unitValueColumn, "_value_sort_direction", self._value_model_cmp), + (self._unitIntegerColumn, "_value_sort_direction", self._value_model_cmp), + (self._unitFractionalColumn, "_value_sort_direction", self._value_model_cmp), (self._unitSymbolColumn, "_units_sort_direction", self._symbol_model_cmp), ) return columns def _switch_category(self, category): - self._selectedCategory = category - self._unitDataInCategory = unit_data.UNIT_DESCRIPTIONS[self._selectedCategory] + self._selectedCategoryName = category + self._unitDataInCategory = unit_data.UNIT_DESCRIPTIONS[self._selectedCategoryName] #Fill up the units descriptions and clear the value cells self._clear_visible_unit_data() - for key in unit_data.get_units(self._selectedCategory): - iter = self._unitModel.append() - self._unitModel.set(iter, 0, key, 1, '', 2, self._unitDataInCategory[key][1]) + nameLength = 0 + for key in unit_data.get_units(self._selectedCategoryName): + row = key, '0.0', self._unitDataInCategory[key][1], '0.', '0' + self._unitModel.append(row) + nameLength = max(nameLength, len(key)) self._sortedUnitModel.sort_column_changed() + if constants.FORCE_HILDON_LIKE: + maxCatCharWidth = int(nameLength * 0.75) + maxCharWidth = int(len("nibble | hexit | quadbit") * 0.75) + charWidth = min(maxCatCharWidth, maxCharWidth) + self._unitsNameRenderer.set_property("width-chars", charWidth) + self._select_default_unit() def _clear_visible_unit_data(self): @@ -419,300 +546,311 @@ class Gonvert(object): def _select_default_unit(self): # Restore the previous historical settings of previously selected units # in this newly selected category - if self._selectedCategory in self._defaultUnitForCategory: - units = unit_data.get_units(self._selectedCategory) - - #Restore oldest selection first. - if self._defaultUnitForCategory[self._selectedCategory][1]: - unitIndex = units.index(self._defaultUnitForCategory[self._selectedCategory][1]) - self._unitsView.set_cursor(unitIndex, self._unitNameColumn, True) - - #Restore newest selection second. - if self._defaultUnitForCategory[self._selectedCategory][0]: - unitIndex = units.index(self._defaultUnitForCategory[self._selectedCategory][0]) - self._unitsView.set_cursor(unitIndex, self._unitNameColumn, True) + defaultPrimary = unit_data.get_base_unit(self._selectedCategoryName) + defaultSecondary = "" + if self._selectedCategoryName in self._defaultUnitForCategory: + if self._defaultUnitForCategory[self._selectedCategoryName][0]: + defaultPrimary = self._defaultUnitForCategory[self._selectedCategoryName][0] + if self._defaultUnitForCategory[self._selectedCategoryName][1]: + defaultSecondary = self._defaultUnitForCategory[self._selectedCategoryName][1] + + units = unit_data.get_units(self._selectedCategoryName) + + #Restore oldest selection first. + if defaultPrimary: + try: + unitIndex = units.index(defaultPrimary) + except ValueError: + unitIndex = 0 + self._unitsView.set_cursor(unitIndex, self._unitNameColumn, True) + + #Restore newest selection second. + if defaultSecondary: + try: + unitIndex = units.index(defaultSecondary) + except ValueError: + unitIndex = 0 + self._unitsView.set_cursor(unitIndex, self._unitNameColumn, True) # select the text so user can start typing right away self._unitValue.grab_focus() self._unitValue.select_region(0, -1) - def _on_shortlist_changed(self, *args): - try: - raise NotImplementedError("%s" % self._shortlistcheck.get_active()) - except Exception: - _moduleLogger.exception("") + def _sanitize_value(self, userEntry): + if self._selectedCategoryName == "Computer Numbers": + if userEntry == '': + value = '0' + else: + value = userEntry + else: + if userEntry == '': + value = 0.0 + else: + value = float(userEntry) + return value - def _on_edit_shortlist(self, *args): - try: - raise NotImplementedError("%s" % self._toggleShortList.get_active()) - except Exception: - _moduleLogger.exception("") + def _select_sort_column(self, col): + #Determine which column requires sorting + columns = self._get_column_sort_stuff() + for columnIndex, (maybeCol, directionName, col_cmp) in enumerate(columns): + if col is maybeCol: + direction = getattr(self, directionName) + gtkDirection = gtk.SORT_ASCENDING if direction else gtk.SORT_DESCENDING - def _on_user_clear_selections(self, *args): - try: - selectionsDatPath = "/".join((constants._data_path_, "selections.dat")) - os.remove(selectionsDatPath) - self._defaultUnitForCategory = {} - except Exception: - _moduleLogger.exception("") + # cause a sort + self._sortedUnitModel.set_sort_column_id(columnIndex, gtkDirection) + + # set the visual for sorting + col.set_sort_indicator(True) + col.set_sort_order(not direction) + + setattr(self, directionName, not direction) + break + else: + maybeCol.set_sort_indicator(False) + else: + assert False, "Unknown column: %s" % (col.get_title(), ) + + def set_orientation(self, orientation): + if orientation == gtk.ORIENTATION_VERTICAL: + hildonize.window_to_portrait(self._mainWindow) + self.__isPortrait = True + elif orientation == gtk.ORIENTATION_HORIZONTAL: + hildonize.window_to_landscape(self._mainWindow) + self.__isPortrait = False + else: + raise NotImplementedError(orientation) + + def get_orientation(self): + return gtk.ORIENTATION_VERTICAL if self.__isPortrait else gtk.ORIENTATION_HORIZONTAL + + def _toggle_rotate(self): + if self.__isPortrait: + self.set_orientation(gtk.ORIENTATION_HORIZONTAL) + else: + self.set_orientation(gtk.ORIENTATION_VERTICAL) + @gtk_toolbox.log_exception(_moduleLogger) def _on_key_press(self, widget, event, *args): """ @note Hildon specific """ RETURN_TYPES = (gtk.keysyms.Return, gtk.keysyms.ISO_Enter, gtk.keysyms.KP_Enter) - try: - if ( - event.keyval == gtk.keysyms.F6 or - event.keyval in RETURN_TYPES and event.get_state() & gtk.gdk.CONTROL_MASK - ): - if self._isFullScreen: - self._mainWindow.unfullscreen() - else: - self._mainWindow.fullscreen() - elif event.keyval == gtk.keysyms.f and event.get_state() & gtk.gdk.CONTROL_MASK: + if ( + event.keyval == gtk.keysyms.F6 or + event.keyval in RETURN_TYPES and event.get_state() & gtk.gdk.CONTROL_MASK + ): + if self._isFullScreen: + self._mainWindow.unfullscreen() + else: + self._mainWindow.fullscreen() + elif event.keyval == gtk.keysyms.f and event.get_state() & gtk.gdk.CONTROL_MASK: + if not hildonize.GTK_MENU_USED: self._toggle_find() - elif event.keyval == gtk.keysyms.p and event.get_state() & gtk.gdk.CONTROL_MASK: - self._find_previous() - elif event.keyval == gtk.keysyms.n and event.get_state() & gtk.gdk.CONTROL_MASK: - self._find_next() - except Exception, e: - _moduleLogger.exception("") - + elif event.keyval == gtk.keysyms.p and event.get_state() & gtk.gdk.CONTROL_MASK: + self._find_previous() + elif event.keyval == gtk.keysyms.n and event.get_state() & gtk.gdk.CONTROL_MASK: + self._find_next() + elif event.keyval == gtk.keysyms.o and event.get_state() & gtk.gdk.CONTROL_MASK: + self._toggle_rotate() + elif ( + event.keyval in (gtk.keysyms.w, gtk.keysyms.q) and + event.get_state() & gtk.gdk.CONTROL_MASK + ): + self._mainWindow.destroy() + elif event.keyval == gtk.keysyms.l and event.get_state() & gtk.gdk.CONTROL_MASK: + with open(constants._user_logpath_, "r") as f: + logLines = f.xreadlines() + log = "".join(logLines) + self._clipboard.set_text(str(log)) + + @gtk_toolbox.log_exception(_moduleLogger) + def _on_toggle_search(self, *args): + self._toggle_find() + + @gtk_toolbox.log_exception(_moduleLogger) + def _on_browse_key_press(self, widget, event, *args): + if event.keyval == gtk.keysyms.uparrow or event.keyval == gtk.keysyms.Up: + index, column = self._unitsView.get_cursor() + newIndex = max(index[0]-1, 0) + path = (newIndex, ) + self._unitsView.set_cursor(path, column, True) + self._unitsView.scroll_to_cell(path, column, False, 0, 0) + return True # override default behavior + elif event.keyval == gtk.keysyms.downarrow or event.keyval == gtk.keysyms.Down: + index, column = self._unitsView.get_cursor() + newIndex = min(index[0]+1, len(self._unitModel)-1) + path = (newIndex, ) + self._unitsView.set_cursor(path, column, True) + self._unitsView.scroll_to_cell(path, column, False, 0, 0) + return True # override default behavior + + @gtk_toolbox.log_exception(_moduleLogger) def _on_window_state_change(self, widget, event, *args): """ @note Hildon specific """ - try: - if event.new_window_state & gtk.gdk.WINDOW_STATE_FULLSCREEN: - self._isFullScreen = True - else: - self._isFullScreen = False - except Exception, e: - _moduleLogger.exception("") + if event.new_window_state & gtk.gdk.WINDOW_STATE_FULLSCREEN: + self._isFullScreen = True + else: + self._isFullScreen = False + @gtk_toolbox.log_exception(_moduleLogger) def _on_findEntry_changed(self, *args): """ Clear out find results since the user wants to look for something new """ - try: - self._clear_find() - except Exception: - _moduleLogger.exception("") + self._clear_find() - def _on_find_activate(self, a): - try: - self._find_next() - self._findButton.grab_focus() - except Exception: - _moduleLogger.exception("") + @gtk_toolbox.log_exception(_moduleLogger) + def _on_find_activate(self, *args): + self._find_next() + self._findButton.grab_focus() + + @gtk_toolbox.log_exception(_moduleLogger) + def _on_click_menu_filter(self, button, col): + self._select_sort_column(col) + @gtk_toolbox.log_exception(_moduleLogger) def _on_click_unit_column(self, col): """ Sort the contents of the col when the user clicks on the title. """ - try: - #Determine which column requires sorting - columns = self._get_column_sort_stuff() - for columnIndex, (maybeCol, directionName, col_cmp) in enumerate(columns): - if col is maybeCol: - direction = getattr(self, directionName) - gtkDirection = gtk.SORT_ASCENDING if direction else gtk.SORT_DESCENDING - - # cause a sort - self._sortedUnitModel.set_sort_column_id(columnIndex, gtkDirection) - - # set the visual for sorting - col.set_sort_indicator(True) - col.set_sort_order(not direction) - - setattr(self, directionName, not direction) - break - else: - maybeCol.set_sort_indicator(False) - else: - assert False, "Unknown column: %s" % (col.get_title(), ) - except Exception: - _moduleLogger.exception("") + self._select_sort_column(col) + + @gtk_toolbox.log_exception(_moduleLogger) + def _on_category_selector_clicked(self, *args): + currenntIndex = unit_data.UNIT_CATEGORIES.index(self._selectedCategoryName) + newIndex = hildonize.touch_selector( + self._mainWindow, + "Categories", + unit_data.UNIT_CATEGORIES, + currenntIndex, + ) - def _on_click_category(self, *args): - try: - selected, iter = self._categoryView.get_selection().get_selected() - selectedCategory = self._categoryModel.get_value(iter, 0) - self._switch_category(selectedCategory) - except Exception: - _moduleLogger.exception("") + selectedCategoryName = unit_data.UNIT_CATEGORIES[newIndex] + self._categorySelectionButton.get_child().set_markup("%s" % selectedCategoryName) + self._switch_category(selectedCategoryName) - def _on_click_unit(self, row): - self._calcsuppress = True #suppress calculations + @gtk_toolbox.log_exception(_moduleLogger) + def _on_click_category(self, *args): + selected, iter = self._categoryView.get_selection().get_selected() + if iter is None: + # User is typing in an invalid string, not selecting any category + return + selectedCategory = self._categoryModel.get_value(iter, 0) + self._switch_category(selectedCategory) - #Determine the contents of the selected row. + @gtk_toolbox.log_exception(_moduleLogger) + def _on_click_unit(self, *args): selected, iter = self._unitsView.get_selection().get_selected() - - selected_unit = selected.get_value(iter, 0) - + selected_unit = selected.get_value(iter, self.UNITS_NAME_IDX) unit_spec = self._unitDataInCategory[selected_unit] - #Clear out the description - text_model = gtk.TextBuffer(None) - self._unitDescription.set_buffer(text_model) - - enditer = text_model.get_end_iter() - text_model.insert(enditer, unit_spec[2]) + showSymbol = False if self._unitName.get_text() != selected_unit: self._previousUnitName.set_text(self._unitName.get_text()) self._previousUnitValue.set_text(self._unitValue.get_text()) - if self._unitSymbol.get() == None: - self._previousUnitSymbol.set_text('') - else: - self._previousUnitSymbol.set_text(self._unitSymbol.get()) + self._previousUnitSymbol.set_text(self._unitSymbol.get_text()) + if self._unitSymbol.get_text(): + showSymbol = True + self._unitName.set_text(selected_unit) + self._unitValue.set_text(selected.get_value(iter, self.UNITS_VALUE_IDX)) + buffer = self._unitDescription.get_buffer() + buffer.set_text(unit_spec[2]) + self._unitSymbol.set_text(unit_spec[1]) # put units into label text + if unit_spec[1]: + showSymbol = True + else: + showSymbol = False - self._unitValue.set_text(selected.get_value(iter, 1)) + if showSymbol: + self._unitSymbol.show() + self._previousUnitSymbol.show() + else: + self._unitSymbol.hide() + self._previousUnitSymbol.hide() - self._unitSymbol.set_text(unit_spec[1]) # put units into label text if self._unitValue.get_text() == '': - if self._selectedCategory == "Computer Numbers": + if self._selectedCategoryName == "Computer Numbers": self._unitValue.set_text("0") else: self._unitValue.set_text("0.0") - #For historical purposes, record this unit as the most recent one in this category. - # Also, if a previous unit exists, then shift that previous unit to oldest unit. - if self._selectedCategory in self._defaultUnitForCategory: - if self._defaultUnitForCategory[self._selectedCategory][0]: - self._defaultUnitForCategory[self._selectedCategory] = [selected_unit, self._defaultUnitForCategory[self._selectedCategory][0]] - else: - self._defaultUnitForCategory[self._selectedCategory] = [selected_unit, ''] + self._defaultUnitForCategory[self._selectedCategoryName] = [ + self._unitName.get_text(), self._previousUnitName.get_text() + ] # select the text so user can start typing right away self._unitValue.grab_focus() self._unitValue.select_region(0, -1) - self._calcsuppress = False #enable calculations - - def messagebox_ok_clicked(self, a): - messagebox.hide() - - def _on_user_write_units(self, a): - ''"Write the list of categories and units to stdout for documentation purposes.''" - messagebox_model = gtk.TextBuffer(None) - messageboxtext.set_buffer(messagebox_model) - messagebox_model.insert_at_cursor(_(u'The units are being written to stdout. You can capture this printout by starting gonvert from the command line as follows: \n$ gonvert > file.txt'), -1) - messagebox.show() - while gtk.events_pending(): - gtk.mainiteration(False) - - total_categories = 0 - total_units = 0 - print 'gonvert-%s%s' % ( - constants.__version__, - _(u' - Unit Conversion Utility - Convertible units listing: ') - ) - for category_key in unit_data.UNIT_CATEGORIES: - total_categories = total_categories + 1 - print category_key, ": " - self._unitDataInCategory = unit_data.UNIT_DESCRIPTIONS[category_key] - unit_keys = self._unitDataInCategory.keys() - unit_keys.sort() - del unit_keys[0] # do not display .base_unit description key - for unit_key in unit_keys: - total_units = total_units + 1 - print "\t", unit_key - print total_categories, ' categories' - print total_units, ' units' - - def _on_unit_value_changed(self, a): - if self._calcsuppress: - #self._calcsuppress = False + @gtk_toolbox.log_exception(_moduleLogger) + def _on_unit_value_changed(self, *args): + if self._unitName.get_text() == '': + return + if not self._unitValue.is_focus(): return - # determine if value to be calculated is empty - if self._selectedCategory == "Computer Numbers": - if self._unitValue.get_text() == '': - value = '0' - else: - value = self._unitValue.get_text() - else: - if self._unitValue.get_text() == '': - value = 0.0 - else: - value = float(self._unitValue.get_text()) - - if self._unitName.get_text() != '': - func, arg = self._unitDataInCategory[self._unitName.get_text()][0] #retrieve the conversion function and value from the selected unit - base = apply(func.to_base, (value, arg, )) #determine the base unit value - keys = self._unitDataInCategory.keys() - keys.sort() - del keys[0] - row = 0 + #retrieve the conversion function and value from the selected unit + value = self._sanitize_value(self._unitValue.get_text()) + func, arg = self._unitDataInCategory[self._unitName.get_text()][0] + base = func.to_base(value, arg) - #point to the first row - iter = self._unitModel.get_iter_first() + #point to the first row + for row in self._unitModel: + func, arg = self._unitDataInCategory[row[self.UNITS_NAME_IDX]][0] + newValue = func.from_base(base, arg) - while iter: - #get the formula from the name at the row - func, arg = self._unitDataInCategory[self._unitModel.get_value(iter, 0)][0] + newValueDisplay = str(newValue) + integerDisplay, fractionalDisplay = split_number(newValue) - #set the result in the value column - self._unitModel.set(iter, 1, str(apply(func.from_base, (base, arg, )))) + row[self.UNITS_VALUE_IDX] = newValueDisplay + row[self.UNITS_INTEGER_IDX] = integerDisplay + row[self.UNITS_FRACTION_IDX] = fractionalDisplay - #point to the next row in the self._unitModel - iter = self._unitModel.iter_next(iter) + # Update the secondary unit entry + if self._previousUnitName.get_text() != '': + func, arg = self._unitDataInCategory[self._previousUnitName.get_text()][0] + self._previousUnitValue.set_text(str(func.from_base(base, arg, ))) - # if the second row has a unit then update its value - if self._previousUnitName.get_text() != '': - self._calcsuppress = True - func, arg = self._unitDataInCategory[self._previousUnitName.get_text()][0] - self._previousUnitValue.set_text(str(apply(func.from_base, (base, arg, )))) - self._calcsuppress = False + self._sortedUnitModel.sort_column_changed() + self._refresh_columns() - def _on_previous_unit_value_changed(self, a): - if self._calcsuppress == True: - #self._calcsuppress = False + @gtk_toolbox.log_exception(_moduleLogger) + def _on_previous_unit_value_changed(self, *args): + if self._previousUnitName.get_text() == '': + return + if not self._previousUnitValue.is_focus(): return - # determine if value to be calculated is empty - if self._selectedCategory == "Computer Numbers": - if self._previousUnitValue.get_text() == '': - value = '0' - else: - value = self._previousUnitValue.get_text() - else: - if self._previousUnitValue.get_text() == '': - value = 0.0 - else: - value = float(self._previousUnitValue.get_text()) - - if self._previousUnitName.get_text() != '': - func, arg = self._unitDataInCategory[self._previousUnitName.get_text()][0] #retrieve the conversion function and value from the selected unit - base = apply(func.to_base, (value, arg, )) #determine the base unit value - keys = self._unitDataInCategory.keys() - keys.sort() - del keys[0] - row = 0 + #retrieve the conversion function and value from the selected unit + value = self._sanitize_value(self._previousUnitValue.get_text()) + func, arg = self._unitDataInCategory[self._previousUnitName.get_text()][0] + base = func.to_base(value, arg) - #point to the first row - iter = self._unitModel.get_iter_first() + #point to the first row + for row in self._unitModel: + func, arg = self._unitDataInCategory[row[self.UNITS_NAME_IDX]][0] + newValue = func.from_base(base, arg) - while iter: - #get the formula from the name at the row - func, arg = self._unitDataInCategory[self._unitModel.get_value(iter, 0)][0] + newValueDisplay = str(newValue) + integerDisplay, fractionalDisplay = split_number(newValue) - #set the result in the value column - self._unitModel.set(iter, 1, str(apply(func.from_base, (base, arg, )))) + row[self.UNITS_VALUE_IDX] = newValueDisplay + row[self.UNITS_INTEGER_IDX] = integerDisplay + row[self.UNITS_FRACTION_IDX] = fractionalDisplay - #point to the next row in the self._unitModel - iter = self._unitModel.iter_next(iter) + # Update the primary unit entry + func, arg = self._unitDataInCategory[self._unitName.get_text()][0] + self._unitValue.set_text(str(func.from_base(base, arg, ))) - # if the second row has a unit then update its value - if self._unitName.get_text() != '': - self._calcsuppress = True - func, arg = self._unitDataInCategory[self._unitName.get_text()][0] - self._unitValue.set_text(str(apply(func.from_base, (base, arg, )))) - self._calcsuppress = False + self._sortedUnitModel.sort_column_changed() + self._refresh_columns() + @gtk_toolbox.log_exception(_moduleLogger) def _on_about_clicked(self, a): dlg = gtk.AboutDialog() dlg.set_name(constants.__pretty_app_name__) @@ -720,20 +858,30 @@ class Gonvert(object): dlg.set_copyright("Copyright 2009 - GPL") dlg.set_comments("") dlg.set_website("http://unihedron.com/projects/gonvert/gonvert.php") - dlg.set_authors(["Anthony Tekatch ", "Ed Page "]) + dlg.set_authors(["Anthony Tekatch ", "Ed Page (Blame him for the most recent bugs)"]) dlg.run() dlg.destroy() + @gtk_toolbox.log_exception(_moduleLogger) def _on_user_exit(self, *args): try: self._save_settings() except Exception: - _moduleLogger.exception("") + pass finally: gtk.main_quit() -def main(): +def run_gonvert(): + gtk.gdk.threads_init() + if hildonize.IS_HILDON_SUPPORTED: + gtk.set_application_name(constants.__pretty_app_name__) + handle = Gonvert() + if not constants.PROFILE_STARTUP: + gtk.main() + + +if __name__ == "__main__": logging.basicConfig(level = logging.DEBUG) try: os.makedirs(constants._data_path_) @@ -741,9 +889,4 @@ def main(): if e.errno != 17: raise - gonvert = Gonvert() - gtk.main() - - -if __name__ == "__main__": - main() + run_gonvert()