QScintilla/Editor.py

changeset 2162
4627e6ea7b6b
parent 2084
d3f083dd0222
child 2163
2b02339f52bf
equal deleted inserted replaced
2160:1874d4410904 2162:4627e6ea7b6b
11 import difflib 11 import difflib
12 12
13 from PyQt4.QtCore import QDir, QTimer, QModelIndex, QFileInfo, pyqtSignal, \ 13 from PyQt4.QtCore import QDir, QTimer, QModelIndex, QFileInfo, pyqtSignal, \
14 pyqtSlot, QCryptographicHash, QEvent, QDateTime, QRegExp, Qt 14 pyqtSlot, QCryptographicHash, QEvent, QDateTime, QRegExp, Qt
15 from PyQt4.QtGui import QCursor, QPrinter, QPrintDialog, QLineEdit, QActionGroup, \ 15 from PyQt4.QtGui import QCursor, QPrinter, QPrintDialog, QLineEdit, QActionGroup, \
16 QDialog, QAbstractPrintDialog, QInputDialog, QApplication, QMenu, QPalette, QFont 16 QDialog, QAbstractPrintDialog, QInputDialog, QApplication, QMenu, QPalette, QFont, \
17 QPixmap
17 from PyQt4.Qsci import QsciScintilla, QsciMacro, QsciStyledText 18 from PyQt4.Qsci import QsciScintilla, QsciMacro, QsciStyledText
18 19
19 from E5Gui.E5Application import e5App 20 from E5Gui.E5Application import e5App
20 from E5Gui import E5FileDialog, E5MessageBox 21 from E5Gui import E5FileDialog, E5MessageBox
21 22
73 function has been configured 74 function has been configured
74 @signal coverageMarkersShown(bool) emitted after the coverage markers have been 75 @signal coverageMarkersShown(bool) emitted after the coverage markers have been
75 shown or cleared 76 shown or cleared
76 @signal taskMarkersUpdated(QsciScintillaCompat) emitted when the task markers 77 @signal taskMarkersUpdated(QsciScintillaCompat) emitted when the task markers
77 were updated 78 were updated
79 @signal changeMarkersUpdated(QsciScintillaCompat) emitted when the change markers
80 were updated
78 @signal showMenu(str, QMenu, QsciScintillaCompat) emitted when a menu is about 81 @signal showMenu(str, QMenu, QsciScintillaCompat) emitted when a menu is about
79 to be shown. The name of the menu, a reference to the menu and a reference 82 to be shown. The name of the menu, a reference to the menu and a reference
80 to the editor are given. 83 to the editor are given.
81 @signal languageChanged(str) emitted when the editors language was set. The 84 @signal languageChanged(str) emitted when the editors language was set. The
82 language is passed as a parameter. 85 language is passed as a parameter.
99 bookmarkToggled = pyqtSignal(QsciScintillaCompat) 102 bookmarkToggled = pyqtSignal(QsciScintillaCompat)
100 syntaxerrorToggled = pyqtSignal(QsciScintillaCompat) 103 syntaxerrorToggled = pyqtSignal(QsciScintillaCompat)
101 autoCompletionAPIsAvailable = pyqtSignal(bool) 104 autoCompletionAPIsAvailable = pyqtSignal(bool)
102 coverageMarkersShown = pyqtSignal(bool) 105 coverageMarkersShown = pyqtSignal(bool)
103 taskMarkersUpdated = pyqtSignal(QsciScintillaCompat) 106 taskMarkersUpdated = pyqtSignal(QsciScintillaCompat)
107 changeMarkersUpdated = pyqtSignal(QsciScintillaCompat)
104 showMenu = pyqtSignal(str, QMenu, QsciScintillaCompat) 108 showMenu = pyqtSignal(str, QMenu, QsciScintillaCompat)
105 languageChanged = pyqtSignal(str) 109 languageChanged = pyqtSignal(str)
106 eolChanged = pyqtSignal(str) 110 eolChanged = pyqtSignal(str)
107 encodingChanged = pyqtSignal(str) 111 encodingChanged = pyqtSignal(str)
108 lastEditPositionAvailable = pyqtSignal() 112 lastEditPositionAvailable = pyqtSignal()
242 self.__unifiedMargins = Preferences.getEditor("UnifiedMargins") 246 self.__unifiedMargins = Preferences.getEditor("UnifiedMargins")
243 else: 247 else:
244 self.__unifiedMargins = True 248 self.__unifiedMargins = True
245 249
246 # define the margins markers 250 # define the margins markers
251 changePixmap = QPixmap(16, 16)
252 changePixmap.fill(Preferences.getEditorColour("OnlineChangeTraceMarker"))
253 self.__changeMarker = self.markerDefine(changePixmap)
247 self.breakpoint = \ 254 self.breakpoint = \
248 self.markerDefine(UI.PixmapCache.getPixmap("break.png")) 255 self.markerDefine(UI.PixmapCache.getPixmap("break.png"))
249 self.cbreakpoint = \ 256 self.cbreakpoint = \
250 self.markerDefine(UI.PixmapCache.getPixmap("cBreak.png")) 257 self.markerDefine(UI.PixmapCache.getPixmap("cBreak.png"))
251 self.tbreakpoint = \ 258 self.tbreakpoint = \
411 self.__registerImages() 418 self.__registerImages()
412 419
413 # connect signals after loading the text 420 # connect signals after loading the text
414 self.textChanged.connect(self.__textChanged) 421 self.textChanged.connect(self.__textChanged)
415 422
416 # create the online syntax check timer 423 # initialize the online syntax check timer
417 self.__initOnlineSyntaxCheck() 424 self.__initOnlineSyntaxCheck()
425
426 # initialize the online change trace timer
427 self.__initOnlineChangeTrace()
418 428
419 if self.fileName and \ 429 if self.fileName and \
420 self.project.isOpen() and \ 430 self.project.isOpen() and \
421 self.project.isProjectSource(self.fileName): 431 self.project.isProjectSource(self.fileName):
422 self.project.projectPropertiesChanged.connect(self.__projectPropertiesChanged) 432 self.project.projectPropertiesChanged.connect(self.__projectPropertiesChanged)
1001 self.indicMarginMenu.addAction(self.trUtf8('Next task'), 1011 self.indicMarginMenu.addAction(self.trUtf8('Next task'),
1002 self.nextTask) 1012 self.nextTask)
1003 self.marginMenuActs["PreviousTaskMarker"] = \ 1013 self.marginMenuActs["PreviousTaskMarker"] = \
1004 self.indicMarginMenu.addAction(self.trUtf8('Previous task'), 1014 self.indicMarginMenu.addAction(self.trUtf8('Previous task'),
1005 self.previousTask) 1015 self.previousTask)
1016 self.indicMarginMenu.addSeparator()
1017 self.marginMenuActs["NextChangeMarker"] = \
1018 self.indicMarginMenu.addAction(self.trUtf8('Next change'),
1019 self.nextChange)
1020 self.marginMenuActs["PreviousChangeMarker"] = \
1021 self.indicMarginMenu.addAction(self.trUtf8('Previous change'),
1022 self.previousChange)
1006 1023
1007 self.indicMarginMenu.aboutToShow.connect(self.__showContextMenuMargin) 1024 self.indicMarginMenu.aboutToShow.connect(self.__showContextMenuMargin)
1008 1025
1009 def __initContextMenuUnifiedMargins(self): 1026 def __initContextMenuUnifiedMargins(self):
1010 """ 1027 """
1081 self.nextTask) 1098 self.nextTask)
1082 self.marginMenuActs["PreviousTaskMarker"] = \ 1099 self.marginMenuActs["PreviousTaskMarker"] = \
1083 self.marginMenu.addAction(self.trUtf8('Previous task'), 1100 self.marginMenu.addAction(self.trUtf8('Previous task'),
1084 self.previousTask) 1101 self.previousTask)
1085 self.marginMenu.addSeparator() 1102 self.marginMenu.addSeparator()
1103 self.marginMenuActs["NextChangeMarker"] = \
1104 self.marginMenu.addAction(self.trUtf8('Next change'),
1105 self.nextChange)
1106 self.marginMenuActs["PreviousChangeMarker"] = \
1107 self.marginMenu.addAction(self.trUtf8('Previous change'),
1108 self.previousChange)
1109 self.marginMenu.addSeparator()
1086 self.marginMenuActs["LMBbookmarks"] = \ 1110 self.marginMenuActs["LMBbookmarks"] = \
1087 self.marginMenu.addAction(self.trUtf8('LMB toggles bookmarks'), 1111 self.marginMenu.addAction(self.trUtf8('LMB toggles bookmarks'),
1088 self.__lmBbookmarks) 1112 self.__lmBbookmarks)
1089 self.marginMenuActs["LMBbookmarks"].setCheckable(True) 1113 self.marginMenuActs["LMBbookmarks"].setCheckable(True)
1090 self.marginMenuActs["LMBbookmarks"].setChecked(False) 1114 self.marginMenuActs["LMBbookmarks"].setChecked(False)
2360 shouldBreak = True 2384 shouldBreak = True
2361 break 2385 break
2362 if shouldBreak: 2386 if shouldBreak:
2363 break 2387 break
2364 self.taskMarkersUpdated.emit(self) 2388 self.taskMarkersUpdated.emit(self)
2389
2390 ############################################################################
2391 ## Change tracing methods below
2392 ############################################################################
2393
2394 def __initOnlineChangeTrace(self):
2395 """
2396 Private slot to initialize the online change trace.
2397 """
2398 self.__hasChangeMarkers = False
2399 self.__oldText = self.text()
2400 self.__onlineChangeTraceTimer = QTimer(self)
2401 self.__onlineChangeTraceTimer.setSingleShot(True)
2402 self.__onlineChangeTraceTimer.setInterval(
2403 Preferences.getEditor("OnlineChangeTraceInterval"))
2404 self.__onlineChangeTraceTimer.timeout.connect(
2405 self.__onlineChangeTraceTimerTimeout)
2406 self.textChanged.connect(self.__resetOnlineChangeTraceTimer)
2407
2408 def __resetOnlineChangeTraceTimer(self):
2409 """
2410 Private method to reset the online syntax check timer.
2411 """
2412 if Preferences.getEditor("OnlineChangeTrace"):
2413 self.__onlineChangeTraceTimer.stop()
2414 self.__onlineChangeTraceTimer.start()
2415
2416 def __onlineChangeTraceTimerTimeout(self):
2417 """
2418 Private slot to mark added and changed lines.
2419 """
2420 self.__deleteAllChangeMarkers()
2421
2422 oldL = self.__oldText.splitlines()
2423 newL = self.text().splitlines()
2424 matcher = difflib.SequenceMatcher(None, oldL, newL)
2425
2426 for token, i1, i2, j1, j2 in matcher.get_opcodes():
2427 if token in ["insert", "replace"]:
2428 for lineNo in range(j1, j2):
2429 self.markerAdd(lineNo, self.__changeMarker)
2430 self.__hasChangeMarkers = True
2431
2432 if self.__hasChangeMarkers:
2433 self.changeMarkersUpdated.emit(self)
2434
2435 def __resetOnlineChangeTraceInfo(self):
2436 """
2437 Private slot to reset the online change trace info.
2438 """
2439 self.__oldText = self.text()
2440 self.__deleteAllChangeMarkers()
2441
2442 def __deleteAllChangeMarkers(self):
2443 """
2444 Private slot to delete all change markers.
2445 """
2446 self.markerDeleteAll(self.__changeMarker)
2447 self.__hasChangeMarkers = False
2448 self.changeMarkersUpdated.emit(self)
2449
2450 def hasChangeMarkers(self):
2451 """
2452 Public method to determine, if this editor contains any change markers.
2453
2454 @return flag indicating the presence of change markers (boolean)
2455 """
2456 return self.__hasChangeMarkers
2457
2458 def nextChange(self):
2459 """
2460 Public slot to handle the 'Next change' context menu action.
2461 """
2462 line, index = self.getCursorPosition()
2463 if line == self.lines() - 1:
2464 line = 0
2465 else:
2466 line += 1
2467 changeline = self.markerFindNext(line, 1 << self.__changeMarker)
2468 if changeline < 0:
2469 # wrap around
2470 changeline = self.markerFindNext(0, 1 << self.__changeMarker)
2471 if changeline >= 0:
2472 self.setCursorPosition(changeline, 0)
2473 self.ensureLineVisible(changeline)
2474
2475 def previousChange(self):
2476 """
2477 Public slot to handle the 'Previous task' context menu action.
2478 """
2479 line, index = self.getCursorPosition()
2480 if line == 0:
2481 line = self.lines() - 1
2482 else:
2483 line -= 1
2484 changeline = self.markerFindPrevious(line, 1 << self.__changeMarker)
2485 if changeline < 0:
2486 # wrap around
2487 changeline = self.markerFindPrevious(
2488 self.lines() - 1, 1 << self.__changeMarker)
2489 if changeline >= 0:
2490 self.setCursorPosition(changeline, 0)
2491 self.ensureLineVisible(changeline)
2365 2492
2366 ############################################################################ 2493 ############################################################################
2367 ## Flags handling methods below 2494 ## Flags handling methods below
2368 ############################################################################ 2495 ############################################################################
2369 2496
2655 if newName is not None: 2782 if newName is not None:
2656 self.vm.addToRecentList(newName) 2783 self.vm.addToRecentList(newName)
2657 self.editorSaved.emit(self.fileName) 2784 self.editorSaved.emit(self.fileName)
2658 self.__autoSyntaxCheck() 2785 self.__autoSyntaxCheck()
2659 self.extractTasks() 2786 self.extractTasks()
2787 self.__resetOnlineChangeTraceInfo()
2660 return True 2788 return True
2661 else: 2789 else:
2662 self.lastModified = QFileInfo(fn).lastModified() 2790 self.lastModified = QFileInfo(fn).lastModified()
2663 return False 2791 return False
2664 2792
3521 self.__onlineSyntaxCheckTimer.setInterval( 3649 self.__onlineSyntaxCheckTimer.setInterval(
3522 Preferences.getEditor("OnlineSyntaxCheckInterval") * 1000) 3650 Preferences.getEditor("OnlineSyntaxCheckInterval") * 1000)
3523 else: 3651 else:
3524 self.__onlineSyntaxCheckTimer.stop() 3652 self.__onlineSyntaxCheckTimer.stop()
3525 3653
3654 if Preferences.getEditor("OnlineChangeTrace"):
3655 self.__onlineChangeTraceTimer.setInterval(
3656 Preferences.getEditor("OnlineChangeTraceInterval"))
3657 else:
3658 self.__onlineChangeTraceTimer.stop()
3659 self.__deleteAllChangeMarkers()
3660 changePixmap = QPixmap(16, 16)
3661 changePixmap.fill(Preferences.getEditorColour("OnlineChangeTraceMarker"))
3662 self.markerDefine(changePixmap, self.__changeMarker)
3663
3526 # refresh the annotations display 3664 # refresh the annotations display
3527 self.__refreshAnnotations() 3665 self.__refreshAnnotations()
3528 3666
3529 def __setLineMarkerColours(self): 3667 def __setLineMarkerColours(self):
3530 """ 3668 """
3566 (1 << self.errorline) | \ 3704 (1 << self.errorline) | \
3567 (1 << self.bookmark) | \ 3705 (1 << self.bookmark) | \
3568 (1 << self.syntaxerror) | \ 3706 (1 << self.syntaxerror) | \
3569 (1 << self.notcovered) | \ 3707 (1 << self.notcovered) | \
3570 (1 << self.taskmarker) | \ 3708 (1 << self.taskmarker) | \
3571 (1 << self.warning) 3709 (1 << self.warning) | \
3710 (1 << self.__changeMarker)
3572 self.setMarginWidth(1, 16) 3711 self.setMarginWidth(1, 16)
3573 self.setMarginSensitivity(1, True) 3712 self.setMarginSensitivity(1, True)
3574 self.setMarginMarkerMask(1, margin1Mask) 3713 self.setMarginMarkerMask(1, margin1Mask)
3575 3714
3576 self.__linenoMargin = 0 3715 self.__linenoMargin = 0
3600 self.setMarginMarkerMask(self.__bpMargin, marginBpMask) 3739 self.setMarginMarkerMask(self.__bpMargin, marginBpMask)
3601 3740
3602 marginIndicMask = (1 << self.syntaxerror) | \ 3741 marginIndicMask = (1 << self.syntaxerror) | \
3603 (1 << self.notcovered) | \ 3742 (1 << self.notcovered) | \
3604 (1 << self.taskmarker) | \ 3743 (1 << self.taskmarker) | \
3605 (1 << self.warning) 3744 (1 << self.warning) | \
3745 (1 << self.__changeMarker)
3606 self.setMarginWidth(self.__indicMargin, 16) 3746 self.setMarginWidth(self.__indicMargin, 16)
3607 self.setMarginSensitivity(self.__indicMargin, True) 3747 self.setMarginSensitivity(self.__indicMargin, True)
3608 self.setMarginMarkerMask(self.__indicMargin, marginIndicMask) 3748 self.setMarginMarkerMask(self.__indicMargin, marginIndicMask)
3609 3749
3610 # set linenumber margin settings 3750 # set linenumber margin settings
4394 self.marginMenuActs["PreviousTaskMarker"].setEnabled(True) 4534 self.marginMenuActs["PreviousTaskMarker"].setEnabled(True)
4395 self.marginMenuActs["NextTaskMarker"].setEnabled(True) 4535 self.marginMenuActs["NextTaskMarker"].setEnabled(True)
4396 else: 4536 else:
4397 self.marginMenuActs["PreviousTaskMarker"].setEnabled(False) 4537 self.marginMenuActs["PreviousTaskMarker"].setEnabled(False)
4398 self.marginMenuActs["NextTaskMarker"].setEnabled(False) 4538 self.marginMenuActs["NextTaskMarker"].setEnabled(False)
4539
4540 if self.__hasChangeMarkers:
4541 self.marginMenuActs["PreviousChangeMarker"].setEnabled(True)
4542 self.marginMenuActs["NextChangeMarker"].setEnabled(True)
4543 else:
4544 self.marginMenuActs["PreviousChangeMarker"].setEnabled(False)
4545 self.marginMenuActs["NextChangeMarker"].setEnabled(False)
4399 4546
4400 self.showMenu.emit("Margin", self.sender(), self) 4547 self.showMenu.emit("Margin", self.sender(), self)
4401 4548
4402 def __showContextMenuChecks(self): 4549 def __showContextMenuChecks(self):
4403 """ 4550 """

eric ide

mercurial