Fixing a bug where we did not always refresh the converted value
[gonvert] / src / gonvert_qt.py
index af06463..b2adc92 100755 (executable)
@@ -82,7 +82,14 @@ class Gonvert(object):
 
                self._jumpWindow = None
                self._recentWindow = None
+               self._mainWindow = None
                self._catWindow = None
+               self._quickWindow = None
+
+               self._on_jump_close = lambda obj = None: self._on_child_close("_jumpWindow", obj)
+               self._on_recent_close = lambda obj = None: self._on_child_close("_recentWindow", obj)
+               self._on_cat_close = lambda obj = None: self._on_child_close("_catWindow", obj)
+               self._on_quick_close = lambda obj = None: self._on_child_close("_quickWindow", obj)
 
                self._condensedAction = QtGui.QAction(None)
                self._condensedAction.setText("Condensed View")
@@ -128,30 +135,41 @@ class Gonvert(object):
 
                self.request_category()
                if self._recent:
-                       self._catWindow.select_category(self._recent[-1][0])
+                       self._mainWindow.select_category(self._recent[-1][0])
 
        def request_category(self):
-               if self._catWindow is not None:
-                       self._catWindow.close()
-                       self._catWindow = None
+               if self._mainWindow is not None:
+                       self._mainWindow.hide()
+
                if self._condensedAction.isChecked():
-                       self._catWindow = QuickConvert(None, self)
-                       self._catWindow.window.destroyed.connect(lambda obj = None: self._on_child_close("_catWindow", obj))
+                       if self._quickWindow is None:
+                               self._quickWindow = QuickConvert(None, self)
+                               self._quickWindow.window.destroyed.connect(self._on_quick_close)
+                       else:
+                               self._quickWindow.show()
+                       self._mainWindow = self._quickWindow
                else:
-                       self._catWindow = CategoryWindow(None, self)
-                       self._catWindow.window.destroyed.connect(lambda obj = None: self._on_child_close("_catWindow", obj))
-               return self._catWindow
+                       if self._catWindow is None:
+                               self._catWindow = CategoryWindow(None, self)
+                               self._catWindow.window.destroyed.connect(self._on_cat_close)
+                       else:
+                               self._catWindow.window.show()
+                       self._mainWindow = self._catWindow
+
+               return self._mainWindow
 
        def search_units(self):
-               self._close_windows()
-               self._jumpWindow = QuickJump(None, self)
-               self._jumpWindow.window.destroyed.connect(lambda obj = None: self._on_child_close("_jumpWindow", obj))
+               jumpWindow = QuickJump(None, self)
+               jumpWindow.window.destroyed.connect(self._on_jump_close)
+               self._fake_close_windows()
+               self._jumpWindow = jumpWindow
                return self._jumpWindow
 
        def show_recent(self):
-               self._close_windows()
-               self._recentWindow = Recent(None, self)
-               self._recentWindow.window.destroyed.connect(lambda obj = None: self._on_child_close("_recentWindow", obj))
+               recentWindow = Recent(None, self)
+               recentWindow.window.destroyed.connect(self._on_recent_close)
+               self._fake_close_windows()
+               self._recentWindow = recentWindow
                return self._recentWindow
 
        def add_recent(self, categoryName, unitName):
@@ -265,17 +283,44 @@ class Gonvert(object):
        def _walk_children(self):
                if self._catWindow is not None:
                        yield self._catWindow
+               if self._quickWindow is not None:
+                       yield self._quickWindow
                if self._jumpWindow is not None:
                        yield self._jumpWindow
                if self._recentWindow is not None:
                        yield self._recentWindow
 
+       def _fake_close_windows(self):
+               if self._catWindow is not None:
+                       self._catWindow.hide()
+               if self._quickWindow is not None:
+                       self._quickWindow.hide()
+               if self._jumpWindow is not None:
+                       self._jumpWindow.disconnect(self._on_jump_close)
+                       self._jumpWindow.close()
+                       self._jumpWindow = None
+               if self._recentWindow is not None:
+                       self._recentWindow.disconnect(self._on_recent_close)
+                       self._recentWindow.close()
+                       self._recentWindow = None
+
        def _close_windows(self):
-               for window in self._walk_children():
-                       window.close()
-               self._catWindow = None
-               self._jumpWindow = None
-               self._recentWindow = None
+               if self._catWindow is not None:
+                       self._catWindow.disconnect(self._on_cat_close)
+                       self._catWindow.close()
+                       self._catWindow = None
+               if self._quickWindow is not None:
+                       self._quickWindow.disconnect(self._on_quick_close)
+                       self._quickWindow.close()
+                       self._quickWindow = None
+               if self._jumpWindow is not None:
+                       self._jumpWindow.disconnect(self._on_jump_close)
+                       self._jumpWindow.close()
+                       self._jumpWindow = None
+               if self._recentWindow is not None:
+                       self._recentWindow.disconnect(self._on_recent_close)
+                       self._recentWindow.close()
+                       self._recentWindow = None
 
        @misc_utils.log_exception(_moduleLogger)
        def _on_app_quit(self, checked = False):
