|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2006 - 2009 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 """ |
|
7 Module implementing the Editor Highlighting Styles configuration page. |
|
8 """ |
|
9 |
|
10 import os |
|
11 |
|
12 from PyQt4.QtCore import pyqtSlot, QFileInfo |
|
13 from PyQt4.QtGui import QPalette, QFileDialog, QColorDialog, QFontDialog, \ |
|
14 QInputDialog, QMessageBox |
|
15 |
|
16 from ConfigurationPageBase import ConfigurationPageBase |
|
17 from Ui_EditorHighlightingStylesPage import Ui_EditorHighlightingStylesPage |
|
18 |
|
19 from E4XML.XMLUtilities import make_parser |
|
20 from E4XML.XMLErrorHandler import XMLErrorHandler, XMLFatalParseError |
|
21 from E4XML.XMLEntityResolver import XMLEntityResolver |
|
22 from E4XML.HighlightingStylesWriter import HighlightingStylesWriter |
|
23 from E4XML.HighlightingStylesHandler import HighlightingStylesHandler |
|
24 |
|
25 import Preferences |
|
26 |
|
27 class EditorHighlightingStylesPage(ConfigurationPageBase, |
|
28 Ui_EditorHighlightingStylesPage): |
|
29 """ |
|
30 Class implementing the Editor Highlighting Styles configuration page. |
|
31 """ |
|
32 def __init__(self, lexers): |
|
33 """ |
|
34 Constructor |
|
35 |
|
36 @param lexers reference to the lexers dictionary |
|
37 """ |
|
38 ConfigurationPageBase.__init__(self) |
|
39 self.setupUi(self) |
|
40 self.setObjectName("EditorHighlightingStylesPage") |
|
41 |
|
42 self.lexer = None |
|
43 self.lexers = lexers |
|
44 |
|
45 # set initial values |
|
46 languages = [''] + self.lexers.keys() |
|
47 languages.sort() |
|
48 self.lexerLanguageComboBox.addItems(languages) |
|
49 self.on_lexerLanguageComboBox_activated("") |
|
50 |
|
51 def save(self): |
|
52 """ |
|
53 Public slot to save the Editor Highlighting Styles configuration. |
|
54 """ |
|
55 for lexer in self.lexers.values(): |
|
56 lexer.writeSettings(Preferences.Prefs.settings, "Scintilla") |
|
57 |
|
58 @pyqtSlot(str) |
|
59 def on_lexerLanguageComboBox_activated(self, language): |
|
60 """ |
|
61 Private slot to fill the style combo of the source page. |
|
62 |
|
63 @param language The lexer language (string) |
|
64 """ |
|
65 self.styleElementList.clear() |
|
66 self.styleGroup.setEnabled(False) |
|
67 self.lexer = None |
|
68 |
|
69 self.exportCurrentButton.setEnabled(language != "") |
|
70 self.importCurrentButton.setEnabled(language != "") |
|
71 |
|
72 if not language: |
|
73 return |
|
74 |
|
75 try: |
|
76 self.lexer = self.lexers[language] |
|
77 except KeyError: |
|
78 return |
|
79 |
|
80 self.styleGroup.setEnabled(True) |
|
81 self.styleElementList.addItems(self.lexer.styles) |
|
82 self.styleElementList.setCurrentRow(0) |
|
83 |
|
84 def on_styleElementList_currentRowChanged(self, index): |
|
85 """ |
|
86 Private method to set up the style element part of the source page. |
|
87 |
|
88 @param index the style index. |
|
89 """ |
|
90 try: |
|
91 self.style = self.lexer.ind2style[index] |
|
92 except KeyError: |
|
93 return |
|
94 |
|
95 colour = self.lexer.color(self.style) |
|
96 paper = self.lexer.paper(self.style) |
|
97 eolfill = self.lexer.eolFill(self.style) |
|
98 font = self.lexer.font(self.style) |
|
99 |
|
100 self.sampleText.setFont(font) |
|
101 pl = self.sampleText.palette() |
|
102 pl.setColor(QPalette.Text, colour) |
|
103 pl.setColor(QPalette.Base, paper) |
|
104 self.sampleText.setPalette(pl) |
|
105 self.sampleText.repaint() |
|
106 self.eolfillCheckBox.setChecked(eolfill) |
|
107 |
|
108 @pyqtSlot() |
|
109 def on_foregroundButton_clicked(self): |
|
110 """ |
|
111 Private method used to select the foreground colour of the selected style |
|
112 and lexer. |
|
113 """ |
|
114 colour = QColorDialog.getColor(self.lexer.color(self.style)) |
|
115 if colour.isValid(): |
|
116 pl = self.sampleText.palette() |
|
117 pl.setColor(QPalette.Text, colour) |
|
118 self.sampleText.setPalette(pl) |
|
119 self.sampleText.repaint() |
|
120 if len(self.styleElementList.selectedItems()) > 1: |
|
121 for selItem in self.styleElementList.selectedItems(): |
|
122 style = self.lexer.ind2style[self.styleElementList.row(selItem)] |
|
123 self.lexer.setColor(colour, style) |
|
124 else: |
|
125 self.lexer.setColor(colour, self.style) |
|
126 |
|
127 @pyqtSlot() |
|
128 def on_backgroundButton_clicked(self): |
|
129 """ |
|
130 Private method used to select the background colour of the selected style |
|
131 and lexer. |
|
132 """ |
|
133 colour = QColorDialog.getColor(self.lexer.paper(self.style)) |
|
134 if colour.isValid(): |
|
135 pl = self.sampleText.palette() |
|
136 pl.setColor(QPalette.Base, colour) |
|
137 self.sampleText.setPalette(pl) |
|
138 self.sampleText.repaint() |
|
139 if len(self.styleElementList.selectedItems()) > 1: |
|
140 for selItem in self.styleElementList.selectedItems(): |
|
141 style = self.lexer.ind2style[self.styleElementList.row(selItem)] |
|
142 self.lexer.setPaper(colour, style) |
|
143 else: |
|
144 self.lexer.setPaper(colour, self.style) |
|
145 |
|
146 @pyqtSlot() |
|
147 def on_allBackgroundColoursButton_clicked(self): |
|
148 """ |
|
149 Private method used to select the background colour of all styles of a |
|
150 selected lexer. |
|
151 """ |
|
152 colour = QColorDialog.getColor(self.lexer.paper(self.style)) |
|
153 if colour.isValid(): |
|
154 pl = self.sampleText.palette() |
|
155 pl.setColor(QPalette.Base, colour) |
|
156 self.sampleText.setPalette(pl) |
|
157 self.sampleText.repaint() |
|
158 for style in self.lexer.ind2style.values(): |
|
159 self.lexer.setPaper(colour, style) |
|
160 |
|
161 @pyqtSlot() |
|
162 def on_fontButton_clicked(self): |
|
163 """ |
|
164 Private method used to select the font of the selected style and lexer. |
|
165 """ |
|
166 font, ok = QFontDialog.getFont(self.lexer.font(self.style)) |
|
167 if ok: |
|
168 self.sampleText.setFont(font) |
|
169 if len(self.styleElementList.selectedItems()) > 1: |
|
170 for selItem in self.styleElementList.selectedItems(): |
|
171 style = self.lexer.ind2style[self.styleElementList.row(selItem)] |
|
172 self.lexer.setFont(font, style) |
|
173 else: |
|
174 self.lexer.setFont(font, self.style) |
|
175 |
|
176 @pyqtSlot() |
|
177 def on_allFontsButton_clicked(self): |
|
178 """ |
|
179 Private method used to change the font of all styles of a selected lexer. |
|
180 """ |
|
181 font, ok = QFontDialog.getFont(self.lexer.font(self.style)) |
|
182 if ok: |
|
183 self.sampleText.setFont(font) |
|
184 for style in self.lexer.ind2style.values(): |
|
185 self.lexer.setFont(font, style) |
|
186 |
|
187 def on_eolfillCheckBox_toggled(self, b): |
|
188 """ |
|
189 Private method used to set the eolfill for the selected style and lexer. |
|
190 |
|
191 @param b Flag indicating enabled or disabled state. |
|
192 """ |
|
193 self.lexer.setEolFill(b, self.style) |
|
194 |
|
195 @pyqtSlot() |
|
196 def on_allEolFillButton_clicked(self): |
|
197 """ |
|
198 Private method used to set the eolfill for all styles of a selected lexer. |
|
199 """ |
|
200 on = self.trUtf8("Enabled") |
|
201 off = self.trUtf8("Disabled") |
|
202 selection, ok = QInputDialog.getItem(\ |
|
203 self, |
|
204 self.trUtf8("Fill to end of line"), |
|
205 self.trUtf8("Select fill to end of line for all styles"), |
|
206 [on, off], |
|
207 0, False) |
|
208 if ok: |
|
209 enabled = selection == on |
|
210 self.eolfillCheckBox.setChecked(enabled) |
|
211 for style in self.lexer.ind2style.values(): |
|
212 self.lexer.setEolFill(enabled, style) |
|
213 |
|
214 @pyqtSlot() |
|
215 def on_defaultButton_clicked(self): |
|
216 """ |
|
217 Private method to set the current style to it's default values. |
|
218 """ |
|
219 if len(self.styleElementList.selectedItems()) > 1: |
|
220 for selItem in self.styleElementList.selectedItems(): |
|
221 style = self.lexer.ind2style[self.styleElementList.row(selItem)] |
|
222 self.__setToDefault(style) |
|
223 else: |
|
224 self.__setToDefault(self.style) |
|
225 self.on_styleElementList_currentRowChanged(self.styleElementList.currentRow()) |
|
226 |
|
227 @pyqtSlot() |
|
228 def on_allDefaultButton_clicked(self): |
|
229 """ |
|
230 Private method to set all styles to their default values. |
|
231 """ |
|
232 for style in self.lexer.ind2style.values(): |
|
233 self.__setToDefault(style) |
|
234 self.on_styleElementList_currentRowChanged(self.styleElementList.currentRow()) |
|
235 |
|
236 def __setToDefault(self, style): |
|
237 """ |
|
238 Private method to set a specific style to it's default values. |
|
239 |
|
240 @param style style to be reset (integer) |
|
241 """ |
|
242 self.lexer.setColor(self.lexer.defaultColor(style), style) |
|
243 self.lexer.setPaper(self.lexer.defaultPaper(style), style) |
|
244 self.lexer.setFont(self.lexer.defaultFont(style), style) |
|
245 self.lexer.setEolFill(self.lexer.defaultEolFill(style), style) |
|
246 |
|
247 @pyqtSlot() |
|
248 def on_importCurrentButton_clicked(self): |
|
249 """ |
|
250 Private slot to import the styles of the current lexer. |
|
251 """ |
|
252 self.__importStyles({self.lexer.language() : self.lexer}) |
|
253 |
|
254 @pyqtSlot() |
|
255 def on_exportCurrentButton_clicked(self): |
|
256 """ |
|
257 Private slot to export the styles of the current lexer. |
|
258 """ |
|
259 self.__exportStyles([self.lexer]) |
|
260 |
|
261 @pyqtSlot() |
|
262 def on_importAllButton_clicked(self): |
|
263 """ |
|
264 Private slot to import the styles of all lexers. |
|
265 """ |
|
266 self.__importStyles(self.lexers) |
|
267 |
|
268 @pyqtSlot() |
|
269 def on_exportAllButton_clicked(self): |
|
270 """ |
|
271 Private slot to export the styles of all lexers. |
|
272 """ |
|
273 self.__exportStyles(self.lexers.values()) |
|
274 |
|
275 def __exportStyles(self, lexers): |
|
276 """ |
|
277 Private method to export the styles of the given lexers. |
|
278 |
|
279 @param lexers list of lexer objects for which to export the styles |
|
280 """ |
|
281 fn, selectedFilter = QFileDialog.getSaveFileNameAndFilter(\ |
|
282 self, |
|
283 self.trUtf8("Export Highlighting Styles"), |
|
284 "", |
|
285 self.trUtf8("eric4 highlighting styles file (*.e4h)"), |
|
286 "", |
|
287 QFileDialog.Options(QFileDialog.DontConfirmOverwrite)) |
|
288 |
|
289 if not fn: |
|
290 return |
|
291 |
|
292 ext = QFileInfo(fn).suffix() |
|
293 if not ext: |
|
294 ex = selectedFilter.split("(*")[1].split(")")[0] |
|
295 if ex: |
|
296 fn += ex |
|
297 |
|
298 try: |
|
299 f = open(fn, "wb") |
|
300 HighlightingStylesWriter(f, lexers).writeXML() |
|
301 f.close() |
|
302 except IOError, err: |
|
303 QMessageBox.critical(self, |
|
304 self.trUtf8("Export Highlighting Styles"), |
|
305 self.trUtf8("""<p>The highlighting styles could not be exported""" |
|
306 """ to file <b>{0}</b>.</p><p>Reason: {1}</p>""")\ |
|
307 .format(fn, unicode(err)) |
|
308 ) |
|
309 |
|
310 def __importStyles(self, lexers): |
|
311 """ |
|
312 Private method to import the styles of the given lexers. |
|
313 |
|
314 @param lexers dictionary of lexer objects for which to import the styles |
|
315 """ |
|
316 fn = QFileDialog.getOpenFileName(\ |
|
317 self, |
|
318 self.trUtf8("Import Highlighting Styles"), |
|
319 "", |
|
320 self.trUtf8("eric4 highlighting styles file (*.e4h)")) |
|
321 |
|
322 if not fn: |
|
323 return |
|
324 |
|
325 try: |
|
326 f = open(fn, "rb") |
|
327 try: |
|
328 line = f.readline() |
|
329 dtdLine = f.readline() |
|
330 finally: |
|
331 f.close() |
|
332 except IOError, err: |
|
333 QMessageBox.critical(self, |
|
334 self.trUtf8("Import Highlighting Styles"), |
|
335 self.trUtf8("""<p>The highlighting styles could not be read""" |
|
336 """ from file <b>{0}</b>.</p><p>Reason: {1}</p>""")\ |
|
337 .format(fn, unicode(err)) |
|
338 ) |
|
339 return |
|
340 |
|
341 validating = dtdLine.startswith("<!DOCTYPE") |
|
342 parser = make_parser(validating) |
|
343 handler = HighlightingStylesHandler(lexers) |
|
344 er = XMLEntityResolver() |
|
345 eh = XMLErrorHandler() |
|
346 |
|
347 parser.setContentHandler(handler) |
|
348 parser.setEntityResolver(er) |
|
349 parser.setErrorHandler(eh) |
|
350 |
|
351 try: |
|
352 f = open(fn, "rb") |
|
353 try: |
|
354 try: |
|
355 parser.parse(f) |
|
356 except UnicodeEncodeError: |
|
357 f.seek(0) |
|
358 buf = cStringIO.StringIO(f.read()) |
|
359 parser.parse(buf) |
|
360 finally: |
|
361 f.close() |
|
362 except IOError, err: |
|
363 QMessageBox.critical(self, |
|
364 self.trUtf8("Import Highlighting Styles"), |
|
365 self.trUtf8("""<p>The highlighting styles could not be read""" |
|
366 """ from file <b>{0}</b>.</p><p>Reason: {1}</p>""")\ |
|
367 .format(fn, unicode(err)) |
|
368 ) |
|
369 return |
|
370 except XMLFatalParseError: |
|
371 QMessageBox.critical(self, |
|
372 self.trUtf8("Import Highlighting Styles"), |
|
373 self.trUtf8("""<p>The highlighting styles file <b>{0}</b>""" |
|
374 """ has invalid contents.</p>""").format(fn)) |
|
375 eh.showParseMessages() |
|
376 return |
|
377 |
|
378 eh.showParseMessages() |
|
379 |
|
380 if self.lexer: |
|
381 colour = self.lexer.color(self.style) |
|
382 paper = self.lexer.paper(self.style) |
|
383 eolfill = self.lexer.eolFill(self.style) |
|
384 font = self.lexer.font(self.style) |
|
385 |
|
386 self.sampleText.setFont(font) |
|
387 pl = self.sampleText.palette() |
|
388 pl.setColor(QPalette.Text, colour) |
|
389 pl.setColor(QPalette.Base, paper) |
|
390 self.sampleText.setPalette(pl) |
|
391 self.sampleText.repaint() |
|
392 self.eolfillCheckBox.setChecked(eolfill) |
|
393 |
|
394 def saveState(self): |
|
395 """ |
|
396 Public method to save the current state of the widget. |
|
397 |
|
398 @return array containing the index of the selected lexer language (integer) |
|
399 and the index of the selected lexer entry (integer) |
|
400 """ |
|
401 savedState = [ |
|
402 self.lexerLanguageComboBox.currentIndex(), |
|
403 self.styleElementList.currentRow(), |
|
404 ] |
|
405 return savedState |
|
406 |
|
407 def setState(self, state): |
|
408 """ |
|
409 Public method to set the state of the widget. |
|
410 |
|
411 @param state state data generated by saveState |
|
412 """ |
|
413 self.lexerLanguageComboBox.setCurrentIndex(state[0]) |
|
414 self.on_lexerLanguageComboBox_activated(self.lexerLanguageComboBox.currentText()) |
|
415 self.styleElementList.setCurrentRow(state[1]) |
|
416 |
|
417 def create(dlg): |
|
418 """ |
|
419 Module function to create the configuration page. |
|
420 |
|
421 @param dlg reference to the configuration dialog |
|
422 """ |
|
423 page = EditorHighlightingStylesPage(dlg.getLexers()) |
|
424 return page |