eric7/Preferences/ConfigurationDialog.py

branch
eric7
changeset 8312
800c432b34c8
parent 8265
0090cfa83159
child 8314
e3642a6a1e71
equal deleted inserted replaced
8311:4e8b98454baa 8312:800c432b34c8
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2002 - 2021 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing a dialog for the configuration of eric.
8 """
9
10 import contextlib
11 import enum
12 import os
13 import types
14
15 from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt, QMetaObject, QRect
16 from PyQt5.QtGui import QPixmap
17 from PyQt5.QtWidgets import (
18 QSizePolicy, QSpacerItem, QWidget, QTreeWidget, QStackedWidget, QDialog,
19 QSplitter, QScrollArea, QApplication, QDialogButtonBox, QFrame,
20 QVBoxLayout, QTreeWidgetItem, QLabel, QAbstractScrollArea
21 )
22
23 from E5Gui.E5Application import e5App
24 from E5Gui.E5LineEdit import E5ClearableLineEdit
25 from E5Gui import E5MessageBox
26 from E5Gui.E5MainWindow import E5MainWindow
27
28 from Globals import isMacPlatform, getWebBrowserSupport
29
30 import Preferences
31
32 import UI.PixmapCache
33
34 from eric6config import getConfig
35
36
37 class ConfigurationPageItem(QTreeWidgetItem):
38 """
39 Class implementing a QTreeWidgetItem holding the configuration page data.
40 """
41 def __init__(self, parent, text, pageName, iconFile):
42 """
43 Constructor
44
45 @param parent parent widget of the item (QTreeWidget or
46 QTreeWidgetItem)
47 @param text text to be displayed (string)
48 @param pageName name of the configuration page (string)
49 @param iconFile file name of the icon to be shown (string)
50 """
51 super().__init__(parent, [text])
52 self.setIcon(0, UI.PixmapCache.getIcon(iconFile))
53
54 self.__pageName = pageName
55
56 def getPageName(self):
57 """
58 Public method to get the name of the associated configuration page.
59
60 @return name of the configuration page (string)
61 """
62 return self.__pageName
63
64
65 class ConfigurationMode(enum.Enum):
66 """
67 Class defining the various modes of the configuration widget.
68 """
69 DEFAULTMODE = 0
70 TRAYSTARTERMODE = 1
71 HEXEDITORMODE = 2
72 WEBBROWSERMODE = 3
73
74
75 class ConfigurationWidget(QWidget):
76 """
77 Class implementing a dialog for the configuration of eric.
78
79 @signal preferencesChanged() emitted after settings have been changed
80 @signal masterPasswordChanged(str, str) emitted after the master
81 password has been changed with the old and the new password
82 @signal accepted() emitted to indicate acceptance of the changes
83 @signal rejected() emitted to indicate rejection of the changes
84 """
85 preferencesChanged = pyqtSignal()
86 masterPasswordChanged = pyqtSignal(str, str)
87 accepted = pyqtSignal()
88 rejected = pyqtSignal()
89
90 def __init__(self, parent=None, fromEric=True,
91 displayMode=ConfigurationMode.DEFAULTMODE,
92 expandedEntries=None):
93 """
94 Constructor
95
96 @param parent reference to the parent widget
97 @type QWidget
98 @param fromEric flag indicating a dialog generation from within the
99 eric IDE
100 @type bool
101 @param displayMode mode of the configuration dialog
102 @type ConfigurationMode
103 @param expandedEntries list of entries to be shown expanded
104 @type list of str
105 """
106 super().__init__(parent)
107
108 self.fromEric = fromEric
109 self.displayMode = displayMode
110 self.__webEngine = getWebBrowserSupport() == "QtWebEngine"
111 expandedEntries = [] if expandedEntries is None else expandedEntries[:]
112
113 self.__setupUi()
114
115 self.itmDict = {}
116
117 if not fromEric:
118 from PluginManager.PluginManager import PluginManager
119 try:
120 self.pluginManager = e5App().getObject("PluginManager")
121 except KeyError:
122 self.pluginManager = PluginManager(self)
123 e5App().registerObject("PluginManager", self.pluginManager)
124
125 from VirtualEnv.VirtualenvManager import VirtualenvManager
126 try:
127 self.virtualenvManager = e5App().getObject("VirtualEnvManager")
128 except KeyError:
129 self.virtualenvManager = VirtualenvManager(self)
130 e5App().registerObject("VirtualEnvManager",
131 self.virtualenvManager)
132
133 if displayMode == ConfigurationMode.DEFAULTMODE:
134 self.configItems = {
135 # key : [display string, pixmap name, dialog module name or
136 # page creation function, parent key,
137 # reference to configuration page (must always be last)]
138 # The dialog module must have the module function 'create' to
139 # create the configuration page. This must have the method
140 # 'save' to save the settings.
141 "applicationPage":
142 [self.tr("Application"), "preferences-application",
143 "ApplicationPage", None, None],
144 "condaPage":
145 [self.tr("Conda"), "miniconda",
146 "CondaPage", None, None],
147 "cooperationPage":
148 [self.tr("Cooperation"), "preferences-cooperation",
149 "CooperationPage", None, None],
150 "corbaPage":
151 [self.tr("CORBA"), "preferences-orbit",
152 "CorbaPage", None, None],
153 "diffPage":
154 [self.tr("Diff"), "diffFiles",
155 "DiffColoursPage", None, None],
156 "emailPage":
157 [self.tr("Email"), "preferences-mail_generic",
158 "EmailPage", None, None],
159 "graphicsPage":
160 [self.tr("Graphics"), "preferences-graphics",
161 "GraphicsPage", None, None],
162 "hexEditorPage":
163 [self.tr("Hex Editor"), "hexEditor",
164 "HexEditorPage", None, None],
165 "iconsPage":
166 [self.tr("Icons"), "preferences-icons",
167 "IconsPage", None, None],
168 "ircPage":
169 [self.tr("IRC"), "irc",
170 "IrcPage", None, None],
171 "logViewerPage":
172 [self.tr("Log-Viewer"), "preferences-logviewer",
173 "LogViewerPage", None, None],
174 "microPythonPage":
175 [self.tr("MicroPython"), "micropython",
176 "MicroPythonPage", None, None],
177 "mimeTypesPage":
178 [self.tr("Mimetypes"), "preferences-mimetypes",
179 "MimeTypesPage", None, None],
180 "networkPage":
181 [self.tr("Network"), "preferences-network",
182 "NetworkPage", None, None],
183 "notificationsPage":
184 [self.tr("Notifications"),
185 "preferences-notifications",
186 "NotificationsPage", None, None],
187 "pipPage":
188 [self.tr("Python Package Management"), "pypi",
189 "PipPage", None, None],
190 "pluginManagerPage":
191 [self.tr("Plugin Manager"),
192 "preferences-pluginmanager",
193 "PluginManagerPage", None, None],
194 "printerPage":
195 [self.tr("Printer"), "preferences-printer",
196 "PrinterPage", None, None],
197 "protobufPage":
198 [self.tr("Protobuf"), "protobuf",
199 "ProtobufPage", None, None],
200 "pythonPage":
201 [self.tr("Python"), "preferences-python",
202 "PythonPage", None, None],
203 "qtPage":
204 [self.tr("Qt"), "preferences-qtlogo",
205 "QtPage", None, None],
206 "securityPage":
207 [self.tr("Security"), "preferences-security",
208 "SecurityPage", None, None],
209 "shellPage":
210 [self.tr("Shell"), "preferences-shell",
211 "ShellPage", None, None],
212 "tasksPage":
213 [self.tr("Tasks"), "task",
214 "TasksPage", None, None],
215 "templatesPage":
216 [self.tr("Templates"), "preferences-template",
217 "TemplatesPage", None, None],
218 "trayStarterPage":
219 [self.tr("Tray Starter"), "erict",
220 "TrayStarterPage", None, None],
221 "vcsPage":
222 [self.tr("Version Control Systems"),
223 "preferences-vcs",
224 "VcsPage", None, None],
225
226 "0debuggerPage":
227 [self.tr("Debugger"), "preferences-debugger",
228 None, None, None],
229 "debuggerGeneralPage":
230 [self.tr("General"), "preferences-debugger",
231 "DebuggerGeneralPage", "0debuggerPage", None],
232 "debuggerPython3Page":
233 [self.tr("Python3"), "preferences-pyDebugger",
234 "DebuggerPython3Page", "0debuggerPage", None],
235
236 "0editorPage":
237 [self.tr("Editor"), "preferences-editor",
238 None, None, None],
239 "editorAPIsPage":
240 [self.tr("APIs"), "preferences-api",
241 "EditorAPIsPage", "0editorPage", None],
242 "editorAutocompletionPage":
243 [self.tr("Autocompletion"),
244 "preferences-autocompletion",
245 "EditorAutocompletionPage", "0editorPage", None],
246 "editorAutocompletionQScintillaPage":
247 [self.tr("QScintilla"), "qscintilla",
248 "EditorAutocompletionQScintillaPage",
249 "editorAutocompletionPage", None],
250 "editorCalltipsPage":
251 [self.tr("Calltips"), "preferences-calltips",
252 "EditorCalltipsPage", "0editorPage", None],
253 "editorCalltipsQScintillaPage":
254 [self.tr("QScintilla"), "qscintilla",
255 "EditorCalltipsQScintillaPage", "editorCalltipsPage", None],
256 "editorDocViewerPage":
257 [self.tr("Documentation Viewer"), "codeDocuViewer",
258 "EditorDocViewerPage", "0editorPage", None],
259 "editorGeneralPage":
260 [self.tr("General"), "preferences-general",
261 "EditorGeneralPage", "0editorPage", None],
262 "editorFilePage":
263 [self.tr("Filehandling"),
264 "preferences-filehandling",
265 "EditorFilePage", "0editorPage", None],
266 "editorSearchPage":
267 [self.tr("Searching"), "preferences-search",
268 "EditorSearchPage", "0editorPage", None],
269 "editorSpellCheckingPage":
270 [self.tr("Spell checking"),
271 "preferences-spellchecking",
272 "EditorSpellCheckingPage", "0editorPage", None],
273 "editorStylesPage":
274 [self.tr("Style"), "preferences-styles",
275 "EditorStylesPage", "0editorPage", None],
276 "editorSyntaxPage":
277 [self.tr("Code Checkers"), "preferences-debugger",
278 "EditorSyntaxPage", "0editorPage", None],
279 "editorTypingPage":
280 [self.tr("Typing"), "preferences-typing",
281 "EditorTypingPage", "0editorPage", None],
282 "editorExportersPage":
283 [self.tr("Exporters"), "preferences-exporters",
284 "EditorExportersPage", "0editorPage", None],
285
286 "1editorLexerPage":
287 [self.tr("Highlighters"),
288 "preferences-highlighting-styles",
289 None, "0editorPage", None],
290 "editorHighlightersPage":
291 [self.tr("Filetype Associations"),
292 "preferences-highlighter-association",
293 "EditorHighlightersPage", "1editorLexerPage", None],
294 "editorHighlightingStylesPage":
295 [self.tr("Styles"),
296 "preferences-highlighting-styles",
297 "EditorHighlightingStylesPage", "1editorLexerPage", None],
298 "editorKeywordsPage":
299 [self.tr("Keywords"), "preferences-keywords",
300 "EditorKeywordsPage", "1editorLexerPage", None],
301 "editorPropertiesPage":
302 [self.tr("Properties"), "preferences-properties",
303 "EditorPropertiesPage", "1editorLexerPage", None],
304
305 "1editorMouseClickHandlers":
306 [self.tr("Mouse Click Handlers"),
307 "preferences-mouse-click-handler",
308 "EditorMouseClickHandlerPage", "0editorPage", None],
309
310 "0helpPage":
311 [self.tr("Help"), "preferences-help",
312 None, None, None],
313 "helpDocumentationPage":
314 [self.tr("Help Documentation"),
315 "preferences-helpdocumentation",
316 "HelpDocumentationPage", "0helpPage", None],
317 "helpViewersPage":
318 [self.tr("Help Viewers"),
319 "preferences-helpviewers",
320 "HelpViewersPage", "0helpPage", None],
321
322 "0projectPage":
323 [self.tr("Project"), "preferences-project",
324 None, None, None],
325 "projectBrowserPage":
326 [self.tr("Project Viewer"), "preferences-project",
327 "ProjectBrowserPage", "0projectPage", None],
328 "projectPage":
329 [self.tr("Project"), "preferences-project",
330 "ProjectPage", "0projectPage", None],
331 "multiProjectPage":
332 [self.tr("Multiproject"),
333 "preferences-multiproject",
334 "MultiProjectPage", "0projectPage", None],
335
336 "0interfacePage":
337 [self.tr("Interface"), "preferences-interface",
338 None, None, None],
339 "interfacePage":
340 [self.tr("Interface"), "preferences-interface",
341 "InterfacePage", "0interfacePage", None],
342 "viewmanagerPage":
343 [self.tr("Viewmanager"), "preferences-viewmanager",
344 "ViewmanagerPage", "0interfacePage", None],
345 }
346 if self.__webEngine:
347 self.configItems.update({
348 "0webBrowserPage":
349 [self.tr("Web Browser"), "ericWeb",
350 None, None, None],
351 "webBrowserAppearancePage":
352 [self.tr("Appearance"), "preferences-styles",
353 "WebBrowserAppearancePage", "0webBrowserPage", None],
354 "webBrowserPage":
355 [self.tr("eric Web Browser"), "ericWeb",
356 "WebBrowserPage", "0webBrowserPage", None],
357 "webBrowserVirusTotalPage":
358 [self.tr("VirusTotal Interface"), "virustotal",
359 "WebBrowserVirusTotalPage", "0webBrowserPage", None],
360 "webBrowserSpellCheckingPage":
361 [self.tr("Spell checking"),
362 "preferences-spellchecking",
363 "WebBrowserSpellCheckingPage", "0webBrowserPage",
364 None],
365 })
366
367 self.configItems.update(
368 e5App().getObject("PluginManager").getPluginConfigData())
369
370 elif displayMode == ConfigurationMode.WEBBROWSERMODE:
371 self.configItems = {
372 # key : [display string, pixmap name, dialog module name or
373 # page creation function, parent key,
374 # reference to configuration page (must always be last)]
375 # The dialog module must have the module function 'create' to
376 # create the configuration page. This must have the method
377 # 'save' to save the settings.
378 "interfacePage":
379 [self.tr("Interface"), "preferences-interface",
380 "WebBrowserInterfacePage", None, None],
381 "networkPage":
382 [self.tr("Network"), "preferences-network",
383 "NetworkPage", None, None],
384 "printerPage":
385 [self.tr("Printer"), "preferences-printer",
386 "PrinterPage", None, None],
387 "securityPage":
388 [self.tr("Security"), "preferences-security",
389 "SecurityPage", None, None],
390
391 "helpDocumentationPage":
392 [self.tr("Help Documentation"),
393 "preferences-helpdocumentation",
394 "HelpDocumentationPage", None, None],
395
396 "webBrowserAppearancePage":
397 [self.tr("Appearance"), "preferences-styles",
398 "WebBrowserAppearancePage", None, None],
399 "webBrowserPage":
400 [self.tr("eric Web Browser"), "ericWeb",
401 "WebBrowserPage", None, None],
402
403 "webBrowserVirusTotalPage":
404 [self.tr("VirusTotal Interface"), "virustotal",
405 "WebBrowserVirusTotalPage", None, None],
406
407 "webBrowserSpellCheckingPage":
408 [self.tr("Spell checking"),
409 "preferences-spellchecking",
410 "WebBrowserSpellCheckingPage", None, None],
411 }
412
413 elif displayMode == ConfigurationMode.TRAYSTARTERMODE:
414 self.configItems = {
415 # key : [display string, pixmap name, dialog module name or
416 # page creation function, parent key,
417 # reference to configuration page (must always be last)]
418 # The dialog module must have the module function 'create' to
419 # create the configuration page. This must have the method
420 # 'save' to save the settings.
421 "trayStarterPage":
422 [self.tr("Tray Starter"), "erict",
423 "TrayStarterPage", None, None],
424 }
425
426 elif displayMode == ConfigurationMode.HEXEDITORMODE:
427 self.configItems = {
428 # key : [display string, pixmap name, dialog module name or
429 # page creation function, parent key,
430 # reference to configuration page (must always be last)]
431 # The dialog module must have the module function 'create' to
432 # create the configuration page. This must have the method
433 # 'save' to save the settings.
434 "hexEditorPage":
435 [self.tr("Hex Editor"), "hexEditor",
436 "HexEditorPage", None, None],
437 }
438
439 # generate the list entries
440 self.__expandedEntries = []
441 for key in sorted(self.configItems.keys()):
442 pageData = self.configItems[key]
443 if pageData[3]:
444 if pageData[3] in self.itmDict:
445 pitm = self.itmDict[pageData[3]] # get the parent item
446 else:
447 continue
448 else:
449 pitm = self.configList
450 self.itmDict[key] = ConfigurationPageItem(pitm, pageData[0], key,
451 pageData[1])
452 self.itmDict[key].setData(0, Qt.ItemDataRole.UserRole, key)
453 if (
454 not self.fromEric or
455 displayMode != ConfigurationMode.DEFAULTMODE or
456 key in expandedEntries
457 ):
458 self.itmDict[key].setExpanded(True)
459 self.configList.sortByColumn(0, Qt.SortOrder.AscendingOrder)
460
461 # set the initial size of the splitter
462 self.configSplitter.setSizes([200, 600])
463 self.configSplitter.splitterMoved.connect(self.__resizeConfigStack)
464
465 self.configList.itemActivated.connect(self.__showConfigurationPage)
466 self.configList.itemClicked.connect(self.__showConfigurationPage)
467 self.buttonBox.accepted.connect(self.accept)
468 self.buttonBox.rejected.connect(self.rejected)
469
470 if displayMode in [ConfigurationMode.TRAYSTARTERMODE,
471 ConfigurationMode.HEXEDITORMODE,
472 ConfigurationMode.WEBBROWSERMODE]:
473 self.configListSearch.hide()
474
475 if displayMode not in [ConfigurationMode.TRAYSTARTERMODE,
476 ConfigurationMode.HEXEDITORMODE]:
477 self.__initLexers()
478
479 def accept(self):
480 """
481 Public slot to accept the buttonBox accept signal.
482 """
483 if not isMacPlatform():
484 wdg = self.focusWidget()
485 if wdg == self.configList:
486 return
487
488 self.accepted.emit()
489
490 def __setupUi(self):
491 """
492 Private method to perform the general setup of the configuration
493 widget.
494 """
495 self.setObjectName("ConfigurationDialog")
496 self.resize(900, 750)
497 self.verticalLayout_2 = QVBoxLayout(self)
498 self.verticalLayout_2.setSpacing(6)
499 self.verticalLayout_2.setContentsMargins(6, 6, 6, 6)
500 self.verticalLayout_2.setObjectName("verticalLayout_2")
501
502 self.configSplitter = QSplitter(self)
503 self.configSplitter.setOrientation(Qt.Orientation.Horizontal)
504 self.configSplitter.setObjectName("configSplitter")
505
506 self.configListWidget = QWidget(self.configSplitter)
507 self.leftVBoxLayout = QVBoxLayout(self.configListWidget)
508 self.leftVBoxLayout.setContentsMargins(0, 0, 0, 0)
509 self.leftVBoxLayout.setSpacing(0)
510 self.leftVBoxLayout.setObjectName("leftVBoxLayout")
511 self.configListSearch = E5ClearableLineEdit(
512 self, self.tr("Enter search text..."))
513 self.configListSearch.setObjectName("configListSearch")
514 self.leftVBoxLayout.addWidget(self.configListSearch)
515 self.configList = QTreeWidget()
516 self.configList.setObjectName("configList")
517 self.leftVBoxLayout.addWidget(self.configList)
518 self.configListSearch.textChanged.connect(self.__searchTextChanged)
519
520 self.scrollArea = QScrollArea(self.configSplitter)
521 self.scrollArea.setFrameShape(QFrame.Shape.NoFrame)
522 self.scrollArea.setVerticalScrollBarPolicy(
523 Qt.ScrollBarPolicy.ScrollBarAlwaysOn)
524 self.scrollArea.setHorizontalScrollBarPolicy(
525 Qt.ScrollBarPolicy.ScrollBarAlwaysOn)
526 self.scrollArea.setWidgetResizable(False)
527 self.scrollArea.setSizeAdjustPolicy(
528 QAbstractScrollArea.SizeAdjustPolicy.AdjustToContents)
529 self.scrollArea.setObjectName("scrollArea")
530
531 self.configStack = QStackedWidget()
532 self.configStack.setFrameShape(QFrame.Shape.Box)
533 self.configStack.setFrameShadow(QFrame.Shadow.Sunken)
534 self.configStack.setObjectName("configStack")
535 self.scrollArea.setWidget(self.configStack)
536
537 self.emptyPage = QWidget()
538 self.emptyPage.setGeometry(QRect(0, 0, 372, 591))
539 self.emptyPage.setObjectName("emptyPage")
540 self.vboxlayout = QVBoxLayout(self.emptyPage)
541 self.vboxlayout.setSpacing(6)
542 self.vboxlayout.setContentsMargins(6, 6, 6, 6)
543 self.vboxlayout.setObjectName("vboxlayout")
544 spacerItem = QSpacerItem(
545 20, 20, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
546 self.vboxlayout.addItem(spacerItem)
547 self.emptyPagePixmap = QLabel(self.emptyPage)
548 self.emptyPagePixmap.setAlignment(Qt.AlignmentFlag.AlignCenter)
549 self.emptyPagePixmap.setObjectName("emptyPagePixmap")
550 self.emptyPagePixmap.setPixmap(
551 QPixmap(os.path.join(getConfig('ericPixDir'), 'eric.png')))
552 self.vboxlayout.addWidget(self.emptyPagePixmap)
553 self.textLabel1 = QLabel(self.emptyPage)
554 self.textLabel1.setAlignment(Qt.AlignmentFlag.AlignCenter)
555 self.textLabel1.setObjectName("textLabel1")
556 self.vboxlayout.addWidget(self.textLabel1)
557 spacerItem1 = QSpacerItem(
558 20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
559 self.vboxlayout.addItem(spacerItem1)
560 self.configStack.addWidget(self.emptyPage)
561
562 self.verticalLayout_2.addWidget(self.configSplitter)
563
564 self.buttonBox = QDialogButtonBox(self)
565 self.buttonBox.setOrientation(Qt.Orientation.Horizontal)
566 self.buttonBox.setStandardButtons(
567 QDialogButtonBox.StandardButton.Apply |
568 QDialogButtonBox.StandardButton.Cancel |
569 QDialogButtonBox.StandardButton.Ok |
570 QDialogButtonBox.StandardButton.Reset
571 )
572 self.buttonBox.setObjectName("buttonBox")
573 if (
574 not self.fromEric and
575 self.displayMode == ConfigurationMode.DEFAULTMODE
576 ):
577 self.buttonBox.button(QDialogButtonBox.StandardButton.Apply).hide()
578 self.buttonBox.button(
579 QDialogButtonBox.StandardButton.Apply).setEnabled(False)
580 self.buttonBox.button(
581 QDialogButtonBox.StandardButton.Reset).setEnabled(False)
582 self.verticalLayout_2.addWidget(self.buttonBox)
583
584 self.setWindowTitle(self.tr("Preferences"))
585
586 self.configList.header().hide()
587 self.configList.header().setSortIndicator(
588 0, Qt.SortOrder.AscendingOrder)
589 self.configList.setSortingEnabled(True)
590 self.textLabel1.setText(
591 self.tr("Please select an entry of the list \n"
592 "to display the configuration page."))
593
594 QMetaObject.connectSlotsByName(self)
595 self.setTabOrder(self.configList, self.configStack)
596
597 self.configStack.setCurrentWidget(self.emptyPage)
598
599 self.configList.setFocus()
600
601 def __searchTextChanged(self, text):
602 """
603 Private slot to handle a change of the search text.
604
605 @param text text to search for (string)
606 """
607 self.__searchChildItems(self.configList.invisibleRootItem(), text)
608
609 def __searchChildItems(self, parent, text):
610 """
611 Private method to enable child items based on a search string.
612
613 @param parent reference to the parent item (QTreeWidgetItem)
614 @param text text to search for (string)
615 @return flag indicating an enabled child item (boolean)
616 """
617 childEnabled = False
618 text = text.lower()
619 for index in range(parent.childCount()):
620 itm = parent.child(index)
621 enable = (
622 (self.__searchChildItems(itm, text) or
623 text == "" or
624 text in itm.text(0).lower())
625 if itm.childCount() > 0 else
626 (text == "" or text in itm.text(0).lower())
627 )
628 if enable:
629 childEnabled = True
630 itm.setDisabled(not enable)
631
632 return childEnabled
633
634 def __initLexers(self):
635 """
636 Private method to initialize the dictionary of preferences lexers.
637 """
638 import QScintilla.Lexers
639 from .PreferencesLexer import (
640 PreferencesLexer, PreferencesLexerLanguageError
641 )
642
643 self.lexers = {}
644 for language in QScintilla.Lexers.getSupportedLanguages():
645 if language not in self.lexers:
646 with contextlib.suppress(PreferencesLexerLanguageError):
647 self.lexers[language] = PreferencesLexer(language, self)
648
649 def __importConfigurationPage(self, name):
650 """
651 Private method to import a configuration page module.
652
653 @param name name of the configuration page module (string)
654 @return reference to the configuration page module
655 """
656 modName = "Preferences.ConfigurationPages.{0}".format(name)
657 try:
658 mod = __import__(modName)
659 components = modName.split('.')
660 for comp in components[1:]:
661 mod = getattr(mod, comp)
662 return mod
663 except ImportError:
664 E5MessageBox.critical(
665 self,
666 self.tr("Configuration Page Error"),
667 self.tr("""<p>The configuration page <b>{0}</b>"""
668 """ could not be loaded.</p>""").format(name))
669 return None
670
671 def __showConfigurationPage(self, itm, column):
672 """
673 Private slot to show a selected configuration page.
674
675 @param itm reference to the selected item (QTreeWidgetItem)
676 @param column column that was selected (integer) (ignored)
677 """
678 pageName = itm.getPageName()
679 self.showConfigurationPageByName(pageName, setCurrent=False)
680
681 def __initPage(self, pageData):
682 """
683 Private method to initialize a configuration page.
684
685 @param pageData data structure for the page to initialize
686 @return reference to the initialized page
687 """
688 page = None
689 if isinstance(pageData[2], types.FunctionType):
690 page = pageData[2](self)
691 else:
692 mod = self.__importConfigurationPage(pageData[2])
693 if mod:
694 page = mod.create(self)
695 if page is not None:
696 self.configStack.addWidget(page)
697 pageData[-1] = page
698 with contextlib.suppress(AttributeError):
699 page.setMode(self.displayMode)
700 return page
701
702 def showConfigurationPageByName(self, pageName, setCurrent=True):
703 """
704 Public slot to show a named configuration page.
705
706 @param pageName name of the configuration page to show (string)
707 @param setCurrent flag indicating to set the current item (boolean)
708 """
709 if pageName == "empty" or pageName not in self.configItems:
710 page = self.emptyPage
711 else:
712 pageData = self.configItems[pageName]
713 if pageData[-1] is None and pageData[2] is not None:
714 # the page was not loaded yet, create it
715 page = self.__initPage(pageData)
716 else:
717 page = pageData[-1]
718 if page is None:
719 page = self.emptyPage
720 elif setCurrent:
721 items = self.configList.findItems(
722 pageData[0],
723 Qt.MatchFlag.MatchFixedString |
724 Qt.MatchFlag.MatchRecursive)
725 for item in items:
726 if item.data(0, Qt.ItemDataRole.UserRole) == pageName:
727 self.configList.setCurrentItem(item)
728 self.configStack.setCurrentWidget(page)
729 self.__resizeConfigStack()
730
731 if page != self.emptyPage:
732 page.polishPage()
733 self.buttonBox.button(
734 QDialogButtonBox.StandardButton.Apply).setEnabled(True)
735 self.buttonBox.button(
736 QDialogButtonBox.StandardButton.Reset).setEnabled(True)
737 else:
738 self.buttonBox.button(
739 QDialogButtonBox.StandardButton.Apply).setEnabled(False)
740 self.buttonBox.button(
741 QDialogButtonBox.StandardButton.Reset).setEnabled(False)
742
743 # reset scrollbars
744 for sb in [self.scrollArea.horizontalScrollBar(),
745 self.scrollArea.verticalScrollBar()]:
746 if sb:
747 sb.setValue(0)
748
749 self.__currentConfigurationPageName = pageName
750
751 def resizeEvent(self, evt):
752 """
753 Protected method to handle the resizing of the widget.
754
755 @param evt reference to the event object
756 @type QResizeEvent
757 """
758 self.__resizeConfigStack()
759
760 def __resizeConfigStack(self):
761 """
762 Private method to resize the stack of configuration pages.
763 """
764 ssize = self.scrollArea.size()
765 if self.scrollArea.horizontalScrollBar():
766 ssize.setHeight(
767 ssize.height() -
768 self.scrollArea.horizontalScrollBar().height() - 2)
769 if self.scrollArea.verticalScrollBar():
770 ssize.setWidth(
771 ssize.width() -
772 self.scrollArea.verticalScrollBar().width() - 2)
773 psize = self.configStack.currentWidget().minimumSizeHint()
774 self.configStack.resize(max(ssize.width(), psize.width()),
775 max(ssize.height(), psize.height()))
776
777 def getConfigurationPageName(self):
778 """
779 Public method to get the page name of the current page.
780
781 @return page name of the current page (string)
782 """
783 return self.__currentConfigurationPageName
784
785 def calledFromEric(self):
786 """
787 Public method to check, if invoked from within eric.
788
789 @return flag indicating invocation from within eric (boolean)
790 """
791 return self.fromEric
792
793 def getPage(self, pageName):
794 """
795 Public method to get a reference to the named page.
796
797 @param pageName name of the configuration page (string)
798 @return reference to the page or None, indicating page was
799 not loaded yet
800 """
801 return self.configItems[pageName][-1]
802
803 def getLexers(self):
804 """
805 Public method to get a reference to the lexers dictionary.
806
807 @return reference to the lexers dictionary
808 """
809 return self.lexers
810
811 def setPreferences(self):
812 """
813 Public method called to store the selected values into the preferences
814 storage.
815 """
816 for pageData in self.configItems.values():
817 if pageData[-1]:
818 pageData[-1].save()
819 # page was loaded (and possibly modified)
820 QApplication.processEvents() # ensure HMI is responsive
821
822 def on_buttonBox_clicked(self, button):
823 """
824 Private slot called by a button of the button box clicked.
825
826 @param button button that was clicked (QAbstractButton)
827 """
828 if button == self.buttonBox.button(
829 QDialogButtonBox.StandardButton.Apply
830 ):
831 self.on_applyButton_clicked()
832 elif button == self.buttonBox.button(
833 QDialogButtonBox.StandardButton.Reset
834 ):
835 self.on_resetButton_clicked()
836
837 @pyqtSlot()
838 def on_applyButton_clicked(self):
839 """
840 Private slot called to apply the settings of the current page.
841 """
842 if self.configStack.currentWidget() != self.emptyPage:
843 page = self.configStack.currentWidget()
844 savedState = page.saveState()
845 page.save()
846 self.preferencesChanged.emit()
847 if savedState is not None:
848 page.setState(savedState)
849 page.polishPage()
850
851 @pyqtSlot()
852 def on_resetButton_clicked(self):
853 """
854 Private slot called to reset the settings of the current page.
855 """
856 if self.configStack.currentWidget() != self.emptyPage:
857 currentPage = self.configStack.currentWidget()
858 savedState = currentPage.saveState()
859 pageName = self.configList.currentItem().getPageName()
860 self.configStack.removeWidget(currentPage)
861 if pageName == "editorHighlightingStylesPage":
862 self.__initLexers()
863 self.configItems[pageName][-1] = None
864
865 self.showConfigurationPageByName(pageName)
866 if savedState is not None:
867 self.configStack.currentWidget().setState(savedState)
868
869 def getExpandedEntries(self):
870 """
871 Public method to get a list of expanded entries.
872
873 @return list of expanded entries (list of string)
874 """
875 return self.__expandedEntries
876
877 @pyqtSlot(QTreeWidgetItem)
878 def on_configList_itemCollapsed(self, item):
879 """
880 Private slot handling a list entry being collapsed.
881
882 @param item reference to the collapsed item (QTreeWidgetItem)
883 """
884 pageName = item.data(0, Qt.ItemDataRole.UserRole)
885 if pageName in self.__expandedEntries:
886 self.__expandedEntries.remove(pageName)
887
888 @pyqtSlot(QTreeWidgetItem)
889 def on_configList_itemExpanded(self, item):
890 """
891 Private slot handling a list entry being expanded.
892
893 @param item reference to the expanded item (QTreeWidgetItem)
894 """
895 pageName = item.data(0, Qt.ItemDataRole.UserRole)
896 if pageName not in self.__expandedEntries:
897 self.__expandedEntries.append(pageName)
898
899 def isUsingWebEngine(self):
900 """
901 Public method to get an indication, if QtWebEngine is being used.
902
903 @return flag indicating the use of QtWebEngine
904 @rtype bool
905 """
906 return (
907 self.__webEngine or
908 self.displayMode == ConfigurationMode.WEBBROWSERMODE
909 )
910
911
912 class ConfigurationDialog(QDialog):
913 """
914 Class for the dialog variant.
915
916 @signal preferencesChanged() emitted after settings have been changed
917 @signal masterPasswordChanged(str, str) emitted after the master
918 password has been changed with the old and the new password
919 """
920 preferencesChanged = pyqtSignal()
921 masterPasswordChanged = pyqtSignal(str, str)
922
923 def __init__(self, parent=None, name=None, modal=False,
924 fromEric=True,
925 displayMode=ConfigurationMode.DEFAULTMODE,
926 expandedEntries=None):
927 """
928 Constructor
929
930 @param parent reference to the parent widget
931 @type QWidget
932 @param name name of the dialog
933 @type str
934 @param modal flag indicating a modal dialog
935 @type bool
936 @param fromEric flag indicating a dialog generation from within the
937 eric IDE
938 @type bool
939 @param displayMode mode of the configuration dialog
940 @type ConfigurationMode
941 @param expandedEntries list of entries to be shown expanded
942 @type list of str
943 """
944 super().__init__(parent)
945 if name:
946 self.setObjectName(name)
947 self.setModal(modal)
948 self.setWindowFlags(Qt.WindowType.Window)
949
950 self.layout = QVBoxLayout(self)
951 self.layout.setContentsMargins(0, 0, 0, 0)
952 self.layout.setSpacing(0)
953
954 self.cw = ConfigurationWidget(self, fromEric=fromEric,
955 displayMode=displayMode,
956 expandedEntries=expandedEntries)
957 size = self.cw.size()
958 self.layout.addWidget(self.cw)
959 self.resize(size)
960 self.setWindowTitle(self.cw.windowTitle())
961
962 self.cw.accepted.connect(self.accept)
963 self.cw.rejected.connect(self.reject)
964 self.cw.preferencesChanged.connect(self.__preferencesChanged)
965 self.cw.masterPasswordChanged.connect(self.__masterPasswordChanged)
966
967 def __preferencesChanged(self):
968 """
969 Private slot to handle a change of the preferences.
970 """
971 self.preferencesChanged.emit()
972
973 def __masterPasswordChanged(self, oldPassword, newPassword):
974 """
975 Private slot to handle the change of the master password.
976
977 @param oldPassword current master password (string)
978 @param newPassword new master password (string)
979 """
980 self.masterPasswordChanged.emit(oldPassword, newPassword)
981
982 def showConfigurationPageByName(self, pageName):
983 """
984 Public slot to show a named configuration page.
985
986 @param pageName name of the configuration page to show (string)
987 """
988 self.cw.showConfigurationPageByName(pageName)
989
990 def getConfigurationPageName(self):
991 """
992 Public method to get the page name of the current page.
993
994 @return page name of the current page (string)
995 """
996 return self.cw.getConfigurationPageName()
997
998 def getExpandedEntries(self):
999 """
1000 Public method to get a list of expanded entries.
1001
1002 @return list of expanded entries (list of string)
1003 """
1004 return self.cw.getExpandedEntries()
1005
1006 def setPreferences(self):
1007 """
1008 Public method called to store the selected values into the preferences
1009 storage.
1010 """
1011 self.cw.setPreferences()
1012
1013 def accept(self):
1014 """
1015 Public method to accept the dialog.
1016 """
1017 super().accept()
1018
1019
1020 class ConfigurationWindow(E5MainWindow):
1021 """
1022 Main window class for the standalone dialog.
1023 """
1024 def __init__(self, parent=None):
1025 """
1026 Constructor
1027
1028 @param parent reference to the parent widget (QWidget)
1029 """
1030 super().__init__(parent)
1031
1032 self.cw = ConfigurationWidget(self, fromEric=False)
1033 size = self.cw.size()
1034 self.setCentralWidget(self.cw)
1035 self.resize(size)
1036 self.setWindowTitle(self.cw.windowTitle())
1037
1038 self.setStyle(Preferences.getUI("Style"),
1039 Preferences.getUI("StyleSheet"))
1040
1041 self.cw.accepted.connect(self.accept)
1042 self.cw.rejected.connect(self.close)
1043
1044 def showConfigurationPageByName(self, pageName):
1045 """
1046 Public slot to show a named configuration page.
1047
1048 @param pageName name of the configuration page to show (string)
1049 """
1050 self.cw.showConfigurationPageByName(pageName)
1051
1052 def accept(self):
1053 """
1054 Public slot called by the Ok button.
1055 """
1056 self.cw.setPreferences()
1057 Preferences.saveResetLayout()
1058 Preferences.syncPreferences()
1059 self.close()

eric ide

mercurial