4 http://www.grigoriev.ru/svgmath/ (MathML->SVG in Python)
5 http://helm.cs.unibo.it/mml-widget/ (MathML widget in C++)
10 from PyQt4 import QtGui
11 from PyQt4 import QtCore
13 import util.misc as misc_utils
18 _moduleLogger = logging.getLogger(__name__)
21 class RowData(object):
23 HEADERS = ["", "Equation", "Result"]
24 ALIGNMENT = [QtCore.Qt.AlignLeft, QtCore.Qt.AlignLeft, QtCore.Qt.AlignLeft]
29 def __init__(self, renderer, node, simpleNode):
31 self._simpleNode = simpleNode
32 self._prettyRenderer = renderer
40 return self._simpleNode
44 return operation.render_operation(self._prettyRenderer, self._node),
48 return operation.render_operation(self._prettyRenderer, self._simpleNode),
50 def data(self, column):
51 if column == self.CLOSE_COLUMN:
53 elif column == self.EQ_COLUMN:
55 elif column == self.RESULT_COLUMN:
61 class HistoryModel(QtCore.QAbstractItemModel):
63 def __init__(self, parent=None):
64 super(HistoryModel, self).__init__(parent)
68 @misc_utils.log_exception(_moduleLogger)
69 def columnCount(self, parent):
73 return len(RowData.HEADERS)
75 @misc_utils.log_exception(_moduleLogger)
76 def data(self, index, role):
77 if not index.isValid():
79 elif role == QtCore.Qt.DecorationRole:
80 if index.column() == RowData.CLOSE_COLUMN:
84 elif role == QtCore.Qt.TextAlignmentRole:
85 return RowData.ALIGNMENT[index.column()]
86 elif role != QtCore.Qt.DisplayRole:
89 item = index.internalPointer()
90 if isinstance(item, RowData):
91 return item.data(index.column())
92 elif item is RowData.HEADERS:
93 return item[index.column()]
95 @misc_utils.log_exception(_moduleLogger)
96 def flags(self, index):
97 if not index.isValid():
98 return QtCore.Qt.NoItemFlags
100 return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable
102 @misc_utils.log_exception(_moduleLogger)
103 def headerData(self, section, orientation, role):
104 if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
105 return RowData.HEADERS[section]
109 @misc_utils.log_exception(_moduleLogger)
110 def index(self, row, column, parent):
111 if not self.hasIndex(row, column, parent):
112 return QtCore.QModelIndex()
115 return QtCore.QModelIndex()
117 parentItem = RowData.HEADERS
118 childItem = self._children[row]
120 return self.createIndex(row, column, childItem)
122 return QtCore.QModelIndex()
124 @misc_utils.log_exception(_moduleLogger)
125 def parent(self, index):
126 if not index.isValid():
127 return QtCore.QModelIndex()
129 childItem = index.internalPointer()
130 if isinstance(childItem, RowData):
131 return QtCore.QModelIndex()
132 elif childItem is RowData.HEADERS:
135 @misc_utils.log_exception(_moduleLogger)
136 def rowCount(self, parent):
137 if 0 < parent.column():
140 if not parent.isValid():
141 return len(self._children)
143 return len(self._children)
146 self._children.append(row)
147 self._signal_rows_added()
150 data = self._children[-1]
151 del self._children[-1]
152 self._signal_rows_removed()
156 data = self._children[-1]
160 del self._children[:]
164 return len(self._children)
167 return iter(self._children)
169 def _signal_rows_added(self):
170 # @todo Only signal new rows
173 def _signal_rows_removed(self):
174 # @todo Only signal new rows
177 def _all_changed(self):
178 topLeft = self.createIndex(0, 0, self._children[0])
179 bottomRight = self.createIndex(len(self._children)-1, len(RowData.HEADERS)-1, self._children[-1])
180 self.dataChanged.emit(topLeft, bottomRight)
183 class QCalcHistory(history.AbstractHistory):
186 super(QCalcHistory, self).__init__()
187 self._prettyRenderer = operation.render_number()
189 self._historyStore = HistoryModel()
191 self._historyView = QtGui.QTreeView()
192 self._historyView.setModel(self._historyStore)
193 self._historyView.setUniformRowHeights(True)
194 self._historyView.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
195 self._historyView.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
196 self._historyView.setSelectionMode(QtGui.QAbstractItemView.SingleSelection)
197 self._historyView.setHeaderHidden(True)
199 viewHeader = self._historyView.header()
200 viewHeader.setSortIndicatorShown(True)
201 viewHeader.setClickable(True)
203 viewHeader.setResizeMode(RowData.CLOSE_COLUMN, QtGui.QHeaderView.ResizeToContents)
204 viewHeader.setResizeMode(RowData.EQ_COLUMN, QtGui.QHeaderView.ResizeToContents)
205 viewHeader.setResizeMode(RowData.RESULT_COLUMN, QtGui.QHeaderView.ResizeToContents)
206 viewHeader.setStretchLastSection(False)
210 return self._historyView
212 def push(self, node):
213 simpleNode = node.simplify()
214 row = RowData(node, simpleNode)
215 self._historyStore.push(row)
217 selection = self._historyView.get_selection()
218 selectionPath = (len(self._historyStore)-1, )
219 selection.select_path(selectionPath)
220 self._historyView.scroll_to_cell(selectionPath)
223 if len(self._historyStore) == 0:
224 raise IndexError("Not enough items in the history for the operation")
226 row = self._historyStore.pop()
230 if len(self._historyStore) == 0:
231 raise IndexError("Not enough items in the history for the operation")
232 row = self._historyStore.peek()
236 self._historyStore.clear()
239 return len(self._historyStore)
242 for row in iter(self._historyStore):