@@ -296,6 +341,8 @@ class Gonvert(object):
        @misc_utils.log_exception(_moduleLogger)
        def _on_condensed_start(self, checked = False):
                self.request_category()
+               if self._recent:
+                       self._mainWindow.select_category(self._recent[-1][0])
 
        @misc_utils.log_exception(_moduleLogger)
        def _on_jump_start(self, checked = False):
@@ -350,8 +397,6 @@ class QuickJump(object):
                self._window.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)
                maeqt.set_autorient(self._window, True)
                maeqt.set_stackable(self._window, True)
-               if parent is not None:
-                       self._window.setWindowModality(QtCore.Qt.WindowModal)
                self._window.setWindowTitle("%s - Quick Jump" % constants.__pretty_app_name__)
                self._window.setWindowIcon(QtGui.QIcon(self._app.appIconPath))
                self._window.setCentralWidget(centralWidget)
@@ -382,6 +427,12 @@ class QuickJump(object):
        def window(self):
                return self._window
 
+       def show(self):
+               self._window.show()
+
+       def hide(self):
+               self._window.hide()
+
        def close(self):
                self._window.close()
 
@@ -444,8 +495,6 @@ class Recent(object):
                self._window.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)
                maeqt.set_autorient(self._window, True)
                maeqt.set_stackable(self._window, True)
-               if parent is not None:
-                       self._window.setWindowModality(QtCore.Qt.WindowModal)
                self._window.setWindowTitle("%s - Recent" % constants.__pretty_app_name__)
                self._window.setWindowIcon(QtGui.QIcon(self._app.appIconPath))
                self._window.setCentralWidget(centralWidget)
@@ -481,6 +530,12 @@ class Recent(object):
        def window(self):
                return self._window
 
+       def show(self):
+               self._window.show()
+
+       def hide(self):
+               self._window.hide()
+
        def close(self):
                self._window.close()
 
@@ -530,7 +585,7 @@ class QuickConvert(object):
 
                self._categoryView = QtGui.QTreeWidget()
                self._categoryView.setHeaderLabels(["Categories"])
-               self._categoryView.setHeaderHidden(True)
+               self._categoryView.setHeaderHidden(False)
                if not IS_MAEMO:
                        self._categoryView.setAlternatingRowColors(True)
                self._categoryView.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
@@ -542,8 +597,8 @@ class QuickConvert(object):
                self._categorySelection.selectionChanged.connect(self._on_category_selection_changed)
 
                self._inputView = QtGui.QTreeWidget()
-               self._inputView.setHeaderLabels(["Input", "Name"])
-               self._inputView.setHeaderHidden(True)
+               self._inputView.setHeaderLabels(["From", "Name"])
+               self._inputView.setHeaderHidden(False)
                self._inputView.header().hideSection(1)
                if not IS_MAEMO:
                        self._inputView.setAlternatingRowColors(True)
@@ -553,8 +608,8 @@ class QuickConvert(object):
                self._inputSelection.selectionChanged.connect(self._on_input_selection_changed)
 
                self._outputView = QtGui.QTreeWidget()
-               self._outputView.setHeaderLabels(["Output", "Name"])
-               self._outputView.setHeaderHidden(True)
+               self._outputView.setHeaderLabels(["To", "Name"])
+               self._outputView.setHeaderHidden(False)
                self._outputView.header().hideSection(1)
                if not IS_MAEMO:
                        self._outputView.setAlternatingRowColors(True)
@@ -580,8 +635,6 @@ class QuickConvert(object):
                self._window.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)
                maeqt.set_autorient(self._window, True)
                maeqt.set_stackable(self._window, True)
-               if parent is not None:
-                       self._window.setWindowModality(QtCore.Qt.WindowModal)
                self._window.setWindowTitle("%s - Quick Convert" % (constants.__pretty_app_name__, ))
                self._window.setWindowIcon(QtGui.QIcon(app.appIconPath))
                self._window.setCentralWidget(centralWidget)
@@ -593,6 +646,7 @@ class QuickConvert(object):
                self._chooseUnitFavoritesAction = QtGui.QAction(None)
                self._chooseUnitFavoritesAction.setText("Select Units")
                self._chooseUnitFavoritesAction.triggered.connect(self._on_choose_unit_favorites)
