1# ---------------------------------------------------------------------- 2# $Id: qrcontroller.py 2640 2014-08-12 02:04:01Z thomas-sturm $ 3# ---------------------------------------------------------------------- 4# (c) 2009 T. Sturm, 2010 T. Sturm, C. Zengler, 2011-2014 T. Sturm 5# ---------------------------------------------------------------------- 6# Redistribution and use in source and binary forms, with or without 7# modification, are permitted provided that the following conditions 8# are met: 9# 10# * Redistributions of source code must retain the relevant 11# copyright notice, this list of conditions and the following 12# disclaimer. 13# * Redistributions in binary form must reproduce the above 14# copyright notice, this list of conditions and the following 15# disclaimer in the documentation and/or other materials provided 16# with the distribution. 17# 18# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22# OWNERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29# 30 31from PySide.QtCore import QObject 32from PySide.QtCore import Signal 33 34from qrlogging import fontLogger 35from qrlogging import signalLogger 36from qrlogging import traceLogger 37 38from qrmodel import QtReduceComputation 39from qrmodel import QtReduceModel 40 41from qrview import QtReduceFrameView 42from qrview import SubCell 43 44from types import BooleanType 45from types import StringType 46 47 48class QtReduceController(QObject): 49 endComputation = Signal(object) 50 acceptAbort = Signal(BooleanType) 51 fileNameChanged = Signal(StringType) 52 modified = Signal(BooleanType) 53 startComputation = Signal(object) 54 55 def __init__(self,parent=None): 56 super(QtReduceController,self).__init__(parent) 57 58 self.mainWindow = parent 59 60 self.setFileName('') 61 62 self.model = QtReduceModel(self) 63 self.view = QtReduceFrameView(parent) 64 65 self.view.computationRequest.connect(self.computationRequestV) 66 self.view.modified.connect(self.modifiedV) 67 68 self.model.dataChanged.connect(self.dataChangedM) 69 self.model.endComputation.connect(self.endComputationM) 70 self.model.rowsInserted.connect(self.rowsInsertedM) 71 self.model.rowsRemoved.connect(self.rowsRemovedM) 72 self.model.startComputation.connect(self.startComputationM) 73 self.updatingModel = False 74 75 self.model.insertRow(0) 76 77 def abortComputation(self): 78 self.model.abortComputation() 79 80 def computationRequestV(self,row): 81 signalLogger.debug("catching row = %d" % row) 82 if not self.view.input(row): 83 return 84 index = self.model.index(row,0) 85 computation = self.model.data(index,QtReduceModel.RawDataRole) 86 computation.command = self.view.input(row) 87 self.model.setData(index,computation,QtReduceModel.RawDataRole) 88 self.model.compute(row) 89 90 def evaluateAll(self): 91 for row in range(self.view.rowCount()): 92 self.computationRequestV(row) 93 94 def evaluateSelection(self): 95 None 96 97 def dataChangedM(self,topLeft,bottomRight): 98 if self.updatingModel: 99 return 100 start = topLeft.row() 101 end = bottomRight.row() 102 signalLogger.debug("start = %d, end = %d" % (start,end)) 103 for row in range(start,end+1): 104 index = self.model.index(row,0) 105 computation = self.model.data(index,QtReduceModel.RawDataRole) 106 self.setCell(row,computation) 107 if computation.status in [QtReduceComputation.Error, 108 QtReduceComputation.Aborted]: 109 return 110 if row < self.model.rowCount() - 1: 111 self.view.gotoRow(row + 1) 112 113 def setCell(self,row,computation): 114 self.view.setCell(row, 115 computation.c1, 116 computation.command, 117 computation.c2, 118 computation.result, 119 computation.c3) 120 s = computation.status 121 if s == QtReduceComputation.NotEvaluated: 122 self.view.setNotEvaluated(row) 123 elif s == QtReduceComputation.Evaluated: 124 if computation.result: 125 result = computation.result 126 if not computation.symbolic: 127 result = self.renderResult(result) 128 self.view.setResult(row,result) 129 else: 130 self.view.setNoResult(row) 131 elif s == QtReduceComputation.Error: 132 self.view.setError(row,computation.errorText) 133 elif s == QtReduceComputation.Aborted: 134 self.view.setAborted(row) 135 else: 136 traceLogger.debug("Bad status: %d" % s) 137 138 def deleteOutput(self): 139 self.model.deleteOutput() 140 141 def deleteRowOrPreviousRow(self): 142 row = self.view.rowOrPreviousRow() 143 if row >= 0: 144 self.model.removeRow(row) 145 if self.model.rowCount() == 0: 146 self.model.insertRow(0) 147 148 def endComputationM(self,computation): 149 signalLogger.debug("catching computation.statCounter = %s," 150 "status=%s" % 151 (computation.statCounter,computation.status)) 152 self.view.setReadOnly(False) 153 self.acceptAbort.emit(False) 154 self.endComputation.emit(computation) 155 156 def fileName(self): 157 return self.__fileName 158 159 def insertAbove(self): 160 if self.view.atEnd(): 161 self.model.insertRow(self.model.rowCount()) 162 return 163 row = self.view.rowOrNextRow() 164 if row < 0: 165 traceLogger.critical("unxepected row %s" % row) 166 self.model.insertRow(row) 167 self.view.gotoRow(row) 168 169 def insertBelow(self): 170 if self.view.atStart(): 171 self.model.insertRow(0) 172 return 173 row = self.view.rowOrPreviousRow() 174 if row < 0: 175 traceLogger.critical("unxepected row %s" % row) 176 self.model.insertRow(row + 1) 177 self.view.gotoRow(row + 1) 178 179 def modifiedV(self): 180 self.updatingModel = True 181 sc = self.view.subCell() 182 if sc.type != SubCell.Root: 183 row = sc.row 184 index = self.model.index(row,0) 185 computation = self.model.data(index,QtReduceModel.RawDataRole) 186 if sc.type == SubCell.Input: 187 computation.command = sc.content 188 elif sc.type == SubCell.C1: 189 computation.c1 = sc.content 190 elif sc.type == SubCell.C2: 191 computation.c2 = sc.content 192 elif sc.type == SubCell.C3: 193 computation.c3 = sc.content 194 self.model.setData(index,computation,QtReduceModel.RawDataRole) 195 self.modified.emit(True) 196 self.updatingModel = False 197 198 def open(self,fileName): 199 success = self.model.open(fileName) 200 if success: 201 self.view.gotoRow(self.model.rowCount() - 1) 202 self.modified.emit(False) 203 self.setFileName(fileName) 204 self.parent().showMessage(self.tr("Read ") + fileName) 205 return 206 207 def renderResult(self,result): 208 traceLogger.debug("result=%s" % result) 209 if result.strip("\\0123456789 ") == '': 210 return result.replace('\\ ','\\\n') 211 command = "qr_render(" + result.rstrip("$") + ");" 212 answer = self.model.reduce.reduce.compute(command) 213 rendered = answer['pretext'] 214 if rendered: 215 rendered = rendered.strip("\n") 216 traceLogger.debug("rendered=%s" % rendered) 217 return rendered 218 219 def rowsInsertedM(self,parent,start,end): 220 traceLogger.debug("start=%d, end=%d" % (start, end)) 221 self.view.insertRows(start,end) 222 223 def rowsRemovedM(self,parent,start,end): 224 traceLogger.debug("start=%d, end=%d" % (start, end)) 225 self.view.removeRows(start,end) 226 227 def save(self): 228 if not self.__fileName: 229 traceLogger.critical('empty file name') 230 self.__saveAs(self.__fileName) 231 232 def saveAs(self,fileName): 233 self.__saveAs(fileName) 234 self.setFileName(fileName) 235 236 def setFileName(self,name): 237 self.__fileName = name 238 self.fileNameChanged.emit(name) 239 240 def startComputationM(self,computation): 241 signalLogger.debug("catching computation.command = %s" % 242 computation.command) 243 self.view.setReadOnly(True) 244 self.acceptAbort.emit(True) 245 self.startComputation.emit(computation) 246 247 def __saveAs(self,fileName): 248 self.model.save(fileName) 249 self.modified.emit(False) 250 self.parent().showMessage(self.tr("Wrote ") + fileName) 251