Creation of history and getting it displayed
authorEd Page <eopage@byu.net>
Wed, 9 Jun 2010 01:37:16 +0000 (20:37 -0500)
committerEd Page <eopage@byu.net>
Wed, 9 Jun 2010 01:37:16 +0000 (20:37 -0500)
src/ejpi_qt.py
src/qhistory.py [new file with mode: 0644]

index 743b43d..813e821 100755 (executable)
@@ -15,6 +15,8 @@ import constants
 import maeqt
 from util import misc as misc_utils
 
+import qhistory
+
 
 _moduleLogger = logging.getLogger(__name__)
 
@@ -52,6 +54,9 @@ class Calculator(object):
                self._app.lastWindowClosed.connect(self._on_app_quit)
                self.load_settings()
 
+               self._mainWindow = MainWindow(None, self)
+               self._mainWindow.window.destroyed.connect(self._on_child_close)
+
        def load_settings(self):
                try:
                        with open(constants._user_settings_, "r") as settingsFile:
@@ -120,7 +125,10 @@ class MainWindow(object):
        def __init__(self, parent, app):
                self._app = app
 
+               self._historyView = qhistory.QCalcHistory()
+
                self._layout = QtGui.QVBoxLayout()
+               self._layout.addWidget(self._historyView.toplevel)
 
                centralWidget = QtGui.QWidget()
                centralWidget.setLayout(self._layout)
@@ -138,9 +146,9 @@ class MainWindow(object):
                self._closeWindowAction.triggered.connect(self._on_close_window)
 
                if IS_MAEMO:
-                       fileMenu = self._window.menuBar().addMenu("&File")
+                       #fileMenu = self._window.menuBar().addMenu("&File")
 
-                       viewMenu = self._window.menuBar().addMenu("&View")
+                       #viewMenu = self._window.menuBar().addMenu("&View")
 
                        self._window.addAction(self._closeWindowAction)
                        self._window.addAction(self._app.quitAction)
