5 @todo Look into using two columns for displaying the value, split by the
6 decimal place. The left one would be right aligned and the right would be left
7 aligned (only if not in exponential notation
8 OR display everything in engineering notation
10 @tood Add a unit description dialog for when hildonized
12 @todo Add support for custom units
14 @todo Add support for compound units
40 _moduleLogger = logging.getLogger("gonvert_glade")
41 PROFILE_STARTUP = False
42 FORCE_HILDON_LIKE = True
44 if gettext is not None:
45 gettext.bindtextdomain('gonvert', '/usr/share/locale')
46 gettext.textdomain('gonvert')
49 def change_menu_label(widgets, labelname, newtext):
50 item_label = widgets.get_widget(labelname).get_children()[0]
51 item_label.set_text(newtext)
54 class Gonvert(object):
57 os.path.join(os.path.dirname(__file__), "gonvert.glade"),
58 os.path.join(os.path.dirname(__file__), "../data/gonvert.glade"),
59 os.path.join(os.path.dirname(__file__), "../lib/gonvert.glade"),
60 '/usr/share/gonvert/gonvert.glade',
61 '/usr/lib/gonvert/gonvert.glade',
69 self._unitDataInCategory = None
70 self._unit_sort_direction = False
71 self._value_sort_direction = False
72 self._units_sort_direction = False
73 self._isFullScreen = False
75 self._find_result = [] # empty find result list
76 self._findIndex = 0 # default to find result number zero
78 self._selectedCategoryName = '' # preset to no selected category
79 self._defaultUnitForCategory = {} # empty dictionary for later use
81 #check to see if glade file is in current directory (user must be
82 # running from download untar directory)
83 for gladePath in self._glade_files:
84 if os.path.isfile(gladePath):
85 homepath = os.path.dirname(gladePath)
86 pixmapspath = "/".join((homepath, "pixmaps"))
87 widgets = gtk.glade.XML(gladePath)
90 _moduleLogger.error("UI Descriptor not found!")
94 self._mainWindow = widgets.get_widget('mainWindow')
95 self._app = hildonize.get_app_class()()
96 self._mainWindow = hildonize.hildonize_window(self._app, self._mainWindow)
98 change_menu_label(widgets, 'fileMenuItem', _('File'))
99 change_menu_label(widgets, 'exitMenuItem', _('Exit'))
100 change_menu_label(widgets, 'toolsMenuItem', _('Tools'))
101 change_menu_label(widgets, 'clearSelectionMenuItem', _('Clear selections'))
102 change_menu_label(widgets, 'helpMenuItem', _('Help'))
103 change_menu_label(widgets, 'aboutMenuItem', _('About'))
104 change_menu_label(widgets, 'findButton', _('Find'))
106 self._shortlistcheck = widgets.get_widget('shortlistcheck')
107 self._toggleShortList = widgets.get_widget('toggleShortList')
109 self._categorySelectionButton = widgets.get_widget("categorySelectionButton")
110 self._categoryView = widgets.get_widget('categoryView')
112 self._unitsView = widgets.get_widget('unitsView')
113 self._unitsView.set_property('rules_hint', 1)
114 self._unitsView_selection = self._unitsView.get_selection()
116 self._unitName = widgets.get_widget('unitName')
117 self._unitValue = widgets.get_widget('unitValue')
118 self._previousUnitName = widgets.get_widget('previousUnitName')
119 self._previousUnitValue = widgets.get_widget('previousUnitValue')
121 self._unitSymbol = widgets.get_widget('unitSymbol')
122 self._previousUnitSymbol = widgets.get_widget('previousUnitSymbol')
124 self._unitDescription = widgets.get_widget('unitDescription')
126 self._searchLayout = widgets.get_widget('searchLayout')
127 self._searchLayout.hide()
128 self._findEntry = widgets.get_widget('findEntry')
129 self._findLabel = widgets.get_widget('findLabel')
130 self._findButton = widgets.get_widget('findButton')
132 #insert a self._categoryColumnumn into the units list even though the heading will not be seen
133 renderer = gtk.CellRendererText()
134 renderer.set_property("ellipsize", pango.ELLIPSIZE_END)
135 renderer.set_property("width-chars", len("grams per cubic cm plus some"))
136 self._unitNameColumn = gtk.TreeViewColumn(_('Name'), renderer)
137 self._unitNameColumn.set_property('resizable', 1)
138 self._unitNameColumn.add_attribute(renderer, 'text', self.UNITS_NAME_IDX)
139 self._unitNameColumn.set_clickable(True)
140 self._unitNameColumn.connect("clicked", self._on_click_unit_column)
141 self._unitsView.append_column(self._unitNameColumn)
143 renderer = gtk.CellRendererText()
144 hildonize.set_cell_thumb_selectable(renderer)
145 self._unitValueColumn = gtk.TreeViewColumn(_('Value'), renderer)
146 self._unitValueColumn.set_property('resizable', 1)
147 self._unitValueColumn.add_attribute(renderer, 'text', self.UNITS_VALUE_IDX)
148 self._unitValueColumn.set_clickable(True)
149 self._unitValueColumn.connect("clicked", self._on_click_unit_column)
150 self._unitsView.append_column(self._unitValueColumn)
152 renderer = gtk.CellRendererText()
153 renderer.set_property("ellipsize", pango.ELLIPSIZE_END)
154 renderer.set_property("width-chars", len("G ohm plus some"))
155 hildonize.set_cell_thumb_selectable(renderer)
156 self._unitSymbolColumn = gtk.TreeViewColumn(_('Units'), renderer)
157 self._unitSymbolColumn.set_property('resizable', 1)
158 self._unitSymbolColumn.add_attribute(renderer, 'text', self.UNITS_SYMBOL_IDX)
159 self._unitSymbolColumn.set_clickable(True)
160 self._unitSymbolColumn.connect("clicked", self._on_click_unit_column)
161 self._unitsView.append_column(self._unitSymbolColumn)
163 self._unitModel = gtk.ListStore(
164 gobject.TYPE_STRING, # UNITS_NAME_IDX
165 gobject.TYPE_STRING, # UNITS_VALUE_IDX
166 gobject.TYPE_STRING, # UNITS_SYMBOL_IDX
168 self._sortedUnitModel = gtk.TreeModelSort(self._unitModel)
169 columns = self._get_column_sort_stuff()
170 for columnIndex, (column, sortDirection, col_cmp) in enumerate(columns):
171 self._sortedUnitModel.set_sort_func(columnIndex, col_cmp)
172 self._unitsView.set_model(self._sortedUnitModel)
174 #Insert a column into the category list even though the heading will not be seen
175 renderer = gtk.CellRendererText()
176 self._categoryColumn = gtk.TreeViewColumn('Title', renderer)
177 self._categoryColumn.set_property('resizable', 1)
178 self._categoryColumn.add_attribute(renderer, 'text', 0)
179 self._categoryView.append_column(self._categoryColumn)
181 self._categoryModel = gtk.ListStore(gobject.TYPE_STRING)
182 self._categoryView.set_model(self._categoryModel)
183 #colourize each row differently for easier reading
184 self._categoryView.set_property('rules_hint', 1)
186 #Populate the catagories list
187 for key in unit_data.UNIT_CATEGORIES:
189 self._categoryModel.append(row)
191 #--------- connections to GUI ----------------
192 self._mainWindow.connect("delete-event", self._on_user_exit)
193 self._mainWindow.connect("key-press-event", self._on_key_press)
194 self._mainWindow.connect("window-state-event", self._on_window_state_change)
195 self._categorySelectionButton.connect("clicked", self._on_category_selector_clicked)
196 self._categoryView.connect("cursor-changed", self._on_click_category)
197 self._findButton.connect("clicked", self._on_find_activate)
198 self._findEntry.connect("activate", self._on_find_activate)
199 self._findEntry.connect("changed", self._on_findEntry_changed)
200 self._previousUnitValue.connect("changed", self._on_previous_unit_value_changed)
201 self._shortlistcheck.connect("toggled", self._on_shortlist_changed)
202 self._unitValue.connect("changed", self._on_unit_value_changed)
203 self._unitsView.connect("cursor-changed", self._on_click_unit)
204 if hildonize.GTK_MENU_USED:
205 widgets.get_widget("aboutMenuItem").connect("activate", self._on_about_clicked)
206 widgets.get_widget("clearSelectionMenuItem").connect("activate", self._on_user_clear_selections)
207 widgets.get_widget("editShortListMenuItem").connect("activate", self._on_edit_shortlist)
208 widgets.get_widget("exitMenuItem").connect("activate", self._on_user_exit)
210 for scrollingWidgetName in (
211 "unitsViewScrolledWindow",
213 scrollingWidget = widgets.get_widget(scrollingWidgetName)
214 assert scrollingWidget is not None, scrollingWidgetName
215 hildonize.hildonize_scrollwindow_with_viewport(scrollingWidget)
217 if hildonize.IS_HILDON_SUPPORTED or FORCE_HILDON_LIKE:
218 self._categoryView.get_parent().hide()
219 self._unitsView.set_headers_visible(False)
220 self._previousUnitName.get_parent().hide()
221 self._unitDescription.get_parent().get_parent().hide()
223 self._categorySelectionButton.hide()
225 replacementButtons = []
226 menu = hildonize.hildonize_menu(
228 widgets.get_widget("mainMenuBar"),
232 if not hildonize.IS_HILDON_SUPPORTED:
233 _moduleLogger.info("No hildonization support")
235 hildonize.set_application_title(
236 self._mainWindow, "%s - Unit Conversion Utility" % constants.__pretty_app_name__
238 iconPath = pixmapspath + '/gonvert.png'
239 if os.path.exists(iconPath):
240 self._mainWindow.set_icon(gtk.gdk.pixbuf_new_from_file(iconPath))
242 _moduleLogger.warn("Error: Could not find gonvert icon: %s" % iconPath)
244 self._load_settings()
245 self._mainWindow.show()
247 def _load_settings(self):
248 #Restore window size from previously saved settings if it exists and is valid.
249 windowDatPath = "/".join((constants._data_path_, "window.dat"))
250 if os.path.exists(windowDatPath):
251 saved_window = pickle.load(open(windowDatPath, "r"))
253 a, b = saved_window['size']
257 self._mainWindow.resize(a, b)
259 #Restore selections from previously saved settings if it exists and is valid.
261 selectedCategoryName = unit_data.UNIT_CATEGORIES[0]
262 selectionsDatPath = "/".join((constants._data_path_, "selections.dat"))
263 if os.path.exists(selectionsDatPath):
264 selections = pickle.load(open(selectionsDatPath, 'r'))
266 self._defaultUnitForCategory = selections['selected_units']
271 selectedCategoryName = selections['selected_category']
276 categoryIndex = unit_data.UNIT_CATEGORIES.index(selectedCategoryName)
278 _moduleLogger.warn("Unknown category: %s" % selectedCategoryName)
280 self._categorySelectionButton.get_child().set_markup("<big>%s</big>" % selectedCategoryName)
281 self._categoryView.set_cursor(categoryIndex, self._categoryColumn, False)
282 self._categoryView.grab_focus()
284 self._select_default_unit()
286 def _save_settings(self):
288 This routine saves the selections to a file, and
289 should therefore only be called when exiting the program.
291 Update selections dictionary which consists of the following keys:
292 'self._selectedCategoryName': full name of selected category
293 'self._defaultUnitForCategory': self._defaultUnitForCategory dictionary which contains:
294 [categoryname: #1 displayed unit, #2 displayed unit]
296 #Determine the contents of the selected category row
297 selected, iter = self._categoryView.get_selection().get_selected()
298 self._selectedCategoryName = self._categoryModel.get_value(iter, 0)
301 'selected_category': self._selectedCategoryName,
302 'selected_units': self._defaultUnitForCategory
304 selectionsDatPath = "/".join((constants._data_path_, "selections.dat"))
305 pickle.dump(selections, open(selectionsDatPath, 'w'))
307 #Get last size of app and save it
309 'size': self._mainWindow.get_size()
311 windowDatPath = "/".join((constants._data_path_, "window.dat"))
312 pickle.dump(window_settings, open(windowDatPath, 'w'))
314 def _clear_find(self):
315 # switch to "new find" state
316 self._find_result = []
319 # Clear our user message
320 self._findLabel.set_text('')
322 def _find_first(self):
323 assert len(self._find_result) == 0
324 assert self._findIndex == 0
325 findString = self._findEntry.get_text().strip().lower()
329 # Gather info on all the matching units from all categories
330 for catIndex, category in enumerate(unit_data.UNIT_CATEGORIES):
331 units = unit_data.get_units(category)
332 for unitIndex, unit in enumerate(units):
333 loweredUnit = unit.lower()
334 if loweredUnit in findString or findString in loweredUnit:
335 self._find_result.append((category, unit, catIndex, unitIndex))
337 def _update_find_selection(self):
338 assert 0 < len(self._find_result)
340 #check if next find is in a new category (prevent category changes when unnecessary
341 searchCategoryName = self._find_result[self._findIndex][0]
342 if self._selectedCategoryName != searchCategoryName:
343 self._categorySelectionButton.get_child().set_markup("<big>%s</big>" % searchCategoryName)
344 self._categoryView.set_cursor(
345 self._find_result[self._findIndex][2], self._categoryColumn, False
348 self._unitsView.set_cursor(
349 self._find_result[self._findIndex][3], self._unitNameColumn, True
352 def _find_next(self):
353 if len(self._find_result) == 0:
356 if self._findIndex == len(self._find_result)-1:
361 if not self._find_result:
362 self._findLabel.set_text('Text not found')
364 self._update_find_selection()
365 resultsLeft = len(self._find_result) - self._findIndex - 1
366 self._findLabel.set_text(
367 '%s result(s) left' % (resultsLeft, )
370 def _find_previous(self):
371 if len(self._find_result) == 0:
374 if self._findIndex == 0:
375 self._findIndex = len(self._find_result)-1
379 if not self._find_result:
380 self._findLabel.set_text('Text not found')
382 self._update_find_selection()
383 resultsLeft = len(self._find_result) - self._findIndex - 1
384 self._findLabel.set_text(
385 '%s result(s) left' % (resultsLeft, )
388 def _toggle_find(self):
389 if self._searchLayout.get_property("visible"):
390 self._searchLayout.hide()
391 self._unitsView.grab_focus()
393 self._searchLayout.show()
394 self._findEntry.grab_focus()
396 def _unit_model_cmp(self, sortedModel, leftItr, rightItr):
397 leftUnitText = self._unitModel.get_value(leftItr, 0)
398 rightUnitText = self._unitModel.get_value(rightItr, 0)
399 return cmp(leftUnitText, rightUnitText)
401 def _symbol_model_cmp(self, sortedModel, leftItr, rightItr):
402 leftSymbolText = self._unitModel.get_value(leftItr, 2)
403 rightSymbolText = self._unitModel.get_value(rightItr, 2)
404 return cmp(leftSymbolText, rightSymbolText)
406 def _value_model_cmp(self, sortedModel, leftItr, rightItr):
407 #special sorting exceptions for ascii values (instead of float values)
408 if self._selectedCategoryName == "Computer Numbers":
409 leftValue = self._unitModel.get_value(leftItr, 1)
410 rightValue = self._unitModel.get_value(rightItr, 1)
412 leftValueText = self._unitModel.get_value(leftItr, 1)
413 leftValue = float(leftValueText) if leftValueText else 0.0
415 rightValueText = self._unitModel.get_value(rightItr, 1)
416 rightValue = float(rightValueText) if rightValueText else 0.0
417 return cmp(leftValue, rightValue)
419 def _get_column_sort_stuff(self):
421 (self._unitNameColumn, "_unit_sort_direction", self._unit_model_cmp),
422 (self._unitValueColumn, "_value_sort_direction", self._value_model_cmp),
423 (self._unitSymbolColumn, "_units_sort_direction", self._symbol_model_cmp),
427 def _switch_category(self, category):
428 self._selectedCategoryName = category
429 self._unitDataInCategory = unit_data.UNIT_DESCRIPTIONS[self._selectedCategoryName]
431 #Fill up the units descriptions and clear the value cells
432 self._clear_visible_unit_data()
433 for key in unit_data.get_units(self._selectedCategoryName):
434 iter = self._unitModel.append()
435 self._unitModel.set(iter, 0, key, 1, '', 2, self._unitDataInCategory[key][1])
436 self._sortedUnitModel.sort_column_changed()
438 self._select_default_unit()
440 def _clear_visible_unit_data(self):
441 self._unitDescription.get_buffer().set_text("")
442 self._unitName.set_text('')
443 self._unitValue.set_text('')
444 self._unitSymbol.set_text('')
446 self._previousUnitName.set_text('')
447 self._previousUnitValue.set_text('')
448 self._previousUnitSymbol.set_text('')
450 self._unitModel.clear()
452 def _select_default_unit(self):
453 # Restore the previous historical settings of previously selected units
454 # in this newly selected category
455 defaultPrimary = unit_data.get_base_unit(self._selectedCategoryName)
456 defaultSecondary = ""
457 if self._selectedCategoryName in self._defaultUnitForCategory:
458 if self._defaultUnitForCategory[self._selectedCategoryName][0]:
459 defaultPrimary = self._defaultUnitForCategory[self._selectedCategoryName][0]
460 if self._defaultUnitForCategory[self._selectedCategoryName][1]:
461 defaultSecondary = self._defaultUnitForCategory[self._selectedCategoryName][1]
463 units = unit_data.get_units(self._selectedCategoryName)
465 #Restore oldest selection first.
468 unitIndex = units.index(defaultPrimary)
471 self._unitsView.set_cursor(unitIndex, self._unitNameColumn, True)
473 #Restore newest selection second.
476 unitIndex = units.index(defaultSecondary)
479 self._unitsView.set_cursor(unitIndex, self._unitNameColumn, True)
481 # select the text so user can start typing right away
482 self._unitValue.grab_focus()
483 self._unitValue.select_region(0, -1)
485 def _sanitize_value(self, userEntry):
486 if self._selectedCategoryName == "Computer Numbers":
495 value = float(userEntry)
498 def _on_shortlist_changed(self, *args):
500 raise NotImplementedError("%s" % self._shortlistcheck.get_active())
502 _moduleLogger.exception("_on_shortlist_changed")
504 def _on_edit_shortlist(self, *args):
506 raise NotImplementedError("%s" % self._toggleShortList.get_active())
508 _moduleLogger.exception("_on_edit_shortlist")
510 def _on_user_clear_selections(self, *args):
512 selectionsDatPath = "/".join((constants._data_path_, "selections.dat"))
513 os.remove(selectionsDatPath)
514 self._defaultUnitForCategory = {}
516 _moduleLogger.exception("_on_user_clear_selections")
518 def _on_key_press(self, widget, event, *args):
520 @note Hildon specific
522 RETURN_TYPES = (gtk.keysyms.Return, gtk.keysyms.ISO_Enter, gtk.keysyms.KP_Enter)
525 event.keyval == gtk.keysyms.F6 or
526 event.keyval in RETURN_TYPES and event.get_state() & gtk.gdk.CONTROL_MASK
528 if self._isFullScreen:
529 self._mainWindow.unfullscreen()
531 self._mainWindow.fullscreen()
532 elif event.keyval == gtk.keysyms.f and event.get_state() & gtk.gdk.CONTROL_MASK:
534 elif event.keyval == gtk.keysyms.p and event.get_state() & gtk.gdk.CONTROL_MASK:
535 self._find_previous()
536 elif event.keyval == gtk.keysyms.n and event.get_state() & gtk.gdk.CONTROL_MASK:
539 _moduleLogger.exception("_on_key_press")
541 def _on_window_state_change(self, widget, event, *args):
543 @note Hildon specific
546 if event.new_window_state & gtk.gdk.WINDOW_STATE_FULLSCREEN:
547 self._isFullScreen = True
549 self._isFullScreen = False
551 _moduleLogger.exception("_on_window_state_change")
553 def _on_findEntry_changed(self, *args):
555 Clear out find results since the user wants to look for something new
560 _moduleLogger.exception("_on_findEntry_changed")
562 def _on_find_activate(self, *args):
565 self._findButton.grab_focus()
567 _moduleLogger.exception("_on_find_activate")
569 def _on_click_unit_column(self, col):
571 Sort the contents of the col when the user clicks on the title.
574 #Determine which column requires sorting
575 columns = self._get_column_sort_stuff()
576 for columnIndex, (maybeCol, directionName, col_cmp) in enumerate(columns):
578 direction = getattr(self, directionName)
579 gtkDirection = gtk.SORT_ASCENDING if direction else gtk.SORT_DESCENDING
582 self._sortedUnitModel.set_sort_column_id(columnIndex, gtkDirection)
584 # set the visual for sorting
585 col.set_sort_indicator(True)
586 col.set_sort_order(not direction)
588 setattr(self, directionName, not direction)
591 maybeCol.set_sort_indicator(False)
593 assert False, "Unknown column: %s" % (col.get_title(), )
595 _moduleLogger.exception("_on_click_unit_column")
597 def _on_category_selector_clicked(self, *args):
599 currenntIndex = unit_data.UNIT_CATEGORIES.index(self._selectedCategoryName)
600 newIndex = hildonize.touch_selector(
603 unit_data.UNIT_CATEGORIES,
607 selectedCategoryName = unit_data.UNIT_CATEGORIES[newIndex]
608 self._categorySelectionButton.set_label(selectedCategoryName)
609 self._categoryView.set_cursor(newIndex, self._categoryColumn, False)
610 self._categoryView.grab_focus()
612 _moduleLogger.exception("_on_category_selector_clicked")
614 def _on_click_category(self, *args):
616 selected, iter = self._categoryView.get_selection().get_selected()
618 # User is typing in an invalid string, not selecting any category
620 selectedCategory = self._categoryModel.get_value(iter, 0)
621 self._switch_category(selectedCategory)
623 _moduleLogger.exception("_on_click_category")
625 def _on_click_unit(self, *args):
627 selected, iter = self._unitsView.get_selection().get_selected()
628 selected_unit = selected.get_value(iter, 0)
629 unit_spec = self._unitDataInCategory[selected_unit]
633 if self._unitName.get_text() != selected_unit:
634 self._previousUnitName.set_text(self._unitName.get_text())
635 self._previousUnitValue.set_text(self._unitValue.get_text())
636 self._previousUnitSymbol.set_text(self._unitSymbol.get_text())
637 if self._unitSymbol.get_text():
640 self._unitName.set_text(selected_unit)
641 self._unitValue.set_text(selected.get_value(iter, 1))
642 buffer = self._unitDescription.get_buffer()
643 buffer.set_text(unit_spec[2])
644 self._unitSymbol.set_text(unit_spec[1]) # put units into label text
651 self._unitSymbol.show()
652 self._previousUnitSymbol.show()
654 self._unitSymbol.hide()
655 self._previousUnitSymbol.hide()
657 if self._unitValue.get_text() == '':
658 if self._selectedCategoryName == "Computer Numbers":
659 self._unitValue.set_text("0")
661 self._unitValue.set_text("0.0")
663 self._defaultUnitForCategory[self._selectedCategoryName] = [
664 self._unitName.get_text(), self._previousUnitName.get_text()
667 # select the text so user can start typing right away
668 self._unitValue.grab_focus()
669 self._unitValue.select_region(0, -1)
671 _moduleLogger.exception("_on_click_unit")
673 def _on_unit_value_changed(self, *args):
675 if self._unitName.get_text() == '':
677 if not self._unitValue.is_focus():
680 #retrieve the conversion function and value from the selected unit
681 value = self._sanitize_value(self._unitValue.get_text())
682 func, arg = self._unitDataInCategory[self._unitName.get_text()][0]
683 base = func.to_base(value, arg)
685 #point to the first row
686 for row in self._unitModel:
687 func, arg = self._unitDataInCategory[row[0]][0]
688 row[1] = str(func.from_base(base, arg))
690 # Update the secondary unit entry
691 if self._previousUnitName.get_text() != '':
692 func, arg = self._unitDataInCategory[self._previousUnitName.get_text()][0]
693 self._previousUnitValue.set_text(str(func.from_base(base, arg, )))
695 _moduleLogger.exception("_on_unit_value_changed")
697 def _on_previous_unit_value_changed(self, *args):
699 if self._previousUnitName.get_text() == '':
701 if not self._previousUnitValue.is_focus():
704 #retrieve the conversion function and value from the selected unit
705 value = self._sanitize_value(self._previousUnitValue.get_text())
706 func, arg = self._unitDataInCategory[self._previousUnitName.get_text()][0]
707 base = func.to_base(value, arg)
709 #point to the first row
710 for row in self._unitModel:
711 func, arg = self._unitDataInCategory[row[0]][0]
712 row[1] = str(func.from_base(base, arg))
714 # Update the primary unit entry
715 func, arg = self._unitDataInCategory[self._unitName.get_text()][0]
716 self._unitValue.set_text(str(func.from_base(base, arg, )))
718 _moduleLogger.exception("_on_previous_unit_value_changed")
720 def _on_about_clicked(self, a):
721 dlg = gtk.AboutDialog()
722 dlg.set_name(constants.__pretty_app_name__)
723 dlg.set_version("%s-%d" % (constants.__version__, constants.__build__))
724 dlg.set_copyright("Copyright 2009 - GPL")
726 dlg.set_website("http://unihedron.com/projects/gonvert/gonvert.php")
727 dlg.set_authors(["Anthony Tekatch <anthony@unihedron.com>", "Ed Page <edpage@byu.net>"])
731 def _on_user_exit(self, *args):
733 self._save_settings()
735 _moduleLogger.exception("_on_user_exit")
741 gtk.gdk.threads_init()
742 if hildonize.IS_HILDON_SUPPORTED:
743 gtk.set_application_name(constants.__pretty_app_name__)
745 if not PROFILE_STARTUP:
749 if __name__ == "__main__":
750 logging.basicConfig(level = logging.DEBUG)
752 os.makedirs(constants._data_path_)