eric7/Preferences/ConfigurationPages/EditorHighlightingStylesPage.py

branch
eric7
changeset 8312
800c432b34c8
parent 8259
2bbec88047dd
child 8314
e3642a6a1e71
equal deleted inserted replaced
8311:4e8b98454baa 8312:800c432b34c8
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2006 - 2021 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 PyQt5.QtCore import pyqtSlot, Qt, QFileInfo, QFile, QIODevice
13 from PyQt5.QtGui import QPalette, QFont, QColor
14 from PyQt5.QtWidgets import (
15 QColorDialog, QFontDialog, QInputDialog, QMenu, QTreeWidgetItem, QDialog
16 )
17
18 from .ConfigurationPageBase import ConfigurationPageBase
19 from .Ui_EditorHighlightingStylesPage import Ui_EditorHighlightingStylesPage
20 from ..SubstyleDefinitionDialog import SubstyleDefinitionDialog
21
22 from E5Gui import E5MessageBox, E5FileDialog
23
24 import UI.PixmapCache
25
26 try:
27 MonospacedFontsOption = QFontDialog.FontDialogOption.MonospacedFonts
28 except AttributeError:
29 MonospacedFontsOption = QFontDialog.FontDialogOptions(0x10)
30 NoFontsOption = QFontDialog.FontDialogOptions(0)
31
32
33 class EditorHighlightingStylesPage(ConfigurationPageBase,
34 Ui_EditorHighlightingStylesPage):
35 """
36 Class implementing the Editor Highlighting Styles configuration page.
37 """
38 FAMILYONLY = 0
39 SIZEONLY = 1
40 FAMILYANDSIZE = 2
41 FONT = 99
42
43 StyleRole = Qt.ItemDataRole.UserRole + 1
44 SubstyleRole = Qt.ItemDataRole.UserRole + 2
45
46 def __init__(self, lexers):
47 """
48 Constructor
49
50 @param lexers reference to the lexers dictionary
51 """
52 super().__init__()
53 self.setupUi(self)
54 self.setObjectName("EditorHighlightingStylesPage")
55
56 self.defaultSubstylesButton.setIcon(UI.PixmapCache.getIcon("editUndo"))
57 self.addSubstyleButton.setIcon(UI.PixmapCache.getIcon("plus"))
58 self.deleteSubstyleButton.setIcon(UI.PixmapCache.getIcon("minus"))
59 self.editSubstyleButton.setIcon(UI.PixmapCache.getIcon("edit"))
60 self.copySubstyleButton.setIcon(UI.PixmapCache.getIcon("editCopy"))
61
62 self.__fontButtonMenu = QMenu()
63 act = self.__fontButtonMenu.addAction(self.tr("Font"))
64 act.setData(self.FONT)
65 self.__fontButtonMenu.addSeparator()
66 act = self.__fontButtonMenu.addAction(
67 self.tr("Family and Size only"))
68 act.setData(self.FAMILYANDSIZE)
69 act = self.__fontButtonMenu.addAction(self.tr("Family only"))
70 act.setData(self.FAMILYONLY)
71 act = self.__fontButtonMenu.addAction(self.tr("Size only"))
72 act.setData(self.SIZEONLY)
73 self.__fontButtonMenu.triggered.connect(self.__fontButtonMenuTriggered)
74 self.fontButton.setMenu(self.__fontButtonMenu)
75
76 self.__allFontsButtonMenu = QMenu()
77 act = self.__allFontsButtonMenu.addAction(self.tr("Font"))
78 act.setData(self.FONT)
79 self.__allFontsButtonMenu.addSeparator()
80 act = self.__allFontsButtonMenu.addAction(
81 self.tr("Family and Size only"))
82 act.setData(self.FAMILYANDSIZE)
83 act = self.__allFontsButtonMenu.addAction(self.tr("Family only"))
84 act.setData(self.FAMILYONLY)
85 act = self.__allFontsButtonMenu.addAction(self.tr("Size only"))
86 act.setData(self.SIZEONLY)
87 self.__allFontsButtonMenu.triggered.connect(
88 self.__allFontsButtonMenuTriggered)
89 self.allFontsButton.setMenu(self.__allFontsButtonMenu)
90
91 self.lexer = None
92 self.lexers = lexers
93
94 # set initial values
95 import QScintilla.Lexers
96 languages = sorted([''] + list(self.lexers.keys()))
97 for language in languages:
98 self.lexerLanguageComboBox.addItem(
99 QScintilla.Lexers.getLanguageIcon(language, False),
100 language)
101 self.on_lexerLanguageComboBox_activated(0)
102
103 def save(self):
104 """
105 Public slot to save the Editor Highlighting Styles configuration.
106 """
107 for lexer in list(self.lexers.values()):
108 lexer.writeSettings()
109
110 @pyqtSlot(int)
111 def on_lexerLanguageComboBox_activated(self, index):
112 """
113 Private slot to fill the style combo of the source page.
114
115 @param index index of the selected entry
116 @type int
117 """
118 language = self.lexerLanguageComboBox.itemText(index)
119
120 self.styleElementList.clear()
121 self.styleGroup.setEnabled(False)
122 self.lexer = None
123
124 if not language:
125 return
126
127 try:
128 self.lexer = self.lexers[language]
129 except KeyError:
130 return
131
132 self.styleGroup.setEnabled(True)
133 for description, styleNo, subStyleNo in self.lexer.getStyles():
134 if subStyleNo >= 0:
135 parent = self.styleElementList.findItems(
136 self.lexer.description(styleNo),
137 Qt.MatchFlag.MatchExactly)[0]
138 parent.setExpanded(True)
139 else:
140 parent = self.styleElementList
141 itm = QTreeWidgetItem(parent, [description])
142 itm.setData(0, self.StyleRole, styleNo)
143 itm.setData(0, self.SubstyleRole, subStyleNo)
144 self.__styleAllItems()
145 self.styleElementList.setCurrentItem(
146 self.styleElementList.topLevelItem(0))
147
148 def __stylesForItem(self, itm):
149 """
150 Private method to get the style and sub-style number of the given item.
151
152 @param itm reference to the item to extract the styles from
153 @type QTreeWidgetItem
154 @return tuple containing the style and sub-style numbers
155 @rtype tuple of (int, int)
156 """
157 style = itm.data(0, self.StyleRole)
158 substyle = itm.data(0, self.SubstyleRole)
159
160 return (style, substyle)
161
162 def __currentStyles(self):
163 """
164 Private method to get the styles of the current item.
165
166 @return tuple containing the style and sub-style numbers
167 @rtype tuple of (int, int)
168 """
169 itm = self.styleElementList.currentItem()
170 # return default style, if no current item
171 styles = (0, -1) if itm is None else self.__stylesForItem(itm)
172
173 return styles
174
175 def __styleOneItem(self, item, style, substyle):
176 """
177 Private method to style one item of the style element list.
178
179 @param item reference to the item to be styled
180 @type QTreeWidgetItem
181 @param style base style number
182 @type int
183 @param substyle sub-style number
184 @type int
185 """
186 colour = self.lexer.color(style, substyle)
187 paper = self.lexer.paper(style, substyle)
188 font = self.lexer.font(style, substyle)
189 eolfill = self.lexer.eolFill(style, substyle)
190
191 item.setFont(0, font)
192 item.setBackground(0, paper)
193 item.setForeground(0, colour)
194 if eolfill:
195 item.setCheckState(0, Qt.CheckState.Checked)
196 else:
197 item.setCheckState(0, Qt.CheckState.Unchecked)
198
199 def __styleAllItems(self):
200 """
201 Private method to style all items of the style element list.
202 """
203 itm = self.styleElementList.topLevelItem(0)
204 while itm is not None:
205 style, substyle = self.__stylesForItem(itm)
206 self.__styleOneItem(itm, style, substyle)
207 itm = self.styleElementList.itemBelow(itm)
208
209 @pyqtSlot(QTreeWidgetItem, QTreeWidgetItem)
210 def on_styleElementList_currentItemChanged(self, current, previous):
211 """
212 Private method to handle a change of the current row.
213
214 @param current reference to the current item
215 @type QTreeWidgetItem
216 @param previous reference to the previous item
217 @type QTreeWidgetItem
218 """
219 if current is None:
220 return
221
222 style, substyle = self.__stylesForItem(current)
223 colour = self.lexer.color(style, substyle)
224 paper = self.lexer.paper(style, substyle)
225 eolfill = self.lexer.eolFill(style, substyle)
226 font = self.lexer.font(style, substyle)
227
228 self.sampleText.setFont(font)
229 pl = self.sampleText.palette()
230 pl.setColor(QPalette.ColorRole.Text, colour)
231 pl.setColor(QPalette.ColorRole.Base, paper)
232 self.sampleText.setPalette(pl)
233 self.sampleText.repaint()
234 self.eolfillCheckBox.setChecked(eolfill)
235
236 selectedOne = len(self.styleElementList.selectedItems()) == 1
237 self.defaultSubstylesButton.setEnabled(
238 selectedOne and substyle < 0 and self.lexer.isBaseStyle(style))
239 self.addSubstyleButton.setEnabled(
240 selectedOne and substyle < 0 and self.lexer.isBaseStyle(style))
241 self.deleteSubstyleButton.setEnabled(selectedOne and substyle >= 0)
242 self.editSubstyleButton.setEnabled(selectedOne and substyle >= 0)
243 self.copySubstyleButton.setEnabled(selectedOne and substyle >= 0)
244
245 @pyqtSlot()
246 def on_foregroundButton_clicked(self):
247 """
248 Private method used to select the foreground colour of the selected
249 style and lexer.
250 """
251 style, substyle = self.__currentStyles()
252 colour = QColorDialog.getColor(self.lexer.color(style, substyle))
253 if colour.isValid():
254 pl = self.sampleText.palette()
255 pl.setColor(QPalette.ColorRole.Text, colour)
256 self.sampleText.setPalette(pl)
257 self.sampleText.repaint()
258 for selItem in self.styleElementList.selectedItems():
259 style, substyle = self.__stylesForItem(selItem)
260 self.lexer.setColor(colour, style, substyle)
261 selItem.setForeground(0, colour)
262
263 @pyqtSlot()
264 def on_backgroundButton_clicked(self):
265 """
266 Private method used to select the background colour of the selected
267 style and lexer.
268 """
269 style, substyle = self.__currentStyles()
270 colour = QColorDialog.getColor(self.lexer.paper(style, substyle))
271 if colour.isValid():
272 pl = self.sampleText.palette()
273 pl.setColor(QPalette.ColorRole.Base, colour)
274 self.sampleText.setPalette(pl)
275 self.sampleText.repaint()
276 for selItem in self.styleElementList.selectedItems():
277 style, substyle = self.__stylesForItem(selItem)
278 self.lexer.setPaper(colour, style, substyle)
279 selItem.setBackground(0, colour)
280
281 @pyqtSlot()
282 def on_allBackgroundColoursButton_clicked(self):
283 """
284 Private method used to select the background colour of all styles of a
285 selected lexer.
286 """
287 style, substyle = self.__currentStyles()
288 colour = QColorDialog.getColor(self.lexer.paper(style, substyle))
289 if colour.isValid():
290 pl = self.sampleText.palette()
291 pl.setColor(QPalette.ColorRole.Base, colour)
292 self.sampleText.setPalette(pl)
293 self.sampleText.repaint()
294
295 itm = self.styleElementList.topLevelItem(0)
296 while itm is not None:
297 style, substyle = self.__stylesForItem(itm)
298 self.lexer.setPaper(colour, style, substyle)
299 itm = self.styleElementList.itemBelow(itm)
300 self.__styleAllItems()
301
302 def __changeFont(self, doAll, familyOnly, sizeOnly):
303 """
304 Private slot to change the highlighter font.
305
306 @param doAll flag indicating to change the font for all styles
307 (boolean)
308 @param familyOnly flag indicating to set the font family only (boolean)
309 @param sizeOnly flag indicating to set the font size only (boolean
310 """
311 def setFont(font, style, substyle, familyOnly, sizeOnly):
312 """
313 Local function to set the font.
314
315 @param font font to be set
316 @type QFont
317 @param style style number
318 @type int
319 @param substyle sub-style number
320 @type int
321 @param familyOnly flag indicating to set the font family only
322 @type bool
323 @param sizeOnly flag indicating to set the font size only
324 @type bool
325 """
326 if familyOnly or sizeOnly:
327 newFont = QFont(self.lexer.font(style))
328 if familyOnly:
329 newFont.setFamily(font.family())
330 if sizeOnly:
331 newFont.setPointSize(font.pointSize())
332 self.lexer.setFont(newFont, style, substyle)
333 else:
334 self.lexer.setFont(font, style, substyle)
335
336 def setSampleFont(font, familyOnly, sizeOnly):
337 """
338 Local function to set the font of the sample text.
339
340 @param font font to be set (QFont)
341 @param familyOnly flag indicating to set the font family only
342 (boolean)
343 @param sizeOnly flag indicating to set the font size only (boolean
344 """
345 if familyOnly or sizeOnly:
346 style, substyle = self.__currentStyles()
347 newFont = QFont(self.lexer.font(style, substyle))
348 if familyOnly:
349 newFont.setFamily(font.family())
350 if sizeOnly:
351 newFont.setPointSize(font.pointSize())
352 self.sampleText.setFont(newFont)
353 else:
354 self.sampleText.setFont(font)
355
356 style, substyle = self.__currentStyles()
357 options = (
358 MonospacedFontsOption
359 if self.monospacedButton.isChecked() else
360 NoFontsOption
361 )
362 font, ok = QFontDialog.getFont(self.lexer.font(style, substyle), self,
363 "", options)
364 if ok:
365 setSampleFont(font, familyOnly, sizeOnly)
366 if doAll:
367 itm = self.styleElementList.topLevelItem(0)
368 while itm is not None:
369 style, substyle = self.__stylesForItem(itm)
370 setFont(font, style, substyle, familyOnly, sizeOnly)
371 itm = self.styleElementList.itemBelow(itm)
372 self.__styleAllItems()
373 else:
374 for selItem in self.styleElementList.selectedItems():
375 style, substyle = self.__stylesForItem(selItem)
376 setFont(font, style, substyle, familyOnly, sizeOnly)
377 itmFont = self.lexer.font(style, substyle)
378 selItem.setFont(0, itmFont)
379
380 def __fontButtonMenuTriggered(self, act):
381 """
382 Private slot used to select the font of the selected style and lexer.
383
384 @param act reference to the triggering action (QAction)
385 """
386 if act is None:
387 return
388
389 familyOnly = act.data() in [self.FAMILYANDSIZE, self.FAMILYONLY]
390 sizeOnly = act.data() in [self.FAMILYANDSIZE, self.SIZEONLY]
391 self.__changeFont(False, familyOnly, sizeOnly)
392
393 def __allFontsButtonMenuTriggered(self, act):
394 """
395 Private slot used to change the font of all styles of a selected lexer.
396
397 @param act reference to the triggering action (QAction)
398 """
399 if act is None:
400 return
401
402 familyOnly = act.data() in [self.FAMILYANDSIZE, self.FAMILYONLY]
403 sizeOnly = act.data() in [self.FAMILYANDSIZE, self.SIZEONLY]
404 self.__changeFont(True, familyOnly, sizeOnly)
405
406 @pyqtSlot(bool)
407 def on_eolfillCheckBox_clicked(self, on):
408 """
409 Private method used to set the eolfill for the selected style and
410 lexer.
411
412 @param on flag indicating enabled or disabled state (boolean)
413 """
414 style, substyle = self.__currentStyles()
415 checkState = Qt.CheckState.Checked if on else Qt.CheckState.Unchecked
416 for selItem in self.styleElementList.selectedItems():
417 style, substyle = self.__stylesForItem(selItem)
418 self.lexer.setEolFill(on, style, substyle)
419 selItem.setCheckState(0, checkState)
420
421 @pyqtSlot()
422 def on_allEolFillButton_clicked(self):
423 """
424 Private method used to set the eolfill for all styles of a selected
425 lexer.
426 """
427 on = self.tr("Enabled")
428 off = self.tr("Disabled")
429 selection, ok = QInputDialog.getItem(
430 self,
431 self.tr("Fill to end of line"),
432 self.tr("Select fill to end of line for all styles"),
433 [on, off],
434 0, False)
435 if ok:
436 enabled = selection == on
437 self.eolfillCheckBox.setChecked(enabled)
438
439 itm = self.styleElementList.topLevelItem(0)
440 while itm is not None:
441 style, substyle = self.__stylesForItem(itm)
442 self.lexer.setEolFill(enabled, style, substyle)
443 itm = self.styleElementList.itemBelow(itm)
444 self.__styleAllItems()
445
446 @pyqtSlot()
447 def on_defaultButton_clicked(self):
448 """
449 Private method to set the current style to its default values.
450 """
451 for selItem in self.styleElementList.selectedItems():
452 style, substyle = self.__stylesForItem(selItem)
453 self.__setToDefault(style, substyle)
454 self.on_styleElementList_currentItemChanged(
455 self.styleElementList.currentItem(), None)
456 self.__styleAllItems()
457
458 @pyqtSlot()
459 def on_allDefaultButton_clicked(self):
460 """
461 Private method to set all styles to their default values.
462 """
463 itm = self.styleElementList.topLevelItem(0)
464 while itm is not None:
465 style, substyle = self.__stylesForItem(itm)
466 self.__setToDefault(style, substyle)
467 itm = self.styleElementList.itemBelow(itm)
468 self.on_styleElementList_currentItemChanged(
469 self.styleElementList.currentItem(), None)
470 self.__styleAllItems()
471
472 def __setToDefault(self, style, substyle):
473 """
474 Private method to set a specific style to its default values.
475
476 @param style style number
477 @type int
478 @param substyle sub-style number
479 @type int
480 """
481 self.lexer.setColor(self.lexer.defaultColor(style, substyle),
482 style, substyle)
483 self.lexer.setPaper(self.lexer.defaultPaper(style, substyle),
484 style, substyle)
485 self.lexer.setFont(self.lexer.defaultFont(style, substyle),
486 style, substyle)
487 self.lexer.setEolFill(self.lexer.defaultEolFill(style, substyle),
488 style, substyle)
489
490 #######################################################################
491 ## Importing and exporting of styles
492 #######################################################################
493
494 @pyqtSlot()
495 def on_importButton_clicked(self):
496 """
497 Private slot to import styles to be selected.
498 """
499 self.__importStyles(importAll=False)
500
501 @pyqtSlot()
502 def on_exportButton_clicked(self):
503 """
504 Private slot to export styles to be selected.
505 """
506 self.__exportStyles(exportAll=False)
507
508 @pyqtSlot()
509 def on_importAllButton_clicked(self):
510 """
511 Private slot to import the styles of all lexers.
512 """
513 self.__importStyles(importAll=True)
514
515 @pyqtSlot()
516 def on_exportAllButton_clicked(self):
517 """
518 Private slot to export the styles of all lexers.
519 """
520 self.__exportStyles(exportAll=True)
521
522 def __exportStyles(self, exportAll=False):
523 """
524 Private method to export the styles of selectable lexers.
525
526 @param exportAll flag indicating to export all styles without asking
527 (defaults to False)
528 @type bool (optional)
529 """
530 from eric6config import getConfig
531 stylesDir = getConfig("ericStylesDir")
532
533 lexerNames = list(self.lexers.keys())
534 if not exportAll:
535 if self.lexer:
536 preselect = [self.lexer.language()]
537 else:
538 preselect = []
539 from .EditorHighlightingStylesSelectionDialog import (
540 EditorHighlightingStylesSelectionDialog)
541 dlg = EditorHighlightingStylesSelectionDialog(
542 lexerNames, forImport=False, preselect=preselect)
543 if dlg.exec() == QDialog.DialogCode.Accepted:
544 lexerNames = dlg.getLexerNames()
545 else:
546 # Cancelled by user
547 return
548
549 lexers = [self.lexers[name] for name in lexerNames]
550
551 fn, selectedFilter = E5FileDialog.getSaveFileNameAndFilter(
552 self,
553 self.tr("Export Highlighting Styles"),
554 stylesDir,
555 self.tr("Highlighting Styles File (*.ehj);;"
556 "XML Highlighting Styles File (*.e6h)"),
557 "",
558 E5FileDialog.Options(E5FileDialog.DontConfirmOverwrite))
559
560 if not fn:
561 return
562
563 ext = QFileInfo(fn).suffix()
564 if not ext:
565 ex = selectedFilter.split("(*")[1].split(")")[0]
566 if ex:
567 fn += ex
568
569 ok = (
570 E5MessageBox.yesNo(
571 self,
572 self.tr("Export Highlighting Styles"),
573 self.tr("""<p>The highlighting styles file <b>{0}</b> exists"""
574 """ already. Overwrite it?</p>""").format(fn))
575 if os.path.exists(fn) else
576 True
577 )
578
579 if ok:
580 if fn.endswith(".ehj"):
581 from Preferences.HighlightingStylesFile import (
582 HighlightingStylesFile
583 )
584 highlightingStylesFile = HighlightingStylesFile()
585 highlightingStylesFile.writeFile(fn, lexers)
586 else:
587 f = QFile(fn)
588 if f.open(QIODevice.OpenModeFlag.WriteOnly):
589 from E5XML.HighlightingStylesWriter import (
590 HighlightingStylesWriter
591 )
592 HighlightingStylesWriter(f, lexers).writeXML()
593 f.close()
594 else:
595 E5MessageBox.critical(
596 self,
597 self.tr("Export Highlighting Styles"),
598 self.tr("<p>The highlighting styles file <b>{0}</b>"
599 " could not be written.</p><p>Reason: {1}</p>")
600 .format(fn, f.errorString())
601 )
602
603 def __importStyles(self, importAll=False):
604 """
605 Private method to import the styles of lexers to be selected.
606
607 @param importAll flag indicating to import all styles without asking
608 (defaults to False)
609 @type bool (optional)
610 """
611 from eric6config import getConfig
612 stylesDir = getConfig("ericStylesDir")
613
614 fn = E5FileDialog.getOpenFileName(
615 self,
616 self.tr("Import Highlighting Styles"),
617 stylesDir,
618 self.tr("Highlighting Styles File (*.ehj);;"
619 "XML Highlighting Styles File (*.e6h *.e4h)"))
620
621 if not fn:
622 return
623
624 if fn.endswith(".ehj"):
625 # new JSON based file
626 from Preferences.HighlightingStylesFile import (
627 HighlightingStylesFile
628 )
629 highlightingStylesFile = HighlightingStylesFile()
630 styles = highlightingStylesFile.readFile(fn)
631 if not styles:
632 return
633 else:
634 # old XML based file
635 f = QFile(fn)
636 if f.open(QIODevice.OpenModeFlag.ReadOnly):
637 from E5XML.HighlightingStylesReader import (
638 HighlightingStylesReader
639 )
640 reader = HighlightingStylesReader(f, self.lexers)
641 styles = reader.readXML()
642 f.close()
643 if not styles:
644 return
645 else:
646 E5MessageBox.critical(
647 self,
648 self.tr("Import Highlighting Styles"),
649 self.tr(
650 "<p>The highlighting styles file <b>{0}</b> could not"
651 " be read.</p><p>Reason: {1}</p>"
652 ).format(fn, f.errorString())
653 )
654 return
655
656 self.__applyStyles(styles, importAll=importAll)
657 self.on_lexerLanguageComboBox_activated(
658 self.lexerLanguageComboBox.currentIndex())
659
660 def __applyStyles(self, stylesList, importAll=False):
661 """
662 Private method to apply the imported styles to this dialog.
663
664 @param stylesList list of imported lexer styles
665 @type list of dict
666 @param importAll flag indicating to import all styles without asking
667 (defaults to False)
668 @type bool (optional)
669 """
670 lexerNames = [d["name"]
671 for d in stylesList
672 if d["name"] in self.lexers]
673
674 if not importAll:
675 from .EditorHighlightingStylesSelectionDialog import (
676 EditorHighlightingStylesSelectionDialog)
677 dlg = EditorHighlightingStylesSelectionDialog(
678 lexerNames, forImport=True)
679 if dlg.exec() == QDialog.DialogCode.Accepted:
680 lexerNames = dlg.getLexerNames()
681 else:
682 # Cancelled by user
683 return
684
685 for lexerDict in stylesList:
686 if lexerDict["name"] in lexerNames:
687 lexer = self.lexers[lexerDict["name"]]
688 for styleDict in lexerDict["styles"]:
689 style = styleDict["style"]
690 substyle = styleDict["substyle"]
691 lexer.setColor(QColor(styleDict["color"]), style, substyle)
692 lexer.setPaper(QColor(styleDict["paper"]), style, substyle)
693 font = QFont()
694 font.fromString(styleDict["font"])
695 lexer.setFont(font, style, substyle)
696 lexer.setEolFill(styleDict["eolfill"], style, substyle)
697 if substyle >= 0:
698 # description and words can only be set for sub-styles
699 lexer.setDescription(styleDict["description"],
700 style, substyle)
701 lexer.setWords(styleDict["words"], style, substyle)
702
703 #######################################################################
704 ## Methods to save and restore the state
705 #######################################################################
706
707 def saveState(self):
708 """
709 Public method to save the current state of the widget.
710
711 @return list containing the index of the selected lexer language
712 and a tuple containing the index of the parent selected lexer
713 entry and the index of the selected entry
714 @rtype list of int and tuple of (int, int)
715 """
716 itm = self.styleElementList.currentItem()
717 if itm:
718 parent = itm.parent()
719 if parent is None:
720 currentData = (
721 None, self.styleElementList.indexOfTopLevelItem(itm))
722 else:
723 currentData = (
724 self.styleElementList.indexOfTopLevelItem(parent),
725 parent.indexOfChild(itm)
726 )
727
728 savedState = [
729 self.lexerLanguageComboBox.currentIndex(),
730 currentData,
731 ]
732 else:
733 savedState = []
734 return savedState
735
736 def setState(self, state):
737 """
738 Public method to set the state of the widget.
739
740 @param state state data generated by saveState
741 """
742 if state:
743 self.lexerLanguageComboBox.setCurrentIndex(state[0])
744 self.on_lexerLanguageComboBox_activated(
745 self.lexerLanguageComboBox.currentIndex())
746
747 parentIndex, index = state[1]
748 if parentIndex is None:
749 itm = self.styleElementList.topLevelItem(index)
750 else:
751 parent = self.styleElementList.topLevelItem(parentIndex)
752 itm = parent.child(index)
753 self.styleElementList.setCurrentItem(itm)
754
755 #######################################################################
756 ## Methods to add, delete and edit sub-styles and their definitions
757 #######################################################################
758
759 @pyqtSlot()
760 def on_addSubstyleButton_clicked(self):
761 """
762 Private slot to add a new sub-style.
763 """
764 style, substyle = self.__currentStyles()
765 dlg = SubstyleDefinitionDialog(
766 self.lexer, style, substyle, parent=self)
767 if dlg.exec() == QDialog.DialogCode.Accepted:
768 description, words = dlg.getData()
769 substyle = self.lexer.addSubstyle(style)
770 self.lexer.setDescription(description, style, substyle)
771 self.lexer.setWords(words, style, substyle)
772
773 parent = self.styleElementList.findItems(
774 self.lexer.description(style), Qt.MatchFlag.MatchExactly)[0]
775 parent.setExpanded(True)
776 itm = QTreeWidgetItem(parent, [description])
777 itm.setData(0, self.StyleRole, style)
778 itm.setData(0, self.SubstyleRole, substyle)
779 self.__styleOneItem(itm, style, substyle)
780
781 @pyqtSlot()
782 def on_deleteSubstyleButton_clicked(self):
783 """
784 Private slot to delete the selected sub-style.
785 """
786 style, substyle = self.__currentStyles()
787 ok = E5MessageBox.yesNo(
788 self,
789 self.tr("Delete Sub-Style"),
790 self.tr("""<p>Shall the sub-style <b>{0}</b> really be"""
791 """ deleted?</p>""").format(
792 self.lexer.description(style, substyle))
793 )
794 if ok:
795 self.lexer.delSubstyle(style, substyle)
796
797 itm = self.styleElementList.currentItem()
798 parent = itm.parent()
799 index = parent.indexOfChild(itm)
800 parent.takeChild(index)
801 del itm
802
803 @pyqtSlot()
804 def on_editSubstyleButton_clicked(self):
805 """
806 Private slot to edit the selected sub-style entry.
807 """
808 style, substyle = self.__currentStyles()
809 dlg = SubstyleDefinitionDialog(
810 self.lexer, style, substyle, parent=self)
811 if dlg.exec() == QDialog.DialogCode.Accepted:
812 description, words = dlg.getData()
813 self.lexer.setDescription(description, style, substyle)
814 self.lexer.setWords(words, style, substyle)
815
816 itm = self.styleElementList.currentItem()
817 itm.setText(0, description)
818
819 @pyqtSlot()
820 def on_copySubstyleButton_clicked(self):
821 """
822 Private slot to copy the selected sub-style.
823 """
824 style, substyle = self.__currentStyles()
825 newSubstyle = self.lexer.addSubstyle(style)
826
827 description = self.tr("{0} - Copy").format(
828 self.lexer.description(style, substyle))
829 self.lexer.setDescription(description, style, newSubstyle)
830 self.lexer.setWords(self.lexer.words(style, substyle),
831 style, newSubstyle)
832 self.lexer.setColor(self.lexer.color(style, substyle),
833 style, newSubstyle)
834 self.lexer.setPaper(self.lexer.paper(style, substyle),
835 style, newSubstyle)
836 self.lexer.setFont(self.lexer.font(style, substyle),
837 style, newSubstyle)
838 self.lexer.setEolFill(self.lexer.eolFill(style, substyle),
839 style, newSubstyle)
840
841 parent = self.styleElementList.findItems(
842 self.lexer.description(style), Qt.MatchFlag.MatchExactly)[0]
843 parent.setExpanded(True)
844 itm = QTreeWidgetItem(parent, [description])
845 itm.setData(0, self.StyleRole, style)
846 itm.setData(0, self.SubstyleRole, newSubstyle)
847 self.__styleOneItem(itm, style, newSubstyle)
848
849 @pyqtSlot()
850 def on_defaultSubstylesButton_clicked(self):
851 """
852 Private slot to reset all substyles to default values.
853 """
854 style, substyle = self.__currentStyles()
855 ok = E5MessageBox.yesNo(
856 self,
857 self.tr("Reset Sub-Styles to Default"),
858 self.tr("<p>Do you really want to reset all defined sub-styles of"
859 " <b>{0}</b> to the default values?</p>""")
860 .format(self.lexer.description(style, substyle))
861 )
862 if ok:
863 # 1. reset sub-styles
864 self.lexer.loadDefaultSubStyles(style)
865
866 # 2. delete all existing sub-style items
867 parent = self.styleElementList.currentItem()
868 while parent.childCount() > 0:
869 itm = parent.takeChild(0) # __IGNORE_WARNING__
870 del itm
871
872 # 3. create the new list of sub-style items
873 for description, _, substyle in self.lexer.getSubStyles(style):
874 itm = QTreeWidgetItem(parent, [description])
875 itm.setData(0, self.StyleRole, style)
876 itm.setData(0, self.SubstyleRole, substyle)
877 self.__styleOneItem(itm, style, substyle)
878
879
880 def create(dlg):
881 """
882 Module function to create the configuration page.
883
884 @param dlg reference to the configuration dialog
885 @return reference to the instantiated page (ConfigurationPageBase)
886 """
887 page = EditorHighlightingStylesPage(dlg.getLexers())
888 return page

eric ide

mercurial