diff --git a/src/qhistory.py b/src/qhistory.py
new file mode 100644 (file)
index 0000000..74f085d
--- /dev/null
@@ -0,0 +1,243 @@
+#!/usr/bin/env python
+
+"""
+http://www.grigoriev.ru/svgmath/ (MathML->SVG in Python)
+http://helm.cs.unibo.it/mml-widget/ (MathML widget in C++)
+"""
+
+import logging
+
+from PyQt4 import QtGui
+from PyQt4 import QtCore
+
+import util.misc as misc_utils
+import history
+import operation
+
+
+_moduleLogger = logging.getLogger(__name__)
+
+
+class RowData(object):
+
+       HEADERS = ["", "Equation", "Result"]
+       ALIGNMENT = [QtCore.Qt.AlignLeft, QtCore.Qt.AlignLeft, QtCore.Qt.AlignLeft]
+       CLOSE_COLUMN = 0
+       EQ_COLUMN = 1
+       RESULT_COLUMN = 2
+
+       def __init__(self, renderer, node, simpleNode):
+               self._node = node
+               self._simpleNode = simpleNode
+               self._prettyRenderer = renderer
+
+       @property
+       def node(self):
+               return self._node
+
+       @property
+       def simpleNode(self):
+               return self._simpleNode
+
+       @property
+       def equation(self):
+               return operation.render_operation(self._prettyRenderer, self._node),
+
+       @property
+       def result(self):
+               return operation.render_operation(self._prettyRenderer, self._simpleNode),
+
+       def data(self, column):
+               if column == self.CLOSE_COLUMN:
+                       return ""
+               elif column == self.EQ_COLUMN:
+                       return self.equation
+               elif column == self.RESULT_COLUMN:
+                       return self.result
+               else:
+                       return None
+
+
+class HistoryModel(QtCore.QAbstractItemModel):
+
+       def __init__(self, parent=None):
+               super(HistoryModel, self).__init__(parent)
+
+               self._children = []
+
+       @misc_utils.log_exception(_moduleLogger)
+       def columnCount(self, parent):
+               if parent.isValid():
+                       return 0
+               else:
+                       return len(RowData.HEADERS)
+
+       @misc_utils.log_exception(_moduleLogger)
+       def data(self, index, role):
+               if not index.isValid():
+                       return None
+               elif role == QtCore.Qt.DecorationRole:
+                       if index.column() == RowData.CLOSE_COLUMN:
+                               return None
+                       else:
+                               return None
+               elif role == QtCore.Qt.TextAlignmentRole:
+                       return RowData.ALIGNMENT[index.column()]
+               elif role != QtCore.Qt.DisplayRole:
+                       return None
+
+               item = index.internalPointer()
+               if isinstance(item, RowData):
+                       return item.data(index.column())
+               elif item is RowData.HEADERS:
+                       return item[index.column()]
+
+       @misc_utils.log_exception(_moduleLogger)
+       def flags(self, index):
+               if not index.isValid():
+                       return QtCore.Qt.NoItemFlags
+
+               return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable
+
+       @misc_utils.log_exception(_moduleLogger)
+       def headerData(self, section, orientation, role):
+               if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
+                       return RowData.HEADERS[section]
+
+               return None
+
+       @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()
+
+               parentItem = RowData.HEADERS
+               childItem = self._children[row]
+               if childItem:
+                       return self.createIndex(row, column, childItem)
+               else:
+                       return QtCore.QModelIndex()
+
+       @misc_utils.log_exception(_moduleLogger)
+       def parent(self, index):
+               if not index.isValid():
+                       return QtCore.QModelIndex()
+
+               childItem = index.internalPointer()
+               if isinstance(childItem, RowData):
+                       return QtCore.QModelIndex()
+               elif childItem is RowData.HEADERS:
+                       return None
+
+       @misc_utils.log_exception(_moduleLogger)
+       def rowCount(self, parent):
+               if 0 < parent.column():
+                       return 0
+
+               if not parent.isValid():
+                       return len(self._children)
+               else:
+                       return len(self._children)
+
+       def push(self, row):
+               self._children.append(row)
+               self._signal_rows_added()
+
+       def pop(self):
+               data = self._children[-1]
+               del self._children[-1]
+               self._signal_rows_removed()
+               return data
+
+       def peek(self):
+               data = self._children[-1]
+               return data
+
+       def clear(self):
+               del self._children[:]
+               self._all_changed
+
+       def __len__(self):
+               return len(self._children)
+
+       def __iter__(self):
+               return iter(self._children)
+
+       def _signal_rows_added(self):
+               # @todo Only signal new rows
+               self._all_changed
+
+       def _signal_rows_removed(self):
+               # @todo Only signal new rows
+               self._all_changed
+
+       def _all_changed(self):
+               topLeft = self.createIndex(0, 0, self._children[0])
+               bottomRight = self.createIndex(len(self._children)-1, len(RowData.HEADERS)-1, self._children[-1])
+               self.dataChanged.emit(topLeft, bottomRight)
+
+
+class QCalcHistory(history.AbstractHistory):
+
+       def __init__(self):
+               super(QCalcHistory, self).__init__()
+               self._prettyRenderer = operation.render_number()
+
+               self._historyStore = HistoryModel()
+
+               self._historyView = QtGui.QTreeView()
+               self._historyView.setModel(self._historyStore)
+               self._historyView.setUniformRowHeights(True)
+               self._historyView.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
+               self._historyView.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
+               self._historyView.setSelectionMode(QtGui.QAbstractItemView.SingleSelection)
+               self._historyView.setHeaderHidden(True)
+
+               viewHeader = self._historyView.header()
+               viewHeader.setSortIndicatorShown(True)
+               viewHeader.setClickable(True)
+
+               viewHeader.setResizeMode(RowData.CLOSE_COLUMN, QtGui.QHeaderView.ResizeToContents)
+               viewHeader.setResizeMode(RowData.EQ_COLUMN, QtGui.QHeaderView.ResizeToContents)
+               viewHeader.setResizeMode(RowData.RESULT_COLUMN, QtGui.QHeaderView.ResizeToContents)
+               viewHeader.setStretchLastSection(False)
+
+       @property
+       def toplevel(self):
+               return self._historyView
+
+       def push(self, node):
+               simpleNode = node.simplify()
+               row = RowData(node, simpleNode)
+               self._historyStore.push(row)
+
+               selection = self._historyView.get_selection()
+               selectionPath = (len(self._historyStore)-1, )
+               selection.select_path(selectionPath)
+               self._historyView.scroll_to_cell(selectionPath)
+
+       def pop(self):
+               if len(self._historyStore) == 0:
+                       raise IndexError("Not enough items in the history for the operation")
+
+               row = self._historyStore.pop()
+               return row.node
+
+       def peek(self):
+               if len(self._historyStore) == 0:
+                       raise IndexError("Not enough items in the history for the operation")
+               row = self._historyStore.peek()
+               return row.node
+
+       def clear(self):
+               self._historyStore.clear()
+
+       def __len__(self):
+               return len(self._historyStore)
+
+       def __iter__(self):
+               for row in iter(self._historyStore):
+                       yield row.node