eric6/QScintilla/MiniEditor.py

changeset 7690
a59680062837
parent 7635
0cdead130a81
child 7730
20b05e846148
equal deleted inserted replaced
7689:147236d850a4 7690:a59680062837
16 QCoreApplication 16 QCoreApplication
17 ) 17 )
18 from PyQt5.QtGui import QCursor, QKeySequence, QPalette, QFont 18 from PyQt5.QtGui import QCursor, QKeySequence, QPalette, QFont
19 from PyQt5.QtWidgets import ( 19 from PyQt5.QtWidgets import (
20 QWidget, QWhatsThis, QActionGroup, QDialog, QInputDialog, QApplication, 20 QWidget, QWhatsThis, QActionGroup, QDialog, QInputDialog, QApplication,
21 QMenu, QVBoxLayout, QLabel 21 QMenu, QVBoxLayout, QHBoxLayout, QLabel
22 ) 22 )
23 from PyQt5.QtPrintSupport import QPrinter, QPrintDialog, QAbstractPrintDialog 23 from PyQt5.QtPrintSupport import QPrinter, QPrintDialog, QAbstractPrintDialog
24 from PyQt5.Qsci import QsciScintilla 24 from PyQt5.Qsci import QsciScintilla
25 25
26 from E5Gui.E5Action import E5Action, createActionGroup 26 from E5Gui.E5Action import E5Action, createActionGroup
112 class MiniEditor(E5MainWindow): 112 class MiniEditor(E5MainWindow):
113 """ 113 """
114 Class implementing a minimalistic editor for simple editing tasks. 114 Class implementing a minimalistic editor for simple editing tasks.
115 115
116 @signal editorSaved() emitted after the file has been saved 116 @signal editorSaved() emitted after the file has been saved
117 @signal languageChanged(str) emitted when the editors language was set. The
118 language is passed as a parameter.
119 @signal editorRenamed(str) emitted after the editor got a new name
120 (i.e. after a 'Save As')
121 @signal cursorLineChanged(int) emitted when the cursor line was changed
122
123 @signal refreshed() dummy signal to emulate the Editor interface
117 """ 124 """
118 editorSaved = pyqtSignal() 125 editorSaved = pyqtSignal()
126 languageChanged = pyqtSignal(str)
127 editorRenamed = pyqtSignal(str)
128 cursorLineChanged = pyqtSignal(int)
129
130 refreshed = pyqtSignal()
119 131
120 def __init__(self, filename="", filetype="", parent=None, name=None): 132 def __init__(self, filename="", filetype="", parent=None, name=None):
121 """ 133 """
122 Constructor 134 Constructor
123 135
136 148
137 self.__textEdit = MiniScintilla(self) 149 self.__textEdit = MiniScintilla(self)
138 self.__textEdit.clearSearchIndicators = self.clearSearchIndicators 150 self.__textEdit.clearSearchIndicators = self.clearSearchIndicators
139 self.__textEdit.setSearchIndicator = self.setSearchIndicator 151 self.__textEdit.setSearchIndicator = self.setSearchIndicator
140 self.__textEdit.setUtf8(True) 152 self.__textEdit.setUtf8(True)
153
154 self.getCursorPosition = self.__textEdit.getCursorPosition
155 self.text = self.__textEdit.text
156
157 self.__curFile = filename
158 self.__lastLine = 0
141 159
142 self.srHistory = { 160 self.srHistory = {
143 "search": [], 161 "search": [],
144 "replace": [] 162 "replace": []
145 } 163 }
146 from .SearchReplaceWidget import SearchReplaceWidget 164 from .SearchReplaceWidget import SearchReplaceWidget
147 self.__searchWidget = SearchReplaceWidget(False, self, self) 165 self.__searchWidget = SearchReplaceWidget(False, self, self)
148 self.__replaceWidget = SearchReplaceWidget(True, self, self) 166 self.__replaceWidget = SearchReplaceWidget(True, self, self)
149 167
168 from .EditorOutline import EditorOutlineView
169 self.__sourceOutline = EditorOutlineView(self, populate=False)
170 self.__sourceOutline.setMaximumWidth(
171 Preferences.getEditor("SourceOutlineWidth"))
172
173 hlayout = QHBoxLayout()
174 hlayout.setContentsMargins(0, 0, 0, 0)
175 hlayout.setSpacing(1)
176 hlayout.addWidget(self.__textEdit)
177 hlayout.addWidget(self.__sourceOutline)
178
150 centralWidget = QWidget() 179 centralWidget = QWidget()
151 layout = QVBoxLayout() 180 layout = QVBoxLayout()
152 layout.setContentsMargins(1, 1, 1, 1) 181 layout.setContentsMargins(1, 1, 1, 1)
153 layout.addWidget(self.__textEdit) 182 layout.addLayout(hlayout)
154 layout.addWidget(self.__searchWidget) 183 layout.addWidget(self.__searchWidget)
155 layout.addWidget(self.__replaceWidget) 184 layout.addWidget(self.__replaceWidget)
156 centralWidget.setLayout(layout) 185 centralWidget.setLayout(layout)
157 self.setCentralWidget(centralWidget) 186 self.setCentralWidget(centralWidget)
158 self.__searchWidget.hide() 187 self.__searchWidget.hide()
159 self.__replaceWidget.hide() 188 self.__replaceWidget.hide()
160 189
161 self.lexer_ = None 190 self.lexer_ = None
162 self.apiLanguage = "" 191 self.apiLanguage = ""
163 self.filetype = "" 192 self.filetype = ""
164 self.__curFile = filename
165 193
166 self.__loadEditorConfig(filename) 194 self.__loadEditorConfig(filename)
167 195
168 self.__createActions() 196 self.__createActions()
169 self.__createMenus() 197 self.__createMenus()
187 self.__markOccurrencesTimer.setInterval( 215 self.__markOccurrencesTimer.setInterval(
188 Preferences.getEditor("MarkOccurrencesTimeout")) 216 Preferences.getEditor("MarkOccurrencesTimeout"))
189 self.__markOccurrencesTimer.timeout.connect(self.__markOccurrences) 217 self.__markOccurrencesTimer.timeout.connect(self.__markOccurrences)
190 self.__markedText = "" 218 self.__markedText = ""
191 219
220 self.__changeTimer = QTimer(self)
221 self.__changeTimer.setSingleShot(True)
222 self.__changeTimer.setInterval(5 * 1000)
223 self.__textEdit.textChanged.connect(self.__resetChangeTimer)
224
192 self.__textEdit.textChanged.connect(self.__documentWasModified) 225 self.__textEdit.textChanged.connect(self.__documentWasModified)
193 self.__textEdit.modificationChanged.connect(self.__modificationChanged) 226 self.__textEdit.modificationChanged.connect(self.__modificationChanged)
194 self.__textEdit.cursorPositionChanged.connect( 227 self.__textEdit.cursorPositionChanged.connect(
195 self.__cursorPositionChanged) 228 self.__cursorPositionChanged)
196 self.__textEdit.linesChanged.connect(self.__resizeLinenoMargin) 229 self.__textEdit.linesChanged.connect(self.__resizeLinenoMargin)
209 else: 242 else:
210 self.__setCurrentFile("") 243 self.__setCurrentFile("")
211 self.encoding = self.__getEditorConfig("DefaultEncoding") 244 self.encoding = self.__getEditorConfig("DefaultEncoding")
212 245
213 self.__checkActions() 246 self.__checkActions()
247
248 self.__sourceOutline.setActive(True)
249 self.__sourceOutline.setVisible(
250 self.__sourceOutline.isSupportedLanguage(
251 self.getLanguage()
252 )
253 )
254 self.__changeTimer.timeout.connect(self.__sourceOutline.repopulate)
255 self.languageChanged.connect(self.__editorChanged)
256 self.editorRenamed.connect(self.__editorChanged)
214 257
215 def closeEvent(self, event): 258 def closeEvent(self, event):
216 """ 259 """
217 Protected method to handle the close event. 260 Protected method to handle the close event.
218 261
263 """ 306 """
264 fileName = E5FileDialog.getSaveFileName(self) 307 fileName = E5FileDialog.getSaveFileName(self)
265 if not fileName: 308 if not fileName:
266 return False 309 return False
267 310
268 return self.__saveFile(fileName) 311 result = self.__saveFile(fileName)
312
313 self.editorRenamed.emit(fileName)
314
315 return result
269 316
270 def __saveCopy(self): 317 def __saveCopy(self):
271 """ 318 """
272 Private slot to save a copy of the file with a new name. 319 Private slot to save a copy of the file with a new name.
273 """ 320 """
2529 self.__setSbFile(line + 1, pos) 2576 self.__setSbFile(line + 1, pos)
2530 2577
2531 if Preferences.getEditor("MarkOccurrencesEnabled"): 2578 if Preferences.getEditor("MarkOccurrencesEnabled"):
2532 self.__markOccurrencesTimer.stop() 2579 self.__markOccurrencesTimer.stop()
2533 self.__markOccurrencesTimer.start() 2580 self.__markOccurrencesTimer.start()
2581
2582 if self.__lastLine != line:
2583 self.cursorLineChanged.emit(line)
2584 self.__lastLine = line
2534 2585
2535 def __undo(self): 2586 def __undo(self):
2536 """ 2587 """
2537 Private method to undo the last recorded change. 2588 Private method to undo the last recorded change.
2538 """ 2589 """
2897 Private slot handling the aboutToShow signal of the languages context 2948 Private slot handling the aboutToShow signal of the languages context
2898 menu. 2949 menu.
2899 """ 2950 """
2900 if self.apiLanguage.startswith("Pygments|"): 2951 if self.apiLanguage.startswith("Pygments|"):
2901 self.pygmentsSelAct.setText( 2952 self.pygmentsSelAct.setText(
2902 self.tr("Alternatives ({0})").format(self.getLanguage())) 2953 self.tr("Alternatives ({0})").format(
2954 self.getLanguage(normalized=False)))
2903 else: 2955 else:
2904 self.pygmentsSelAct.setText(self.tr("Alternatives")) 2956 self.pygmentsSelAct.setText(self.tr("Alternatives"))
2905 2957
2906 def __selectPygmentsLexer(self): 2958 def __selectPygmentsLexer(self):
2907 """ 2959 """
2908 Private method to select a specific pygments lexer. 2960 Private method to select a specific pygments lexer.
2909 2961
2910 @return name of the selected pygments lexer (string) 2962 @return name of the selected pygments lexer
2963 @rtype str
2911 """ 2964 """
2912 from pygments.lexers import get_all_lexers 2965 from pygments.lexers import get_all_lexers
2913 lexerList = sorted(lex[0] for lex in get_all_lexers()) 2966 lexerList = sorted(lex[0] for lex in get_all_lexers())
2914 try: 2967 try:
2915 lexerSel = lexerList.index(self.getLanguage()) 2968 lexerSel = lexerList.index(
2969 self.getLanguage(normalized=False, forPygments=True))
2916 except ValueError: 2970 except ValueError:
2917 lexerSel = 0 2971 lexerSel = 0
2918 lexerName, ok = QInputDialog.getItem( 2972 lexerName, ok = QInputDialog.getItem(
2919 self, 2973 self,
2920 self.tr("Pygments Lexer"), 2974 self.tr("Pygments Lexer"),
2966 self.__textEdit.setColor( 3020 self.__textEdit.setColor(
2967 Preferences.getEditorColour("EditAreaForeground")) 3021 Preferences.getEditorColour("EditAreaForeground"))
2968 self.__textEdit.setPaper( 3022 self.__textEdit.setPaper(
2969 Preferences.getEditorColour("EditAreaBackground")) 3023 Preferences.getEditorColour("EditAreaBackground"))
2970 3024
3025 self.languageChanged.emit(self.apiLanguage)
3026
2971 def setLanguage(self, filename, initTextDisplay=True, pyname=""): 3027 def setLanguage(self, filename, initTextDisplay=True, pyname=""):
2972 """ 3028 """
2973 Public method to set a lexer language. 3029 Public method to set a lexer language.
2974 3030
2975 @param filename filename used to determine the associated lexer 3031 @param filename filename used to determine the associated lexer
2984 3040
2985 # set the text display 3041 # set the text display
2986 if initTextDisplay: 3042 if initTextDisplay:
2987 self.__setTextDisplay() 3043 self.__setTextDisplay()
2988 self.__setMargins() 3044 self.__setMargins()
3045
3046 self.languageChanged.emit(self.apiLanguage)
2989 3047
2990 def getLanguage(self): 3048 def getLanguage(self, normalized=True, forPygments=False):
2991 """ 3049 """
2992 Public method to retrieve the language of the editor. 3050 Public method to retrieve the language of the editor.
2993 3051
2994 @return language of the editor (string) 3052 @param normalized flag indicating to normalize some Pygments
3053 lexer names
3054 @type bool
3055 @param forPygments flag indicating to normalize some lexer
3056 names for Pygments
3057 @type bool
3058 @return language of the editor
3059 @rtype str
2995 """ 3060 """
2996 if ( 3061 if (
2997 self.apiLanguage == "Guessed" or 3062 self.apiLanguage == "Guessed" or
2998 self.apiLanguage.startswith("Pygments|") 3063 self.apiLanguage.startswith("Pygments|")
2999 ): 3064 ):
3000 return self.lexer_.name() 3065 lang = self.lexer_.name()
3001 else: 3066 if normalized:
3002 return self.apiLanguage 3067 # adjust some Pygments lexer names
3068 if lang in ("Python 2.x", "Python"):
3069 lang = "Python3"
3070 elif lang == "Protocol Buffer":
3071 lang = "Protocol"
3072
3073 else:
3074 lang = self.apiLanguage
3075 if forPygments:
3076 # adjust some names to Pygments lexer names
3077 if lang == "Python3":
3078 lang = "Python"
3079 elif lang == "Protocol":
3080 lang = "Protocol Buffer"
3081 return lang
3003 3082
3004 def __checkLanguage(self): 3083 def __checkLanguage(self):
3005 """ 3084 """
3006 Private method to check the selected language of the language submenu. 3085 Private method to check the selected language of the language submenu.
3007 """ 3086 """
3053 return 3132 return
3054 3133
3055 if pyname: 3134 if pyname:
3056 self.apiLanguage = "Pygments|{0}".format(pyname) 3135 self.apiLanguage = "Pygments|{0}".format(pyname)
3057 else: 3136 else:
3058 self.apiLanguage = self.lexer_.language() 3137 if language == "Protocol":
3138 self.apiLanguage = language
3139 else:
3140 # Change API language for lexer where QScintilla reports
3141 # an abbreviated name.
3142 self.apiLanguage = self.lexer_.language()
3143 if self.apiLanguage == "POV":
3144 self.apiLanguage = "Povray"
3145 elif self.apiLanguage == "PO":
3146 self.apiLanguage = "Gettext"
3059 self.__textEdit.setLexer(self.lexer_) 3147 self.__textEdit.setLexer(self.lexer_)
3060 if self.lexer_.lexer() == "container" or self.lexer_.lexer() is None: 3148 if self.lexer_.lexer() == "container" or self.lexer_.lexer() is None:
3061 self.__textEdit.SCN_STYLENEEDED.connect(self.__styleNeeded) 3149 self.__textEdit.SCN_STYLENEEDED.connect(self.__styleNeeded)
3062 3150
3063 # get the font for style 0 and set it as the default font 3151 # get the font for style 0 and set it as the default font
3493 return overrides[self.filetype][0] 3581 return overrides[self.filetype][0]
3494 elif option == "IndentWidth": 3582 elif option == "IndentWidth":
3495 return overrides[self.filetype][1] 3583 return overrides[self.filetype][1]
3496 3584
3497 return None 3585 return None
3586
3587 #######################################################################
3588 ## Methods supporting the outline view below
3589 #######################################################################
3590
3591 def __resetChangeTimer(self):
3592 """
3593 Private slot to reset the parse timer.
3594 """
3595 self.__changeTimer.stop()
3596 self.__changeTimer.start()
3597
3598 def __editorChanged(self):
3599 """
3600 Private slot handling changes of the editor language or file name.
3601 """
3602 supported = self.__sourceOutline.isSupportedLanguage(
3603 self.getLanguage())
3604
3605 self.__sourceOutline.setVisible(supported)

eric ide

mercurial