Consolidating UI updates for user edits to speed thigns up
[gonvert] / src / gonvert_qt.py
index ab5a754..170e500 100755 (executable)
@@ -3,7 +3,6 @@
 
 #@todo Research Fn
 #@todo Research optimizations
-#@todo Look into switching favorites from selection to checking?
 
 from __future__ import with_statement
 
@@ -29,6 +28,10 @@ IS_MAEMO = True
 
 
 def split_number(number):
+       if number == 0.0:
+               # Optimize the startup case
+               return "0.", "0"
+
        try:
                fractional, integer = math.modf(number)
        except TypeError:
@@ -40,15 +43,16 @@ def split_number(number):
                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
+                       if 0.0 < integer:
+                               integerDisplay = number
+                               fractionalDisplay = ""
+                       else:
+                               integerDisplay = ""
+                               fractionalDisplay = number
                else:
-                       integerDisplay = integerDisplay.split(".", 1)[0] + "."
-                       fractionalDisplay = fractionalDisplay.rsplit(".", 1)[-1]
+                       integerDisplay = integerDisplay[0:-2] + "."
+                       fractionalDisplay = fractionalDisplay[2:]
 
        return integerDisplay, fractionalDisplay
 
@@ -1036,19 +1040,19 @@ class FavoritesWindow(object):
                self._categories = QtGui.QTreeWidget()
                self._categories.setHeaderLabels(["Categories"])
                self._categories.setHeaderHidden(True)
+               self._categories.setSelectionMode(QtGui.QAbstractItemView.NoSelection)
                if not IS_MAEMO:
                        self._categories.setAlternatingRowColors(True)
-               self._categories.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
-               self._categories.setSelectionMode(QtGui.QAbstractItemView.MultiSelection)
                self._childWidgets = []
                for catName in self._source:
                        twi = QtGui.QTreeWidgetItem(self._categories)
                        twi.setText(0, catName)
                        self._childWidgets.append(twi)
-                       if catName not in self._hidden:
-                               self._categories.setItemSelected(twi, True)
-               self._selection = self._categories.selectionModel()
-               self._selection.selectionChanged.connect(self._on_selection_changed)
+                       if catName in self._hidden:
+                               twi.setCheckState(0, QtCore.Qt.Unchecked)
+                       else:
+                               twi.setCheckState(0, QtCore.Qt.Checked)
+               self._categories.itemChanged.connect(self._on_item_changed)
 
                self._allButton = QtGui.QPushButton("All")
                self._allButton.clicked.connect(self._on_select_all)
@@ -1121,29 +1125,36 @@ class FavoritesWindow(object):
        @misc_utils.log_exception(_moduleLogger)
        def _on_select_all(self, checked = False):
                for child in self._childWidgets:
-                       self._categories.setItemSelected(child, True)
+                       child.setCheckState(0, QtCore.Qt.Checked)
 
        @misc_utils.log_exception(_moduleLogger)
        def _on_invert_selection(self, checked = False):
                for child in self._childWidgets:
-                       isSelected = self._categories.isItemSelected(child)
-                       self._categories.setItemSelected(child, not isSelected)
+                       state = child.checkState(0)
+                       if state == QtCore.Qt.Unchecked:
+                               newState = QtCore.Qt.Checked
+                       elif state == QtCore.Qt.Checked:
+                               newState = QtCore.Qt.Unchecked
+                       else:
+                               raise RuntimeError("Bad check state %r" % state)
+                       child.setCheckState(0, newState)
 
        @misc_utils.log_exception(_moduleLogger)
        def _on_select_none(self, checked = False):
                for child in self._childWidgets:
-                       self._categories.setItemSelected(child, False)
+                       child.setCheckState(0, QtCore.Qt.Unchecked)
 
        @misc_utils.log_exception(_moduleLogger)
-       def _on_selection_changed(self, selected, deselected):
-               self._hidden.clear()
-               selectedNames = set(
-                       str(item.text(0))
-                       for item in self._categories.selectedItems()
-               )
-               for name in self._source:
-                       if name not in selectedNames:
-                               self._hidden.add(name)
+       def _on_item_changed(self, item, column):
+               state = item.checkState(column)
+               if state == QtCore.Qt.Unchecked:
+                       name = str(item.text(column))
+                       self._hidden.add(name)
+               elif state == QtCore.Qt.Checked:
+                       name = str(item.text(column))
+                       self._hidden.remove(name)
+               else:
+                       raise RuntimeError("Bad check state %r" % state)
 
        @misc_utils.log_exception(_moduleLogger)
        def _on_close_window(self, checked = True):
@@ -1344,6 +1355,11 @@ class UnitData(object):
        VALUE_COLUMN_1 = 2
        UNIT_COLUMN = 3
 
+       __slots__ = [
+               "_name", "_unit", "_description", "_conversion",
+               "_value", "_integerDisplay", "_fractionalDisplay",
+       ]
+
        def __init__(self, name, unit, description, conversion):
                self._name = name
                self._unit = unit
@@ -1386,6 +1402,10 @@ class UnitModel(QtCore.QAbstractItemModel):
                super(UnitModel, self).__init__(parent)
                self._categoryName = categoryName
                self._unitData = unit_data.UNIT_DESCRIPTIONS[self._categoryName]
+               if self._categoryName == "Computer Numbers":
+                       self._sanitize_value = self._sanitize_alpha_value
+               else:
+                       self._sanitize_value = self._sanitize_numeric_value
 
                self._children = []
                for key in unit_data.get_units(self._categoryName):
