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 |
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) |