+               self._chooseUnitFavoritesAction.setEnabled(False)
 
                self._app.showFavoritesAction.toggled.connect(self._on_show_favorites)
 
@@ -642,6 +696,12 @@ class QuickConvert(object):
        def window(self):
                return self._window
 
+       def show(self):
+               self._window.show()
+
+       def hide(self):
+               self._window.hide()
+
        def close(self):
                self._window.close()
 
@@ -652,10 +712,16 @@ class QuickConvert(object):
                        self._window.showNormal()
 
        def select_category(self, categoryName):
+               self._inputUnitName = ""
+               self._outputUnitName = ""
                self._inputUnitValue.setText("")
+               self._inputUnitSymbol.setText("")
                self._inputView.clear()
+               self._outputUnitValue.setText("")
+               self._outputUnitSymbol.setText("")
                self._outputView.clear()
                self._categoryName = categoryName
+               self._chooseUnitFavoritesAction.setEnabled(True)
 
                unitData = unit_data.UNIT_DESCRIPTIONS[categoryName]
                self._unitNames = list(unit_data.get_units(categoryName))
@@ -704,6 +770,9 @@ class QuickConvert(object):
                currentIndex = self._inputView.model().index(i, 0, rootIndex)
                self._inputView.scrollTo(currentIndex)
 
+               if "" not in [self._categoryName, self._inputUnitName, self._outputUnitName]:
+                       self._update_conversion()
+
        def select_output(self, name):
                # Add the output to recent but don't make things weird by making it the most recent
                self._app.add_recent(self._categoryName, name)
@@ -720,6 +789,9 @@ class QuickConvert(object):
                currentIndex = self._outputView.model().index(i, 0, rootIndex)
                self._outputView.scrollTo(currentIndex)
 
+               if "" not in [self._categoryName, self._inputUnitName, self._outputUnitName]:
+                       self._update_conversion()
+
        def _sanitize_value(self, userEntry):
                if self._categoryName == "Computer Numbers":
                        if userEntry == '':
@@ -733,6 +805,25 @@ class QuickConvert(object):
                                value = float(userEntry)
                return value
 
+       def _update_conversion(self):
+               assert self._categoryName
+               assert self._inputUnitName
+               assert self._outputUnitName
+
+               userInput = str(self._inputUnitValue.text())
+               value = self._sanitize_value(userInput)
+
+               unitData = unit_data.UNIT_DESCRIPTIONS[self._categoryName]
+               inputConversion, _, _ = unitData[self._inputUnitName]
+               outputConversion, _, _ = unitData[self._outputUnitName]
+
+               func, arg = inputConversion
+               base = func.to_base(value, arg)
+
+               func, arg = outputConversion
+               newValue = func.from_base(base, arg)
+               self._outputUnitValue.setText(str(newValue))
+
        def _update_favorites(self):
                if self._app.showFavoritesAction.isChecked():
                        assert self._categoryView.topLevelItemCount() == len(unit_data.UNIT_CATEGORIES)
@@ -812,23 +903,7 @@ class QuickConvert(object):
 
        @misc_utils.log_exception(_moduleLogger)
        def _on_value_edited(self, *args):
-               assert self._categoryName
-               assert self._inputUnitName
-               assert self._outputUnitName
-
-               userInput = str(self._inputUnitValue.text())
-               value = self._sanitize_value(userInput)
-
-               unitData = unit_data.UNIT_DESCRIPTIONS[self._categoryName]
-               inputConversion, _, _ = unitData[self._inputUnitName]
-               outputConversion, _, _ = unitData[self._outputUnitName]
-
-               func, arg = inputConversion
-               base = func.to_base(value, arg)
-
-               func, arg = outputConversion
-               newValue = func.from_base(base, arg)
-               self._outputUnitValue.setText(str(newValue))
+               self._update_conversion()
 
        @misc_utils.log_exception(_moduleLogger)
        def _on_category_selection_changed(self, selected, deselected):
@@ -913,8 +988,6 @@ class FavoritesWindow(object):
                self._window.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)
                maeqt.set_autorient(self._window, True)
                maeqt.set_stackable(self._window, True)
-               if parent is not None:
-                       self._window.setWindowModality(QtCore.Qt.WindowModal)
                self._window.setWindowTitle("%s - Favorites" % constants.__pretty_app_name__)
                self._window.setWindowIcon(QtGui.QIcon(self._app.appIconPath))
                self._window.setCentralWidget(centralWidget)
@@ -945,6 +1018,12 @@ class FavoritesWindow(object):
        def window(self):
                return self._window
 
+       def show(self):
+               self._window.show()
+
+       def hide(self):
+               self._window.hide()
+
        def close(self):
                self._window.close()
 