@@ -1402,19 +1422,20 @@ class UnitModel(QtCore.QAbstractItemModel):
 
        @misc_utils.log_exception(_moduleLogger)
        def data(self, index, role):
-               if not index.isValid():
-                       return None
+               #if not index.isValid():
+               #       return None
+
+               if role == QtCore.Qt.DisplayRole:
+                       item = index.internalPointer()
+                       if isinstance(item, UnitData):
+                               return item.data(index.column())
+                       elif item is UnitData.HEADERS:
+                               return item[index.column()]
                elif role == QtCore.Qt.TextAlignmentRole:
                        return UnitData.ALIGNMENT[index.column()]
-               elif role != QtCore.Qt.DisplayRole:
+               else:
                        return None
 
-               item = index.internalPointer()
-               if isinstance(item, UnitData):
-                       return item.data(index.column())
-               elif item is UnitData.HEADERS:
-                       return item[index.column()]
-
        @misc_utils.log_exception(_moduleLogger)
        def sort(self, column, order = QtCore.Qt.AscendingOrder):
                self._sortSettings = column, order
@@ -1445,11 +1466,10 @@ class UnitModel(QtCore.QAbstractItemModel):
 
        @misc_utils.log_exception(_moduleLogger)
        def index(self, row, column, parent):
-               if not self.hasIndex(row, column, parent):
-                       return QtCore.QModelIndex()
-
-               if parent.isValid():
-                       return QtCore.QModelIndex()
+               #if not self.hasIndex(row, column, parent):
+               #       return QtCore.QModelIndex()
+               #elif parent.isValid():
+               #       return QtCore.QModelIndex()
 
                parentItem = UnitData.HEADERS
                childItem = self._children[row]
@@ -1509,8 +1529,10 @@ class UnitModel(QtCore.QAbstractItemModel):
                ):
                        # Sort takes care of marking everything as changed
                        self.sort(*self._sortSettings)
+                       return True
                else:
                        self._values_changed()
+                       return False
 
        def __len__(self):
                return len(self._children)
@@ -1525,17 +1547,18 @@ class UnitModel(QtCore.QAbstractItemModel):
                bottomRight = self.createIndex(len(self._children)-1, len(UnitData.HEADERS)-1, self._children[-1])
                self.dataChanged.emit(topLeft, bottomRight)
 
-       def _sanitize_value(self, userEntry):
-               if self._categoryName == "Computer Numbers":
-                       if userEntry == '':
-                               value = '0'
-                       else:
-                               value = userEntry
+       def _sanitize_alpha_value(self, userEntry):
+               if userEntry:
+                       value = userEntry
                else:
-                       if userEntry == '':
-                               value = 0.0
-                       else:
-                               value = float(userEntry)
+                       value = '0'
+               return value
+
+       def _sanitize_numeric_value(self, userEntry):
+               if userEntry:
+                       value = float(userEntry)
+               else:
+                       value = 0.0
                return value
 
 
@@ -1552,6 +1575,10 @@ class UnitWindow(object):
                self._selectedUnitValue.textEdited.connect(self._on_value_edited)
                maeqt.mark_numbers_preferred(self._selectedUnitValue)
                self._selectedUnitSymbol = QtGui.QLabel()
+               self._updateDelayTimer = QtCore.QTimer()
+               self._updateDelayTimer.setInterval(100)
+               self._updateDelayTimer.setSingleShot(True)
+               self._updateDelayTimer.timeout.connect(self._on_value_edited_delayed)
 
                self._selectedUnitLayout = QtGui.QHBoxLayout()
                self._selectedUnitLayout.addWidget(self._selectedUnitName)
@@ -1561,15 +1588,15 @@ class UnitWindow(object):
                self._unitsModel = UnitModel(self._categoryName)
                self._unitsView = QtGui.QTreeView()
                self._unitsView.setModel(self._unitsModel)
-               self._unitsView.clicked.connect(self._on_unit_clicked)
                self._unitsView.setUniformRowHeights(True)
                self._unitsView.setSortingEnabled(True)
                self._unitsView.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
                self._unitsView.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
                self._unitsView.setSelectionMode(QtGui.QAbstractItemView.SingleSelection)
+               self._unitsView.setHeaderHidden(True)
+               self._unitsView.clicked.connect(self._on_unit_clicked)
                if not IS_MAEMO:
                        self._unitsView.setAlternatingRowColors(True)
-               self._unitsView.setHeaderHidden(True)
 
                viewHeader = self._unitsView.header()
                viewHeader.setSortIndicatorShown(True)
@@ -1802,9 +1829,15 @@ class UnitWindow(object):
 
        @misc_utils.log_exception(_moduleLogger)
        def _on_value_edited(self, *args):
-               userInput = self._selectedUnitValue.text()
-               self._unitsModel.update_values(self._selectedIndex, str(userInput))
-               self._update_favorites()
+               if not self._updateDelayTimer.isActive():
+                       self._updateDelayTimer.start()
+
+       @misc_utils.log_exception(_moduleLogger)
+       def _on_value_edited_delayed(self, *args):
+               userInput = str(self._selectedUnitValue.text())
+               orderChanged = self._unitsModel.update_values(self._selectedIndex, userInput)
+               if orderChanged:
+                       self._update_favorites()
 
        def _select_unit(self, index):
                unit = self._unitsModel.get_unit(index)
@@ -1819,7 +1852,10 @@ class UnitWindow(object):
 def run_gonvert():
        app = QtGui.QApplication([])
        handle = Gonvert(app)
-       return app.exec_()
+       if constants.PROFILE_STARTUP:
+               return 0
+       else:
+               return app.exec_()
 
 
 if __name__ == "__main__":