1# ---------------------------------------------------------------------- 2# $Id: qrview.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 types import IntType 32from types import BooleanType 33 34from PySide.QtCore import Qt 35from PySide.QtCore import Signal 36from PySide.QtCore import QSettings 37 38from PySide.QtGui import QColor 39from PySide.QtGui import QFont 40from PySide.QtGui import QFontDatabase 41from PySide.QtGui import QFontInfo 42from PySide.QtGui import QFrame 43from PySide.QtGui import QMessageBox 44from PySide.QtGui import QPainter 45from PySide.QtGui import qRgb 46from PySide.QtGui import QTextCursor 47from PySide.QtGui import QTextEdit 48 49from qrlogging import fontLogger 50from qrlogging import signalLogger 51from qrlogging import traceLogger 52 53from qrdefaults import QtReduceDefaults 54 55from qrformats import QtReduceFormat 56from qrformats import QtReduceInput 57from qrformats import QtReduceResult 58from qrformats import QtReduceNoResult 59from qrformats import QtReduceError 60from qrformats import QtReduceRowFormat 61 62 63class QtReduceTextEdit(QTextEdit): 64 65 computationRequest = Signal(IntType) 66 modified = Signal(BooleanType) 67 68 def __init__(self,parent=None): 69 super(QtReduceTextEdit,self).__init__(parent) 70 self.setupFont(int(QSettings().value("worksheet/fontsize", 71 QtReduceDefaults.FONTSIZE))) 72 self.textChanged.connect(self.textChangedHandler) 73 self.setCursorWidth(1) 74 75 def __nextGoodFontSize(self,font,size,step): 76 info = QFontInfo(font) 77 family = info.family() 78 fontDatabase = QFontDatabase() 79 styleStr = fontDatabase.styleString(font) 80 fontLogger.debug("family=%s, style=%s" % (family,styleStr)) 81 if fontDatabase.isSmoothlyScalable(family,styleStr): 82 sizes = QFontDatabase.standardSizes() 83 else: 84 sizes = fontDatabase.smoothSizes(family,styleStr) 85 fontLogger.debug("looking for %s in %s step %d" % (size,sizes,step)) 86 nSize = size 87 while nSize not in sizes and sizes[0] <= nSize and nSize <= sizes[-1]: 88 nSize += step 89 if nSize < sizes[0]: 90 fontLogger.debug("out of range - returning %s" % sizes[0]) 91 return sizes[0] 92 if sizes[-1] < nSize: 93 fontLogger.debug("out of range - returning %s" % sizes[-1]) 94 return sizes[-1] 95 fontLogger.debug("found %s" % nSize) 96 return nSize 97 98 def setupFont(self,size=None,step=1): 99 traceLogger.debug("size=%s, step=%s" % (size,step)) 100 if not size: 101 size = self.font().pointSize() 102 font = self.font() 103 font.setFamily(QSettings().value("worksheet/fontfamily", 104 QtReduceDefaults.FONTFAMILY)) 105 font.setFixedPitch(True) 106 font.setKerning(0) 107 font.setWeight(QFont.Normal) 108 font.setItalic(False) 109 font.setPointSize(self.__nextGoodFontSize(font,size,step)) 110 self.setFont(font) 111 112 def currentFontChangedHandler(self,newFont): 113 QSettings().setValue("worksheet/fontfamily",newFont.family()) 114 self.setupFont() 115 self.ensureCursorVisible() 116 117 def currentSizeChangedHandler(self,newSize,fullScreen): 118 newSize = int(newSize) 119 traceLogger.debug("newSize=%s (%s)" % (newSize,type(newSize))) 120 QSettings().setValue("worksheet/fontsize",newSize) 121 if not fullScreen: 122 self.setupFont(newSize) 123 124 def currentSizeChangedHandlerFs(self,newSize,fullScreen): 125 newSize = int(newSize) 126 traceLogger.debug("newSize=%s (%s)" % (newSize,type(newSize))) 127 QSettings().setValue("worksheet/fontsizefs",newSize) 128 if fullScreen: 129 self.setupFont(newSize) 130 131 def textChangedHandler(self): 132 if self.insertingFrames: 133 return 134 self.modified.emit(True) 135 136 def zoomDef(self,fullScreen): 137 if fullScreen: 138 fs = int(QSettings().value("worksheet/fontsizefs", 139 QtReduceDefaults.FONTSIZEFS)) 140 else: 141 fs = int(QSettings().value("worksheet/fontsize", 142 QtReduceDefaults.FONTSIZE)) 143 self.setupFont(fs) 144 145 def zoomIn(self): 146 currentSize = self.font().pointSize() 147 self.setupFont(currentSize + 1) 148 149 def zoomOut(self): 150 currentSize = self.font().pointSize() 151 self.setupFont(currentSize - 1,step=-1) 152 153 154class QtReduceFrameView(QtReduceTextEdit): 155 Aborted = u'Aborted' 156 Evaluated = u'\u2713'.encode("utf-8") 157 NotEvaluated = '' 158 leftRow = Signal(IntType) 159 160 def __init__(self,parent=None): 161 super(QtReduceFrameView,self).__init__(parent) 162 self.setUndoRedoEnabled(False) 163 self.selectionChanged.connect(self.pruneSelection) 164 self.insertingFrames = False 165 166 def atEnd(self): 167 return self.textCursor().atEnd() 168 169 def atStart(self): 170 return self.textCursor().atStart() 171 172 def gotoNextBlock(self): 173 cursor = self.textCursor() 174 if not cursor.atEnd(): 175 cursor.movePosition(QTextCursor.NextBlock) 176 self.setTextCursor(cursor) 177 178 def gotoNextInputPosition(self): 179 cursor = self.textCursor() 180 if not cursor.atEnd(): 181 cursor.movePosition(QTextCursor.NextBlock) 182 while not cursor.atEnd() and not self.__isInputPosition(cursor): 183 cursor.movePosition(QTextCursor.NextBlock) 184 self.setTextCursor(cursor) 185 186 def gotoNextOtherPosition(self): 187 cursor = self.textCursor() 188 if not cursor.atEnd(): 189 ff = cursor.currentFrame().frameFormat() 190 cursor.movePosition(QTextCursor.NextBlock) 191 while not cursor.atEnd() \ 192 and cursor.currentFrame().frameFormat() == ff: 193 cursor.movePosition(QTextCursor.NextBlock) 194 self.setTextCursor(cursor) 195 196 def gotoPreviousBlock(self): 197 cursor = self.textCursor() 198 if not cursor.atStart(): 199 cursor.movePosition(QTextCursor.PreviousBlock) 200 self.setTextCursor(cursor) 201 202 def gotoPreviousInputPosition(self): 203 cursor = self.textCursor() 204 if not cursor.atStart(): 205 cursor.movePosition(QTextCursor.PreviousBlock) 206 while not cursor.atStart() and not self.__isInputPosition(cursor): 207 cursor.movePosition(QTextCursor.PreviousBlock) 208 self.setTextCursor(cursor) 209 210 def gotoPreviousOtherPosition(self): 211 cursor = self.textCursor() 212 if cursor.atStart(): 213 return 214 cursor.movePosition(QTextCursor.Left) 215 cf = cursor.currentFrame() 216 while not cursor.atStart() and cursor.currentFrame() == cf: 217 cursor.movePosition(QTextCursor.Left) 218 if cursor.currentFrame() != cf: 219 cursor.movePosition(QTextCursor.Right) 220 self.setTextCursor(cursor) 221 222 def gotoRow(self,row): 223 rows = self.document().rootFrame().childFrames() 224 if row >= len(rows): 225 traceLogger.critical("invalid row %d > %d" % (row,len(rows)-1)) 226 row = len(rows) 227 cursor = QTextCursor(rows[row].lastCursorPosition()) 228 cursor.movePosition(QTextCursor.NextBlock) 229 self.setTextCursor(cursor) 230 self.ensureCursorVisible() 231 cursor = QTextCursor(rows[row].childFrames()[0]) 232 self.setTextCursor(cursor) 233 self.ensureCursorVisible() 234 235 def insertRow(self,row): 236 self.insertingFrames = True 237 document = self.document() 238 rootFrame = document.rootFrame() 239 rows = rootFrame.childFrames() 240 if row > len(rows): 241 traceLogger.critical("invalid row %d > %d" % (row,len(rows))) 242 row = len(rows) 243 if row == len(rows): 244 cursor = QTextCursor(document) 245 cursor.movePosition(QTextCursor.End) 246 elif rows: 247 cursor = QTextCursor(rows[row].firstCursorPosition()) 248 cursor.movePosition(QTextCursor.PreviousBlock) 249 cursor.insertFrame(QtReduceRowFormat()) 250 cursor.insertFrame(QtReduceInput().frameFormat) 251 position = cursor.position() 252 cursor.clearSelection() 253 cursor.setBlockFormat(QtReduceInput().blockFormat) 254 cursor.setBlockCharFormat(QtReduceInput().charFormat) 255 cursor.movePosition(QTextCursor.NextBlock) 256 cursor.insertFrame(QtReduceNoResult().frameFormat) 257 cursor.setBlockFormat(QtReduceNoResult().blockFormat) 258 cursor.setBlockCharFormat(QtReduceNoResult().charFormat) 259 cursor.insertText(QtReduceFrameView.NotEvaluated) 260 cursor.setPosition(position) 261 self.insertingFrames = False 262 263 def insertRows(self,start,end): 264 for row in range(start, end + 1): 265 self.insertRow(row) 266 267 def input(self,row): 268 rows = self.document().rootFrame().childFrames() 269 if row >= len(rows): 270 traceLogger.critical("invalid row %d > %d" % (row,len(rows)-1)) 271 row = len(rows) 272 inputFrame = rows[row].childFrames()[0] 273 cursor = QTextCursor(inputFrame) 274 cursor.setPosition(inputFrame.lastPosition(),QTextCursor.KeepAnchor) 275 command = cursor.selectedText() 276 command = command.replace(u'\u2028',u'\n') 277 command = command.replace(u'\u2029',u'\n') 278 if command != '' and not command[-1] in [';','$']: 279 command += ';' 280 return command 281 282 def currentField(self,row): 283 rows = self.document().rootFrame().childFrames() 284 if row >= len(rows): 285 traceLogger.critical("invalid row %d > %d" % (row,len(rows)-1)) 286 row = len(rows) 287 inputFrame = rows[row].childFrames()[0] 288 cursor = QTextCursor(inputFrame) 289 cursor.setPosition(inputFrame.lastPosition(),QTextCursor.KeepAnchor) 290 command = cursor.selectedText() 291 command = command.replace(u'\u2028',u'\n') 292 command = command.replace(u'\u2029',u'\n') 293 if command != '' and not command[-1] in [';','$']: 294 command += ';' 295 return command 296 297 def keyPressEvent(self,e): 298 if e.key() == Qt.Key_Tab: 299 self.gotoNextOtherPosition() 300 return 301 if e.key() == Qt.Key_Backtab: 302 self.gotoPreviousOtherPosition() 303 return 304 if self.__isReadOnlyPosition(): 305 if e.key() not in [Qt.Key_Left,Qt.Key_Right,Qt.Key_Up,Qt.Key_Down]: 306 return 307 if self.__isInputPosition(): 308 if (e.key() == Qt.Key_Return or e.key() == Qt.Key_Enter) and \ 309 not (e.modifiers() & Qt.ShiftModifier): 310 signalLogger.debug("emitting computationRequest") 311 self.computationRequest.emit(self.row()) 312 return 313 super(QtReduceTextEdit,self).keyPressEvent(e) 314 315 def paintEvent(self,e): 316 painter = QPainter(self.viewport()) 317 pen = painter.pen() 318 pen.setCosmetic(True) 319 pen.setWidth(0.0) 320 painter.setPen(pen) 321 painter.setRenderHint(QPainter.Antialiasing, False) 322 groups = self.document().rootFrame().childFrames() 323 for group in groups: 324 h = QtReduceRowFormat().leftMargin() 325 hoff = int(0.4*h) 326 self.__drawFrameBracket(painter,group,hoff, 327 QColor(qRgb(0x80,0x80,0x80)),xt=2) 328 childFrames = group.childFrames() 329 hoff = int(0.7*h) 330 self.__drawFrameBracket(painter,childFrames[0],hoff, 331 QColor(qRgb(0xb0,0x70,0x70)),xt=2) 332 self.__drawFrameBracket(painter,childFrames[1],hoff, 333 QColor(qRgb(0x70,0x70,0xb0)),xt=2) 334 painter.end() 335 super(QtReduceFrameView,self).paintEvent(e) 336 337 def pruneSelection(self): 338 cursor = self.textCursor() 339 if not cursor.hasSelection(): 340 return 341 if cursor.hasComplexSelection(): 342 cursor.clearSelection() 343 self.setTextCursor(cursor) 344 return 345 s = cursor.selectionStart() 346 e = cursor.selectionEnd() 347 sp = self.__positionPair(s) 348 ep = self.__positionPair(e) 349 traceLogger.debug("start=%d in %s, end=%d in %s" % (s,sp,e,ep)) 350 if sp == ep: 351 return 352 c = cursor.position() 353 cp = self.__positionPair(c) 354 traceLogger.debug("cursor=%d in %s" % (c,cp)) 355 cursor.clearSelection() 356 self.setTextCursor(cursor) 357 return 358 359 def rowOrNextRow(self,cursor=None): 360 if not cursor: 361 cursor = self.textCursor() 362 row = self.row(cursor) 363 if row >= 0: 364 return row 365 if cursor.atEnd(): 366 return -1 367 cursor.movePosition(QTextCursor.Right) 368 row = self.row(cursor) 369 if row >= 0: 370 return row 371 traceLogger.critical("unexpected negative row index") 372 373 def rowOrPreviousRow(self,cursor=None): 374 if not cursor: 375 cursor = self.textCursor() 376 row = self.row(cursor) 377 if row >= 0: 378 return row 379 if cursor.atStart(): 380 return -1 381 cursor.movePosition(QTextCursor.Left) 382 row = self.row(cursor) 383 if row >= 0: 384 return row 385 traceLogger.critical("unexpected negative row index") 386 387 def removeRows(self,start,end): 388 document = self.document() 389 rootFrame = document.rootFrame() 390 rows = rootFrame.childFrames() 391 if end >= len(rows): 392 traceLogger.critical("invalid row %d >= %d" % (end,len(rows))) 393 cursor = rows[start].firstCursorPosition() 394 cursor.setPosition(rows[end].lastPosition()+1,QTextCursor.KeepAnchor) 395 cursor.deleteChar() 396 397 def row(self,cursor=None): 398 if not cursor: 399 cursor = self.textCursor() 400 rootFrame = self.document().rootFrame() 401 frames = rootFrame.childFrames() 402 frame = cursor.currentFrame() 403 if frame == rootFrame: 404 return -1 405 p = frame.parentFrame() 406 if p != rootFrame: 407 frame = p 408 return frames.index(frame) 409 410 def rowCount(self): 411 return len(self.document().rootFrame().childFrames()) 412 413 def setError(self,row,text): 414 self.__setOutput(row,text,QtReduceError()) 415 416 def setCell(self,row,c1,input,c2,output,c3): 417 rows = self.document().rootFrame().childFrames() 418 if row >= len(rows): 419 traceLogger.critical("invalid row %d > %d" % (row,len(rows)-1)) 420 return 421 cell = rows[row] 422 rowFrames = cell.childFrames() 423 if len(rowFrames) != 2: 424 traceLogger.critical("%d subframes in row %d", len(rowFrames), row) 425 return 426 inputFrame = rowFrames[0] 427 outputFrame = rowFrames[1] 428 # C1: 429 cursor = cell.firstCursorPosition() 430 cursor.setPosition(inputFrame.firstPosition(),QTextCursor.KeepAnchor) 431 cursor.movePosition(QTextCursor.Left,QTextCursor.KeepAnchor) 432 cursor.insertText(c1) 433 # Input: 434 cursor.setPosition(inputFrame.firstPosition()) 435 cursor.setPosition(inputFrame.lastPosition(),QTextCursor.KeepAnchor) 436 cursor.setBlockFormat(QtReduceInput().blockFormat) 437 #cursor.insertText(input,QtReduceInput().charFormat) 438 cursor.insertText(input) 439 # C2: 440 cursor.setPosition(inputFrame.lastPosition()) 441 cursor.movePosition(QTextCursor.Right) 442 cursor.setPosition(outputFrame.firstPosition(),QTextCursor.KeepAnchor) 443 cursor.movePosition(QTextCursor.Left,QTextCursor.KeepAnchor) 444 cursor.insertText(c2) 445 # Output: 446 cursor.setPosition(outputFrame.firstPosition()) 447 cursor.setPosition(outputFrame.lastPosition(),QTextCursor.KeepAnchor) 448 # ... 449 # C3 450 cursor.setPosition(outputFrame.lastPosition()) 451 cursor.movePosition(QTextCursor.Right) 452 cursor.setPosition(cell.lastPosition(),QTextCursor.KeepAnchor) 453 cursor.insertText(c3) 454 455 def setInput(self,row,text): 456 rows = self.document().rootFrame().childFrames() 457 if row >= len(rows): 458 traceLogger.critical("invalid row %d > %d" % (row,len(rows)-1)) 459 return 460 rowFrames = rows[row].childFrames() 461 if len(rowFrames) != 2: 462 traceLogger.critical("%d subframes in row %d", len(rowFrames), row) 463 return 464 #text = text.rstrip(';') 465 inputFrame = rowFrames[0] 466 cursor = inputFrame.firstCursorPosition() 467 cursor.setPosition(inputFrame.lastPosition(),QTextCursor.KeepAnchor) 468 cursor.setBlockFormat(QtReduceInput().blockFormat) 469 cursor.insertText(text,QtReduceInput().charFormat) 470 471 def setNoResult(self,row): 472 self.__setOutput(row,QtReduceFrameView.Evaluated,QtReduceNoResult()) 473 474 def setAborted(self,row): 475 self.__setOutput(row,QtReduceFrameView.Aborted,QtReduceError()) 476 477 def setNotEvaluated(self,row): 478 self.__setOutput(row,self.tr(QtReduceFrameView.NotEvaluated),QtReduceNoResult()) 479 480 def setResult(self,row,text): 481 self.__setOutput(row,text,QtReduceResult()) 482 483 def subCell(self): 484 rootFrame = self.document().rootFrame() 485 rows = rootFrame.childFrames() 486 cursor = self.textCursor() 487 pos = cursor.position() 488 frame = cursor.currentFrame() 489 if frame == rootFrame: 490 # pos is outside any group 491 return SubCell(-1,pos,pos,SubCell.Root,'') 492 p = frame.parentFrame() 493 if p != rootFrame: 494 # frame is an input or output frame containing pos 495 row = rows.index(p) 496 i = p.childFrames().index(frame) 497 if i == 0: 498 typ = SubCell.Input 499 elif i == 1: 500 typ = SubCell.Output 501 else: 502 traceLogger.critical("bad subframe %d" % i) 503 startPos = frame.firstPosition() 504 endPos = frame.lastPosition() 505 else: 506 # frame is a group frame containing pos in a comment position 507 row = rows.index(frame) 508 localFrames = frame.childFrames() 509 inputStart = localFrames[0].firstPosition() 510 if pos < inputStart: 511 typ = SubCell.C1 512 startPos = frame.firstPosition() 513 endPos = inputStart-1 514 else: 515 inputEnd = localFrames[0].lastPosition() 516 outputStart = localFrames[1].firstPosition() 517 if inputEnd < pos and pos < outputStart: 518 typ = SubCell.C2 519 startPos = inputEnd+1 520 endPos = outputStart-1 521 else: 522 outputEnd = localFrames[1].lastPosition() 523 if pos <= outputEnd: 524 traceLogger.critical("pos could not be identified %d" % 525 pos) 526 typ = SubCell.C3 527 startPos = outputEnd+1 528 endPos = frame.lastPosition() 529 cursor.setPosition(startPos) 530 cursor.setPosition(endPos,QTextCursor.KeepAnchor) 531 content = cursor.selection().toPlainText() 532 return SubCell(row,startPos,endPos,typ,content) 533 534 def __drawFrameBracket(self,painter,frame,hoff,color,xt=0,width=2): 535 pen = painter.pen() 536 pen.setColor(color) 537 painter.setPen(pen) 538 top = self.cursorRect(frame.firstCursorPosition()).top() 539 bot = self.cursorRect(frame.lastCursorPosition()).bottom() + 1 540 top -= xt 541 bot += xt 542 painter.drawLine(hoff,top,hoff+width,top) 543 painter.drawLine(hoff,top,hoff,bot) 544 painter.drawLine(hoff,bot,hoff+width,bot) 545 546 def __isInputPosition(self,cursor=None): 547 if not cursor: 548 cursor = self.textCursor() 549 if cursor.block().blockFormat() == QtReduceInput().blockFormat: 550 return True 551 else: 552 return False 553 554 def __isOutputPosition(self,cursor=None): 555 if not cursor: 556 cursor = self.textCursor() 557 if cursor.block().blockFormat() in \ 558 [QtReduceResult().blockFormat, QtReduceNoResult().blockFormat, 559 QtReduceError().blockFormat]: 560 return True 561 return False 562 563 def __isReadOnlyPosition(self,cursor=None): 564 if self.__isOutputPosition(cursor) or self.__isRootPosition(cursor): 565 return True 566 return False 567 568 def __isRootPosition(self,cursor=None): 569 if not cursor: 570 cursor = self.textCursor() 571 if cursor.currentFrame() == self.document().rootFrame(): 572 return True 573 return False 574 575 def __positionPair(self,pos): 576 cursor = QTextCursor(self.document()) 577 cursor.setPosition(pos) 578 rootFrame = self.document().rootFrame() 579 frames = rootFrame.childFrames() 580 frame = cursor.currentFrame() 581 if frame == rootFrame: 582 # pos is outside any group 583 return [pos,pos] 584 p = frame.parentFrame() 585 if p != rootFrame: 586 # frame is an input or output frame containing pos 587 return [frame.firstPosition(),frame.lastPosition()] 588 # frame is a group frame containing pos in a comment position 589 localFrames = frame.childFrames() 590 inputStart = localFrames[0].firstPosition() 591 if pos < inputStart: 592 return [frame.firstPosition(),inputStart-1] 593 inputEnd = localFrames[0].lastPosition() 594 outputStart = localFrames[1].firstPosition() 595 if inputEnd < pos and pos < outputStart: 596 return [inputEnd+1,outputStart-1] 597 outputEnd = localFrames[1].lastPosition() 598 if outputEnd < pos: 599 return [outputEnd+1,frame.lastPosition()] 600 traceLogger.critical("bad position %d (%d %d) (%d %d)" % 601 (pos, 602 ifr.firstPosition(), ifr.lastPosition(), 603 ofr.firstPosition(), ofr.lastPosition())) 604 return [-1,-1] 605 606 def __setOutput(self,row,text,reduceBlockFormat): 607 rows = self.document().rootFrame().childFrames() 608 if row >= len(rows): 609 traceLogger.critical("invalid row %d > %d" % (row,len(rows)-1)) 610 return 611 rowFrames = rows[row].childFrames() 612 if len(rowFrames) != 2: 613 traceLogger.critical("%d subframes in row %d", len(rowFrames), row) 614 return 615 outputFrame = rowFrames[1] 616 cursor = outputFrame.firstCursorPosition() 617 cursor.setPosition(outputFrame.lastPosition(),QTextCursor.KeepAnchor) 618 cursor.setBlockFormat(reduceBlockFormat.blockFormat) 619 traceLogger.warning("text=%s" % text) 620 cursor.insertText(text.decode('utf-8'),reduceBlockFormat.charFormat) 621# cursor.insertText(text,reduceBlockFormat.charFormat) 622 623 624class SubCell(object): 625 Root = 0 626 C1 = 1 627 Input = 2 628 C2 = 3 629 Output = 4 630 C3 = 5 631 632 def __init__(self,row,startPos,endPos,typ,content): 633 self.row = row 634 self.startPos = startPos 635 self.endPos = endPos 636 self.type = typ 637 self.content = content 638 639 def __repr__(self): 640 return str([self.row,[self.startPos,self.endPos], 641 self.type,self.content]) 642