@@ -1013,8 +1092,6 @@ class CategoryWindow(object):
                self._window.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)
                maeqt.set_autorient(self._window, True)
                maeqt.set_stackable(self._window, True)
-               if parent is not None:
-                       self._window.setWindowModality(QtCore.Qt.WindowModal)
                self._window.setWindowTitle("%s - Categories" % constants.__pretty_app_name__)
                self._window.setWindowIcon(QtGui.QIcon(self._app.appIconPath))
                self._window.setCentralWidget(centralWidget)
@@ -1076,13 +1153,25 @@ class CategoryWindow(object):
                if self._favoritesWindow is not None:
                        yield self._favoritesWindow
 
+       def show(self):
+               for child in self.walk_children():
+                       child.show()
+               self._window.show()
+
+       def hide(self):
+               for child in self.walk_children():
+                       child.hide()
+               self._window.hide()
+
        def close(self):
                for child in self.walk_children():
+                       child.window.destroyed.disconnect(self._on_child_close)
                        child.close()
                self._window.close()
 
        def select_category(self, categoryName):
                for child in self.walk_children():
+                       child.window.destroyed.disconnect(self._on_child_close)
                        child.close()
                self._unitWindow = UnitWindow(self._window, categoryName, self._app)
                self._unitWindow.window.destroyed.connect(self._on_child_close)
@@ -1329,8 +1418,8 @@ class UnitModel(QtCore.QAbstractItemModel):
                        self._sortSettings is not None and
                        self._sortSettings[0]  in [UnitData.VALUE_COLUMN_0, UnitData.VALUE_COLUMN_1]
                ):
+                       # Sort takes care of marking everything as changed
                        self.sort(*self._sortSettings)
-                       self._all_changed()
                else:
                        self._values_changed()
 
@@ -1404,10 +1493,10 @@ class UnitWindow(object):
                viewHeader.setStretchLastSection(False)
 
                # Trying to make things faster by locking in the initial size of the immutable columns
-               nameSize = viewHeader.sectionSize(UnitData.NAME_COLUMN)
+               nameSize = min(viewHeader.sectionSize(UnitData.NAME_COLUMN), 125)
                viewHeader.setResizeMode(UnitData.NAME_COLUMN, QtGui.QHeaderView.Fixed)
                viewHeader.resizeSection(UnitData.NAME_COLUMN, nameSize)
-               unitSize = viewHeader.sectionSize(UnitData.UNIT_COLUMN)
+               unitSize = min(viewHeader.sectionSize(UnitData.UNIT_COLUMN), 125)
                viewHeader.setResizeMode(UnitData.UNIT_COLUMN, QtGui.QHeaderView.Fixed)
                viewHeader.resizeSection(UnitData.UNIT_COLUMN, unitSize)
 
@@ -1422,8 +1511,6 @@ class UnitWindow(object):
                self._window.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)
                maeqt.set_autorient(self._window, True)
                maeqt.set_stackable(self._window, True)
-               if parent is not None:
-                       self._window.setWindowModality(QtCore.Qt.WindowModal)
                self._window.setWindowTitle("%s - %s" % (constants.__pretty_app_name__, category))
                self._window.setWindowIcon(QtGui.QIcon(app.appIconPath))
                self._window.setCentralWidget(centralWidget)
@@ -1433,7 +1520,6 @@ class UnitWindow(object):
                        self.select_unit(defaultUnitName)
                else:
                        self._select_unit(0)
-               self._unitsModel.sort(UnitData.NAME_COLUMN)
 
                self._sortActionGroup = QtGui.QActionGroup(None)
                self._sortByNameAction = QtGui.QAction(self._sortActionGroup)
@@ -1452,7 +1538,10 @@ class UnitWindow(object):
                self._sortByUnitAction.setToolTip("Sort the units by unit")
                self._sortByUnitAction.setCheckable(True)
 
-               self._sortByValueAction.setChecked(True)
+               if UnitData.NAME_COLUMN != 0:
+                       # By default it sorts by he first column (name)
+                       self._unitsModel.sort(UnitData.NAME_COLUMN)
+               self._sortByNameAction.setChecked(True)
 
                self._chooseFavoritesAction = QtGui.QAction(None)
                self._chooseFavoritesAction.setText("Select Favorites")
@@ -1530,8 +1619,19 @@ class UnitWindow(object):
        def window(self):
                return self._window
 
+       def show(self):
+               for child in self.walk_children():
+                       child.hide()
+               self._window.show()
+
+       def hide(self):
+               for child in self.walk_children():
+                       child.hide()
+               self._window.hide()
+
        def close(self):
                for child in self.walk_children():
+                       child.window.destroyed.disconnect(self._on_child_close)
                        child.close()
                self._window.close()