4 http://www.grigoriev.ru/svgmath/ (MathML->SVG in Python)
5 http://helm.cs.unibo.it/mml-widget/ (MathML widget in C++)
8 from __future__ import with_statement
12 from PyQt4 import QtGui
13 from PyQt4 import QtCore
15 from util import qui_utils
16 import util.misc as misc_utils
21 _moduleLogger = logging.getLogger(__name__)
24 class QCalcHistory(history.AbstractHistory):
30 def __init__(self, errorReporter):
31 super(QCalcHistory, self).__init__()
32 self._prettyRenderer = operation.render_number()
33 self._errorLog = errorReporter
35 self._historyStore = QtGui.QStandardItemModel()
36 self._historyStore.setHorizontalHeaderLabels(["", "Equation", "Result"])
37 self._historyStore.itemChanged.connect(self._on_item_changed)
39 self._historyView = QtGui.QTreeView()
40 self._historyView.setModel(self._historyStore)
41 self._historyView.setUniformRowHeights(True)
42 self._historyView.setRootIsDecorated(False)
43 self._historyView.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
44 self._historyView.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
45 self._historyView.setSelectionMode(QtGui.QAbstractItemView.SingleSelection)
46 self._historyView.setHeaderHidden(True)
47 self._historyView.activated.connect(self._on_row_activated)
49 viewHeader = self._historyView.header()
50 viewHeader.setSortIndicatorShown(True)
51 viewHeader.setClickable(True)
53 viewHeader.setResizeMode(self._CLOSE_COLUMN, QtGui.QHeaderView.ResizeToContents)
54 viewHeader.setResizeMode(self._EQ_COLUMN, QtGui.QHeaderView.Stretch)
55 viewHeader.setResizeMode(self._RESULT_COLUMN, QtGui.QHeaderView.ResizeToContents)
56 viewHeader.setStretchLastSection(False)
59 self._programmaticUpdate = False
60 self._closeIcon = qui_utils.get_theme_icon(("window-close", "general_close", "gtk-close"))
64 return self._historyView
67 simpleNode = node.simplify()
69 closeIcon = self._closeIcon
70 icon = QtGui.QStandardItem(closeIcon, "")
71 icon.setEditable(False)
72 icon.setCheckable(False)
73 equation = QtGui.QStandardItem(operation.render_operation(self._prettyRenderer, node))
74 equation.setData(node)
75 equation.setCheckable(False)
76 eqFont = equation.font()
77 eqFont.setPointSize(max(eqFont.pointSize() - 3, 5))
78 equation.setFont(eqFont)
80 result = QtGui.QStandardItem(operation.render_operation(self._prettyRenderer, simpleNode))
81 result.setData(simpleNode)
82 result.setEditable(False)
83 result.setCheckable(False)
85 row = (icon, equation, result)
86 self._historyStore.appendRow(row)
88 index = result.index()
89 self._historyView.scrollToBottom()
94 raise IndexError("Not enough items in the history for the operation")
96 icon, equation, result = self._historyStore.takeRow(self._rowCount - 1)
98 return equation.data().toPyObject()
102 raise IndexError("Not enough items in the history for the operation")
104 icon, equation, result = self._historyStore.takeRow(self._rowCount - 1)
105 row = (icon, equation, result)
106 self._historyStore.appendRow(row)
108 return equation.data().toPyObject()
111 self._historyStore.clear()
114 def scroll_to_bottom(self):
115 self._historyView.scrollToBottom()
117 @misc_utils.log_exception(_moduleLogger)
118 def _on_row_activated(self, index):
119 with qui_utils.notify_error(self._errorLog):
120 if index.column() == self._CLOSE_COLUMN:
121 self._historyStore.removeRow(index.row(), index.parent())
123 elif index.column() == self._EQ_COLUMN:
124 self._duplicate_row(index)
125 elif index.column() == self._RESULT_COLUMN:
126 self._duplicate_row(index)
128 raise NotImplementedError("Unsupported column to activate %s" % index.column())
130 @misc_utils.log_exception(_moduleLogger)
131 def _on_item_changed(self, item):
132 with qui_utils.notify_error(self._errorLog):
133 if self._programmaticUpdate:
134 _moduleLogger.info("Blocking updating %r recursively" % item)
136 self._programmaticUpdate = True
138 if item.column() in [self._EQ_COLUMN, self._RESULT_COLUMN]:
139 self._update_input(item)
141 raise NotImplementedError("Unsupported column to edit %s" % item.column())
142 except StandardError, e:
143 self._errorReporter.push_exception()
145 self._programmaticUpdate = False
147 def _duplicate_row(self, index):
148 item = self._historyStore.item(index.row(), self._EQ_COLUMN)
149 self.push(item.data().toPyObject())
151 def _parse_value(self, value):
152 raise NotImplementedError("What?")
154 def _update_input(self, item):
155 node = item.data().toPyObject()
157 eqNode = self._parse_value(str(item.text()))
158 newText = operation.render_operation(self._prettyRenderer, eqNode)
160 eqItem = self._historyStore.item(item.row(), self._EQ_COLUMN)
161 eqItem.setData(eqNode)
162 eqItem.setText(newText)
164 resultNode = eqNode.simplify()
165 resultText = operation.render_operation(self._prettyRenderer, resultNode)
166 resultItem = self._historyStore.item(item.row(), self._RESULT_COLUMN)
167 resultItem.setData(resultNode)
168 resultItem.setText(resultText)
170 oldText = operation.render_operation(self._prettyRenderer, node)
171 item.setText(oldText)
175 return self._rowCount
178 for i in xrange(self._rowCount):
179 item = self._historyStore.item(i, self._EQ_COLUMN)
182 yield item.data().toPyObject()