src/eric7/Preferences/ConfigurationDialog.py

Wed, 05 Apr 2023 12:05:06 +0200

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Wed, 05 Apr 2023 12:05:06 +0200
branch
eric7
changeset 9972
68ac01294544
parent 9971
773ad1f1ed22
child 10069
435cc5875135
permissions
-rw-r--r--

Corrected some code style and formatting issues.

# -*- coding: utf-8 -*-

# Copyright (c) 2002 - 2023 Detlev Offenbach <detlev@die-offenbachs.de>
#

"""
Module implementing a dialog for the configuration of eric.
"""

import contextlib
import enum
import importlib
import os
import time
import types

from PyQt6.QtCore import QMetaObject, QRect, Qt, pyqtSignal, pyqtSlot
from PyQt6.QtGui import QPixmap
from PyQt6.QtWidgets import (
    QAbstractScrollArea,
    QApplication,
    QDialog,
    QDialogButtonBox,
    QFrame,
    QLabel,
    QLineEdit,
    QScrollArea,
    QSizePolicy,
    QSpacerItem,
    QSplitter,
    QStackedWidget,
    QTreeWidget,
    QTreeWidgetItem,
    QVBoxLayout,
    QWidget,
)

from eric7 import Preferences
from eric7.EricGui import EricPixmapCache
from eric7.EricWidgets import EricMessageBox
from eric7.EricWidgets.EricApplication import ericApp
from eric7.EricWidgets.EricMainWindow import EricMainWindow
from eric7.Globals import getConfig, getWebBrowserSupport
from eric7.SystemUtilities import OSUtilities


class ConfigurationPageItem(QTreeWidgetItem):
    """
    Class implementing a QTreeWidgetItem holding the configuration page data.
    """

    def __init__(self, parent, text, pageName, iconFile):
        """
        Constructor

        @param parent parent widget of the item (QTreeWidget or
            QTreeWidgetItem)
        @param text text to be displayed (string)
        @param pageName name of the configuration page (string)
        @param iconFile file name of the icon to be shown (string)
        """
        super().__init__(parent, [text])
        self.setIcon(0, EricPixmapCache.getIcon(iconFile))

        self.__pageName = pageName

    def getPageName(self):
        """
        Public method to get the name of the associated configuration page.

        @return name of the configuration page (string)
        """
        return self.__pageName


class ConfigurationMode(enum.Enum):
    """
    Class defining the various modes of the configuration widget.
    """

    DEFAULTMODE = 0
    TRAYSTARTERMODE = 1
    HEXEDITORMODE = 2
    WEBBROWSERMODE = 3
    EDITORMODE = 4
    PDFVIEWERMODE = 5


class ConfigurationWidget(QWidget):
    """
    Class implementing a dialog for the configuration of eric.

    @signal preferencesChanged() emitted after settings have been changed
    @signal mainPasswordChanged(str, str) emitted after the main
        password has been changed with the old and the new password
    @signal accepted() emitted to indicate acceptance of the changes
    @signal rejected() emitted to indicate rejection of the changes
    """

    preferencesChanged = pyqtSignal()
    mainPasswordChanged = pyqtSignal(str, str)
    accepted = pyqtSignal()
    rejected = pyqtSignal()

    def __init__(
        self,
        parent=None,
        fromEric=True,
        displayMode=ConfigurationMode.DEFAULTMODE,
        expandedEntries=None,
    ):
        """
        Constructor

        @param parent reference to the parent widget
        @type QWidget
        @param fromEric flag indicating a dialog generation from within the
            eric IDE
        @type bool
        @param displayMode mode of the configuration dialog
        @type ConfigurationMode
        @param expandedEntries list of entries to be shown expanded
        @type list of str
        """
        super().__init__(parent)

        self.fromEric = fromEric
        self.displayMode = displayMode
        self.__webEngine = getWebBrowserSupport() == "QtWebEngine"
        expandedEntries = [] if expandedEntries is None else expandedEntries[:]

        self.__setupUi()

        self.itmDict = {}

        if not fromEric:
            from eric7.PluginManager.PluginManager import (  # __IGNORE_WARNING_I101__
                PluginManager,
            )

            try:
                self.pluginManager = ericApp().getObject("PluginManager")
            except KeyError:
                self.pluginManager = PluginManager(self)
                ericApp().registerObject("PluginManager", self.pluginManager)

            from eric7.VirtualEnv.VirtualenvManager import (  # __IGNORE_WARNING_I101__
                VirtualenvManager,
            )

            try:
                self.virtualenvManager = ericApp().getObject("VirtualEnvManager")
            except KeyError:
                self.virtualenvManager = VirtualenvManager(self)
                ericApp().registerObject("VirtualEnvManager", self.virtualenvManager)

            from eric7.PipInterface.Pip import Pip  # __IGNORE_WARNING_I101__

            try:
                self.pip = ericApp().getObject("Pip")
            except KeyError:
                self.pip = Pip(self)
                ericApp().registerObject("Pip", self.pip)

        if displayMode == ConfigurationMode.DEFAULTMODE:
            self.configItems = {
                # key : [display string, pixmap name, dialog module name or
                #        page creation function, parent key,
                #        reference to configuration page (must always be last)]
                # The dialog module must have the module function 'create' to
                # create the configuration page. This must have the method
                # 'save' to save the settings.
                "applicationPage": [
                    self.tr("Application"),
                    "preferences-application",
                    "ApplicationPage",
                    None,
                    None,
                ],
                "condaPage": [self.tr("Conda"), "miniconda", "CondaPage", None, None],
                "cooperationPage": [
                    self.tr("Cooperation"),
                    "preferences-cooperation",
                    "CooperationPage",
                    None,
                    None,
                ],
                "diffPage": [
                    self.tr("Diff"),
                    "diffFiles",
                    "DiffColoursPage",
                    None,
                    None,
                ],
                "emailPage": [
                    self.tr("Email"),
                    "preferences-mail_generic",
                    "EmailPage",
                    None,
                    None,
                ],
                "graphicsPage": [
                    self.tr("Graphics"),
                    "preferences-graphics",
                    "GraphicsPage",
                    None,
                    None,
                ],
                "hexEditorPage": [
                    self.tr("Hex Editor"),
                    "hexEditor",
                    "HexEditorPage",
                    None,
                    None,
                ],
                "iconsPage": [
                    self.tr("Icons"),
                    "preferences-icons",
                    "IconsPage",
                    None,
                    None,
                ],
                "ircPage": [self.tr("IRC"), "irc", "IrcPage", None, None],
                "logViewerPage": [
                    self.tr("Log-Viewer"),
                    "preferences-logviewer",
                    "LogViewerPage",
                    None,
                    None,
                ],
                "microPythonPage": [
                    self.tr("MicroPython"),
                    "micropython",
                    "MicroPythonPage",
                    None,
                    None,
                ],
                "mimeTypesPage": [
                    self.tr("MIME-Types"),
                    "preferences-mimetypes",
                    "MimeTypesPage",
                    None,
                    None,
                ],
                "networkPage": [
                    self.tr("Network"),
                    "preferences-network",
                    "NetworkPage",
                    None,
                    None,
                ],
                "notificationsPage": [
                    self.tr("Notifications"),
                    "preferences-notifications",
                    "NotificationsPage",
                    None,
                    None,
                ],
                "pdfViewerPage": [
                    self.tr("PDF Viewer"),
                    "ericPdf",
                    "PdfViewerPage",
                    None,
                    None,
                ],
                "pipPage": [
                    self.tr("Python Package Management"),
                    "pypi",
                    "PipPage",
                    None,
                    None,
                ],
                "pluginManagerPage": [
                    self.tr("Plugin Manager"),
                    "preferences-pluginmanager",
                    "PluginManagerPage",
                    None,
                    None,
                ],
                "printerPage": [
                    self.tr("Printer"),
                    "preferences-printer",
                    "PrinterPage",
                    None,
                    None,
                ],
                "pythonPage": [
                    self.tr("Python"),
                    "preferences-python",
                    "PythonPage",
                    None,
                    None,
                ],
                "qtPage": [self.tr("Qt"), "preferences-qtlogo", "QtPage", None, None],
                "securityPage": [
                    self.tr("Security"),
                    "preferences-security",
                    "SecurityPage",
                    None,
                    None,
                ],
                "shellPage": [
                    self.tr("Shell"),
                    "preferences-shell",
                    "ShellPage",
                    None,
                    None,
                ],
                "tasksPage": [self.tr("Tasks"), "task", "TasksPage", None, None],
                "templatesPage": [
                    self.tr("Templates"),
                    "preferences-template",
                    "TemplatesPage",
                    None,
                    None,
                ],
                "trayStarterPage": [
                    self.tr("Tray Starter"),
                    "erict",
                    "TrayStarterPage",
                    None,
                    None,
                ],
                "vcsPage": [
                    self.tr("Version Control Systems"),
                    "preferences-vcs",
                    "VcsPage",
                    None,
                    None,
                ],
                "0debuggerPage": [
                    self.tr("Debugger"),
                    "preferences-debugger",
                    None,
                    None,
                    None,
                ],
                "debuggerGeneralPage": [
                    self.tr("General"),
                    "preferences-debugger",
                    "DebuggerGeneralPage",
                    "0debuggerPage",
                    None,
                ],
                "debuggerPython3Page": [
                    self.tr("Python3"),
                    "preferences-pyDebugger",
                    "DebuggerPython3Page",
                    "0debuggerPage",
                    None,
                ],
                "0editorPage": [
                    self.tr("Editor"),
                    "preferences-editor",
                    None,
                    None,
                    None,
                ],
                "editorAPIsPage": [
                    self.tr("APIs"),
                    "preferences-api",
                    "EditorAPIsPage",
                    "0editorPage",
                    None,
                ],
                "editorDocViewerPage": [
                    self.tr("Documentation Viewer"),
                    "codeDocuViewer",
                    "EditorDocViewerPage",
                    "0editorPage",
                    None,
                ],
                "editorGeneralPage": [
                    self.tr("General"),
                    "preferences-general",
                    "EditorGeneralPage",
                    "0editorPage",
                    None,
                ],
                "editorFilePage": [
                    self.tr("Filehandling"),
                    "preferences-filehandling",
                    "EditorFilePage",
                    "0editorPage",
                    None,
                ],
                "editorSearchPage": [
                    self.tr("Searching"),
                    "preferences-search",
                    "EditorSearchPage",
                    "0editorPage",
                    None,
                ],
                "editorSpellCheckingPage": [
                    self.tr("Spell checking"),
                    "preferences-spellchecking",
                    "EditorSpellCheckingPage",
                    "0editorPage",
                    None,
                ],
                "editorStylesPage": [
                    self.tr("Style"),
                    "preferences-styles",
                    "EditorStylesPage",
                    "0editorPage",
                    None,
                ],
                "editorSyntaxPage": [
                    self.tr("Code Checkers"),
                    "preferences-debugger",
                    "EditorSyntaxPage",
                    "0editorPage",
                    None,
                ],
                "editorTypingPage": [
                    self.tr("Typing"),
                    "preferences-typing",
                    "EditorTypingPage",
                    "0editorPage",
                    None,
                ],
                "editorExportersPage": [
                    self.tr("Exporters"),
                    "preferences-exporters",
                    "EditorExportersPage",
                    "0editorPage",
                    None,
                ],
                "1editorAutocompletionPage": [
                    self.tr("Autocompletion"),
                    "preferences-autocompletion",
                    "EditorAutocompletionPage",
                    "0editorPage",
                    None,
                ],
                "editorAutocompletionQScintillaPage": [
                    self.tr("QScintilla"),
                    "qscintilla",
                    "EditorAutocompletionQScintillaPage",
                    "1editorAutocompletionPage",
                    None,
                ],
                "editorAutocompletionJediPage": [
                    self.tr("Jedi"),
                    "jedi",
                    "EditorAutoCompletionJediPage",
                    "1editorAutocompletionPage",
                    None,
                ],
                "1editorCalltipsPage": [
                    self.tr("Calltips"),
                    "preferences-calltips",
                    "EditorCalltipsPage",
                    "0editorPage",
                    None,
                ],
                "editorCalltipsQScintillaPage": [
                    self.tr("QScintilla"),
                    "qscintilla",
                    "EditorCalltipsQScintillaPage",
                    "1editorCalltipsPage",
                    None,
                ],
                "editorCalltipsJediPage": [
                    self.tr("Jedi"),
                    "jedi",
                    "EditorCallTipsJediPage",
                    "1editorCalltipsPage",
                    None,
                ],
                "1editorLexerPage": [
                    self.tr("Highlighters"),
                    "preferences-highlighting-styles",
                    None,
                    "0editorPage",
                    None,
                ],
                "editorHighlightersPage": [
                    self.tr("Filetype Associations"),
                    "preferences-highlighter-association",
                    "EditorHighlightersPage",
                    "1editorLexerPage",
                    None,
                ],
                "editorHighlightingStylesPage": [
                    self.tr("Styles"),
                    "preferences-highlighting-styles",
                    "EditorHighlightingStylesPage",
                    "1editorLexerPage",
                    None,
                ],
                "editorKeywordsPage": [
                    self.tr("Keywords"),
                    "preferences-keywords",
                    "EditorKeywordsPage",
                    "1editorLexerPage",
                    None,
                ],
                "editorPropertiesPage": [
                    self.tr("Properties"),
                    "preferences-properties",
                    "EditorPropertiesPage",
                    "1editorLexerPage",
                    None,
                ],
                "1editorMouseClickHandlers": [
                    self.tr("Mouse Click Handlers"),
                    "preferences-mouse-click-handler",
                    "EditorMouseClickHandlerPage",
                    "0editorPage",
                    None,
                ],
                "editorMouseClickHandlerJediPage": [
                    self.tr("Jedi"),
                    "jedi",
                    "EditorMouseClickHandlerJediPage",
                    "1editorMouseClickHandlers",
                    None,
                ],
                "0helpPage": [self.tr("Help"), "preferences-help", None, None, None],
                "helpDocumentationPage": [
                    self.tr("Help Documentation"),
                    "preferences-helpdocumentation",
                    "HelpDocumentationPage",
                    "0helpPage",
                    None,
                ],
                "helpViewersPage": [
                    self.tr("Help Viewers"),
                    "preferences-helpviewers",
                    "HelpViewersPage",
                    "0helpPage",
                    None,
                ],
                "0projectPage": [
                    self.tr("Project"),
                    "preferences-project",
                    None,
                    None,
                    None,
                ],
                "projectBrowserPage": [
                    self.tr("Project Viewer"),
                    "preferences-project",
                    "ProjectBrowserPage",
                    "0projectPage",
                    None,
                ],
                "projectPage": [
                    self.tr("Project"),
                    "preferences-project",
                    "ProjectPage",
                    "0projectPage",
                    None,
                ],
                "multiProjectPage": [
                    self.tr("Multiproject"),
                    "preferences-multiproject",
                    "MultiProjectPage",
                    "0projectPage",
                    None,
                ],
                "0interfacePage": [
                    self.tr("Interface"),
                    "preferences-interface",
                    None,
                    None,
                    None,
                ],
                "interfacePage": [
                    self.tr("Interface"),
                    "preferences-interface",
                    "InterfacePage",
                    "0interfacePage",
                    None,
                ],
                "viewmanagerPage": [
                    self.tr("Viewmanager"),
                    "preferences-viewmanager",
                    "ViewmanagerPage",
                    "0interfacePage",
                    None,
                ],
            }
            if self.__webEngine:
                self.configItems.update(
                    {
                        "0webBrowserPage": [
                            self.tr("Web Browser"),
                            "ericWeb",
                            None,
                            None,
                            None,
                        ],
                        "webBrowserAppearancePage": [
                            self.tr("Appearance"),
                            "preferences-styles",
                            "WebBrowserAppearancePage",
                            "0webBrowserPage",
                            None,
                        ],
                        "webBrowserPage": [
                            self.tr("eric Web Browser"),
                            "ericWeb",
                            "WebBrowserPage",
                            "0webBrowserPage",
                            None,
                        ],
                        "webBrowserVirusTotalPage": [
                            self.tr("VirusTotal Interface"),
                            "virustotal",
                            "WebBrowserVirusTotalPage",
                            "0webBrowserPage",
                            None,
                        ],
                        "webBrowserSpellCheckingPage": [
                            self.tr("Spell checking"),
                            "preferences-spellchecking",
                            "WebBrowserSpellCheckingPage",
                            "0webBrowserPage",
                            None,
                        ],
                    }
                )

            self.configItems.update(
                ericApp().getObject("PluginManager").getPluginConfigData()
            )

        elif displayMode == ConfigurationMode.EDITORMODE:
            self.configItems = {
                # key : [display string, pixmap name, dialog module name or
                #        page creation function, parent key,
                #        reference to configuration page (must always be last)]
                # The dialog module must have the module function 'create' to
                # create the configuration page. This must have the method
                # 'save' to save the settings.
                "iconsPage": [
                    self.tr("Icons"),
                    "preferences-icons",
                    "IconsPage",
                    None,
                    None,
                ],
                "interfacePage": [
                    self.tr("Interface"),
                    "preferences-interface",
                    "InterfaceLightPage",
                    None,
                    None,
                ],
                "printerPage": [
                    self.tr("Printer"),
                    "preferences-printer",
                    "PrinterPage",
                    None,
                    None,
                ],
                "0editorPage": [
                    self.tr("Editor"),
                    "preferences-editor",
                    None,
                    None,
                    None,
                ],
                "editorGeneralPage": [
                    self.tr("General"),
                    "preferences-general",
                    "EditorGeneralPage",
                    "0editorPage",
                    None,
                ],
                "editorFilePage": [
                    self.tr("Filehandling"),
                    "preferences-filehandling",
                    "EditorFilePage",
                    "0editorPage",
                    None,
                ],
                "editorSearchPage": [
                    self.tr("Searching"),
                    "preferences-search",
                    "EditorSearchPage",
                    "0editorPage",
                    None,
                ],
                "editorSpellCheckingPage": [
                    self.tr("Spell checking"),
                    "preferences-spellchecking",
                    "EditorSpellCheckingPage",
                    "0editorPage",
                    None,
                ],
                "editorStylesPage": [
                    self.tr("Style"),
                    "preferences-styles",
                    "EditorStylesPage",
                    "0editorPage",
                    None,
                ],
                "editorTypingPage": [
                    self.tr("Typing"),
                    "preferences-typing",
                    "EditorTypingPage",
                    "0editorPage",
                    None,
                ],
                "1editorLexerPage": [
                    self.tr("Highlighters"),
                    "preferences-highlighting-styles",
                    None,
                    "0editorPage",
                    None,
                ],
                "editorHighlightersPage": [
                    self.tr("Filetype Associations"),
                    "preferences-highlighter-association",
                    "EditorHighlightersPage",
                    "1editorLexerPage",
                    None,
                ],
                "editorHighlightingStylesPage": [
                    self.tr("Styles"),
                    "preferences-highlighting-styles",
                    "EditorHighlightingStylesPage",
                    "1editorLexerPage",
                    None,
                ],
                "editorKeywordsPage": [
                    self.tr("Keywords"),
                    "preferences-keywords",
                    "EditorKeywordsPage",
                    "1editorLexerPage",
                    None,
                ],
                "editorPropertiesPage": [
                    self.tr("Properties"),
                    "preferences-properties",
                    "EditorPropertiesPage",
                    "1editorLexerPage",
                    None,
                ],
            }

        elif displayMode == ConfigurationMode.WEBBROWSERMODE:
            self.configItems = {
                # key : [display string, pixmap name, dialog module name or
                #        page creation function, parent key,
                #        reference to configuration page (must always be last)]
                # The dialog module must have the module function 'create' to
                # create the configuration page. This must have the method
                # 'save' to save the settings.
                "iconsPage": [
                    self.tr("Icons"),
                    "preferences-icons",
                    "IconsPage",
                    None,
                    None,
                ],
                "interfacePage": [
                    self.tr("Interface"),
                    "preferences-interface",
                    "InterfaceLightPage",
                    None,
                    None,
                ],
                "networkPage": [
                    self.tr("Network"),
                    "preferences-network",
                    "NetworkPage",
                    None,
                    None,
                ],
                "printerPage": [
                    self.tr("Printer"),
                    "preferences-printer",
                    "PrinterPage",
                    None,
                    None,
                ],
                "securityPage": [
                    self.tr("Security"),
                    "preferences-security",
                    "SecurityPage",
                    None,
                    None,
                ],
                "helpDocumentationPage": [
                    self.tr("Help Documentation"),
                    "preferences-helpdocumentation",
                    "HelpDocumentationPage",
                    None,
                    None,
                ],
                "webBrowserAppearancePage": [
                    self.tr("Appearance"),
                    "preferences-styles",
                    "WebBrowserAppearancePage",
                    None,
                    None,
                ],
                "webBrowserPage": [
                    self.tr("eric Web Browser"),
                    "ericWeb",
                    "WebBrowserPage",
                    None,
                    None,
                ],
                "webBrowserVirusTotalPage": [
                    self.tr("VirusTotal Interface"),
                    "virustotal",
                    "WebBrowserVirusTotalPage",
                    None,
                    None,
                ],
                "webBrowserSpellCheckingPage": [
                    self.tr("Spell checking"),
                    "preferences-spellchecking",
                    "WebBrowserSpellCheckingPage",
                    None,
                    None,
                ],
            }

        elif displayMode == ConfigurationMode.TRAYSTARTERMODE:
            self.configItems = {
                # key : [display string, pixmap name, dialog module name or
                #        page creation function, parent key,
                #        reference to configuration page (must always be last)]
                # The dialog module must have the module function 'create' to
                # create the configuration page. This must have the method
                # 'save' to save the settings.
                "trayStarterPage": [
                    self.tr("Tray Starter"),
                    "erict",
                    "TrayStarterPage",
                    None,
                    None,
                ],
            }

        elif displayMode == ConfigurationMode.HEXEDITORMODE:
            self.configItems = {
                # key : [display string, pixmap name, dialog module name or
                #        page creation function, parent key,
                #        reference to configuration page (must always be last)]
                # The dialog module must have the module function 'create' to
                # create the configuration page. This must have the method
                # 'save' to save the settings.
                "iconsPage": [
                    self.tr("Icons"),
                    "preferences-icons",
                    "IconsPage",
                    None,
                    None,
                ],
                "interfacePage": [
                    self.tr("Interface"),
                    "preferences-interface",
                    "InterfaceLightPage",
                    None,
                    None,
                ],
                "hexEditorPage": [
                    self.tr("Hex Editor"),
                    "hexEditor",
                    "HexEditorPage",
                    None,
                    None,
                ],
            }

        elif displayMode == ConfigurationMode.PDFVIEWERMODE:
            self.configItems = {
                # key : [display string, pixmap name, dialog module name or
                #        page creation function, parent key,
                #        reference to configuration page (must always be last)]
                # The dialog module must have the module function 'create' to
                # create the configuration page. This must have the method
                # 'save' to save the settings.
                "iconsPage": [
                    self.tr("Icons"),
                    "preferences-icons",
                    "IconsPage",
                    None,
                    None,
                ],
                "interfacePage": [
                    self.tr("Interface"),
                    "preferences-interface",
                    "InterfaceLightPage",
                    None,
                    None,
                ],
                "pdfViewerPage": [
                    self.tr("PDF Viewer"),
                    "ericPdf",
                    "PdfViewerPage",
                    None,
                    None,
                ],
            }

        else:
            # display mode for generic use
            self.configItems = {
                # key : [display string, pixmap name, dialog module name or
                #        page creation function, parent key,
                #        reference to configuration page (must always be last)]
                # The dialog module must have the module function 'create' to
                # create the configuration page. This must have the method
                # 'save' to save the settings.
                "iconsPage": [
                    self.tr("Icons"),
                    "preferences-icons",
                    "IconsPage",
                    None,
                    None,
                ],
                "interfacePage": [
                    self.tr("Interface"),
                    "preferences-interface",
                    "InterfaceLightPage",
                    None,
                    None,
                ],
            }

        # generate the list entries
        self.__expandedEntries = []
        for key in sorted(self.configItems.keys()):
            pageData = self.configItems[key]
            if pageData[3]:
                if pageData[3] in self.itmDict:
                    pitm = self.itmDict[pageData[3]]  # get the parent item
                else:
                    continue
            else:
                pitm = self.configList
            self.itmDict[key] = ConfigurationPageItem(
                pitm, pageData[0], key, pageData[1]
            )
            self.itmDict[key].setData(0, Qt.ItemDataRole.UserRole, key)
            if (
                not self.fromEric
                or displayMode != ConfigurationMode.DEFAULTMODE
                or key in expandedEntries
            ):
                self.itmDict[key].setExpanded(True)
        self.configList.sortByColumn(0, Qt.SortOrder.AscendingOrder)

        # set the initial size of the splitter
        self.configSplitter.setSizes([200, 600])
        self.configSplitter.splitterMoved.connect(self.__resizeConfigStack)

        self.configList.itemActivated.connect(self.__showConfigurationPage)
        self.configList.itemClicked.connect(self.__showConfigurationPage)
        self.buttonBox.accepted.connect(self.accept)
        self.buttonBox.rejected.connect(self.rejected)

        if displayMode in [
            ConfigurationMode.TRAYSTARTERMODE,
            ConfigurationMode.HEXEDITORMODE,
            ConfigurationMode.WEBBROWSERMODE,
        ]:
            self.configListSearch.hide()

        if displayMode not in [
            ConfigurationMode.TRAYSTARTERMODE,
            ConfigurationMode.HEXEDITORMODE,
        ]:
            self.__initLexers()

    def accept(self):
        """
        Public slot to accept the buttonBox accept signal.
        """
        if not OSUtilities.isMacPlatform():
            wdg = self.focusWidget()
            if wdg == self.configList:
                return

        self.accepted.emit()

    def __setupUi(self):
        """
        Private method to perform the general setup of the configuration
        widget.
        """
        self.setObjectName("ConfigurationDialog")
        self.resize(900, 750)
        self.verticalLayout_2 = QVBoxLayout(self)
        self.verticalLayout_2.setSpacing(6)
        self.verticalLayout_2.setContentsMargins(6, 6, 6, 6)
        self.verticalLayout_2.setObjectName("verticalLayout_2")

        self.configSplitter = QSplitter(self)
        self.configSplitter.setOrientation(Qt.Orientation.Horizontal)
        self.configSplitter.setObjectName("configSplitter")

        self.configListWidget = QWidget(self.configSplitter)
        self.leftVBoxLayout = QVBoxLayout(self.configListWidget)
        self.leftVBoxLayout.setContentsMargins(0, 0, 0, 0)
        self.leftVBoxLayout.setSpacing(0)
        self.leftVBoxLayout.setObjectName("leftVBoxLayout")
        self.configListSearch = QLineEdit(self)
        self.configListSearch.setPlaceholderText(self.tr("Enter search text..."))
        self.configListSearch.setClearButtonEnabled(True)
        self.configListSearch.setObjectName("configListSearch")
        self.configListSearch.setClearButtonEnabled(True)
        self.leftVBoxLayout.addWidget(self.configListSearch)
        self.configList = QTreeWidget()
        self.configList.setObjectName("configList")
        self.leftVBoxLayout.addWidget(self.configList)
        self.configListSearch.textChanged.connect(self.__searchTextChanged)

        self.scrollArea = QScrollArea(self.configSplitter)
        self.scrollArea.setFrameShape(QFrame.Shape.NoFrame)
        self.scrollArea.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOn)
        self.scrollArea.setHorizontalScrollBarPolicy(
            Qt.ScrollBarPolicy.ScrollBarAlwaysOn
        )
        self.scrollArea.setWidgetResizable(False)
        self.scrollArea.setSizeAdjustPolicy(
            QAbstractScrollArea.SizeAdjustPolicy.AdjustToContents
        )
        self.scrollArea.setObjectName("scrollArea")

        self.configStack = QStackedWidget()
        self.configStack.setFrameShape(QFrame.Shape.Box)
        self.configStack.setFrameShadow(QFrame.Shadow.Sunken)
        self.configStack.setObjectName("configStack")
        self.scrollArea.setWidget(self.configStack)

        self.emptyPage = QWidget()
        self.emptyPage.setGeometry(QRect(0, 0, 372, 591))
        self.emptyPage.setObjectName("emptyPage")
        self.vboxlayout = QVBoxLayout(self.emptyPage)
        self.vboxlayout.setSpacing(6)
        self.vboxlayout.setContentsMargins(6, 6, 6, 6)
        self.vboxlayout.setObjectName("vboxlayout")
        spacerItem = QSpacerItem(
            20, 20, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding
        )
        self.vboxlayout.addItem(spacerItem)
        self.emptyPagePixmap = QLabel(self.emptyPage)
        self.emptyPagePixmap.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.emptyPagePixmap.setObjectName("emptyPagePixmap")
        self.emptyPagePixmap.setPixmap(
            QPixmap(os.path.join(getConfig("ericPixDir"), "eric.png"))
        )
        self.vboxlayout.addWidget(self.emptyPagePixmap)
        self.textLabel1 = QLabel(self.emptyPage)
        self.textLabel1.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.textLabel1.setObjectName("textLabel1")
        self.vboxlayout.addWidget(self.textLabel1)
        spacerItem1 = QSpacerItem(
            20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding
        )
        self.vboxlayout.addItem(spacerItem1)
        self.configStack.addWidget(self.emptyPage)

        self.verticalLayout_2.addWidget(self.configSplitter)

        self.buttonBox = QDialogButtonBox(self)
        self.buttonBox.setOrientation(Qt.Orientation.Horizontal)
        self.buttonBox.setStandardButtons(
            QDialogButtonBox.StandardButton.Apply
            | QDialogButtonBox.StandardButton.Cancel
            | QDialogButtonBox.StandardButton.Ok
            | QDialogButtonBox.StandardButton.Reset
        )
        self.buttonBox.setObjectName("buttonBox")
        if not self.fromEric and self.displayMode == ConfigurationMode.DEFAULTMODE:
            self.buttonBox.button(QDialogButtonBox.StandardButton.Apply).hide()
        self.buttonBox.button(QDialogButtonBox.StandardButton.Apply).setEnabled(False)
        self.buttonBox.button(QDialogButtonBox.StandardButton.Reset).setEnabled(False)
        self.verticalLayout_2.addWidget(self.buttonBox)

        self.setWindowTitle(self.tr("Preferences"))

        self.configList.header().hide()
        self.configList.header().setSortIndicator(0, Qt.SortOrder.AscendingOrder)
        self.configList.setSortingEnabled(True)
        self.textLabel1.setText(
            self.tr(
                "Please select an entry of the list \n"
                "to display the configuration page."
            )
        )

        QMetaObject.connectSlotsByName(self)
        self.setTabOrder(self.configList, self.configStack)

        self.configStack.setCurrentWidget(self.emptyPage)

        self.configList.setFocus()

    def __searchTextChanged(self, text):
        """
        Private slot to handle a change of the search text.

        @param text text to search for (string)
        """
        self.__searchChildItems(self.configList.invisibleRootItem(), text)

    def __searchChildItems(self, parent, text):
        """
        Private method to enable child items based on a search string.

        @param parent reference to the parent item (QTreeWidgetItem)
        @param text text to search for (string)
        @return flag indicating an enabled child item (boolean)
        """
        childEnabled = False
        text = text.lower()
        for index in range(parent.childCount()):
            itm = parent.child(index)
            enable = (
                (
                    self.__searchChildItems(itm, text)
                    or text == ""
                    or text in itm.text(0).lower()
                )
                if itm.childCount() > 0
                else (text == "" or text in itm.text(0).lower())
            )
            if enable:
                childEnabled = True
            itm.setDisabled(not enable)

        return childEnabled

    def __initLexers(self):
        """
        Private method to initialize the dictionary of preferences lexers.
        """
        from eric7.QScintilla import Lexers

        from .PreferencesLexer import PreferencesLexer, PreferencesLexerLanguageError

        self.lexers = {}
        for language in Lexers.getSupportedLanguages():
            if language not in self.lexers:
                with contextlib.suppress(PreferencesLexerLanguageError):
                    self.lexers[language] = PreferencesLexer(language, self)

    def __importConfigurationPage(self, name):
        """
        Private method to import a configuration page module.

        @param name name of the configuration page module (string)
        @return reference to the configuration page module
        """
        try:
            mod = importlib.import_module(
                ".ConfigurationPages.{0}".format(name), __package__
            )
            return mod
        except ImportError:
            EricMessageBox.critical(
                self,
                self.tr("Configuration Page Error"),
                self.tr(
                    """<p>The configuration page <b>{0}</b>"""
                    """ could not be loaded.</p>"""
                ).format(name),
            )
            return None

    def __showConfigurationPage(self, itm, column):
        """
        Private slot to show a selected configuration page.

        @param itm reference to the selected item (QTreeWidgetItem)
        @param column column that was selected (integer) (ignored)
        """
        pageName = itm.getPageName()
        self.showConfigurationPageByName(pageName, setCurrent=False)

    def __initPage(self, pageData):
        """
        Private method to initialize a configuration page.

        @param pageData data structure for the page to initialize
        @return reference to the initialized page
        """
        page = None
        if isinstance(pageData[2], types.FunctionType):
            page = pageData[2](self)
        else:
            mod = self.__importConfigurationPage(pageData[2])
            if mod:
                page = mod.create(self)
        if page is not None:
            self.configStack.addWidget(page)
            pageData[-1] = page
            with contextlib.suppress(AttributeError):
                page.setMode(self.displayMode)
        return page

    def showConfigurationPageByName(self, pageName, setCurrent=True):
        """
        Public slot to show a named configuration page.

        @param pageName name of the configuration page to show (string)
        @param setCurrent flag indicating to set the current item (boolean)
        """
        if pageName == "empty" or pageName not in self.configItems:
            page = self.emptyPage
        else:
            pageData = self.configItems[pageName]
            if pageData[-1] is None and pageData[2] is not None:
                # the page was not loaded yet, create it
                page = self.__initPage(pageData)
            else:
                page = pageData[-1]
            if page is None:
                page = self.emptyPage
            elif setCurrent:
                items = self.configList.findItems(
                    pageData[0],
                    Qt.MatchFlag.MatchFixedString | Qt.MatchFlag.MatchRecursive,
                )
                for item in items:
                    if item.data(0, Qt.ItemDataRole.UserRole) == pageName:
                        self.configList.setCurrentItem(item)
        self.configStack.setCurrentWidget(page)
        self.__resizeConfigStack()

        if page != self.emptyPage:
            page.polishPage()
            self.buttonBox.button(QDialogButtonBox.StandardButton.Apply).setEnabled(
                True
            )
            self.buttonBox.button(QDialogButtonBox.StandardButton.Reset).setEnabled(
                True
            )
        else:
            self.buttonBox.button(QDialogButtonBox.StandardButton.Apply).setEnabled(
                False
            )
            self.buttonBox.button(QDialogButtonBox.StandardButton.Reset).setEnabled(
                False
            )

        # reset scrollbars
        for sb in [
            self.scrollArea.horizontalScrollBar(),
            self.scrollArea.verticalScrollBar(),
        ]:
            if sb:
                sb.setValue(0)

        self.__currentConfigurationPageName = pageName

    def resizeEvent(self, evt):
        """
        Protected method to handle the resizing of the widget.

        @param evt reference to the event object
        @type QResizeEvent
        """
        self.__resizeConfigStack()

    def __resizeConfigStack(self):
        """
        Private method to resize the stack of configuration pages.
        """
        ssize = self.scrollArea.size()
        if self.scrollArea.horizontalScrollBar():
            ssize.setHeight(
                ssize.height() - self.scrollArea.horizontalScrollBar().height() - 2
            )
        if self.scrollArea.verticalScrollBar():
            ssize.setWidth(
                ssize.width() - self.scrollArea.verticalScrollBar().width() - 2
            )
        psize = self.configStack.currentWidget().minimumSizeHint()
        self.configStack.resize(
            max(ssize.width(), psize.width()), max(ssize.height(), psize.height())
        )

    def getConfigurationPageName(self):
        """
        Public method to get the page name of the current page.

        @return page name of the current page (string)
        """
        return self.__currentConfigurationPageName

    def calledFromEric(self):
        """
        Public method to check, if invoked from within eric.

        @return flag indicating invocation from within eric (boolean)
        """
        return self.fromEric

    def getPage(self, pageName):
        """
        Public method to get a reference to the named page.

        @param pageName name of the configuration page (string)
        @return reference to the page or None, indicating page was
            not loaded yet
        """
        return self.configItems[pageName][-1]

    def getLexers(self):
        """
        Public method to get a reference to the lexers dictionary.

        @return reference to the lexers dictionary
        """
        return self.lexers

    def setPreferences(self):
        """
        Public method called to store the selected values into the preferences
        storage.
        """
        now = time.monotonic()
        for pageData in self.configItems.values():
            if pageData[-1]:
                pageData[-1].save()
                # page was loaded (and possibly modified)
                if time.monotonic() - now > 0.01:
                    QApplication.processEvents()  # ensure HMI is responsive
                    now = time.monotonic()

    def on_buttonBox_clicked(self, button):
        """
        Private slot called by a button of the button box clicked.

        @param button button that was clicked (QAbstractButton)
        """
        if button == self.buttonBox.button(QDialogButtonBox.StandardButton.Apply):
            self.on_applyButton_clicked()
        elif button == self.buttonBox.button(QDialogButtonBox.StandardButton.Reset):
            self.on_resetButton_clicked()

    @pyqtSlot()
    def on_applyButton_clicked(self):
        """
        Private slot called to apply the settings of the current page.
        """
        if self.configStack.currentWidget() != self.emptyPage:
            page = self.configStack.currentWidget()
            savedState = page.saveState()
            page.save()
            self.preferencesChanged.emit()
            if savedState is not None:
                page.setState(savedState)
            page.polishPage()

    @pyqtSlot()
    def on_resetButton_clicked(self):
        """
        Private slot called to reset the settings of the current page.
        """
        if self.configStack.currentWidget() != self.emptyPage:
            currentPage = self.configStack.currentWidget()
            savedState = currentPage.saveState()
            pageName = self.configList.currentItem().getPageName()
            self.configStack.removeWidget(currentPage)
            if pageName == "editorHighlightingStylesPage":
                self.__initLexers()
            self.configItems[pageName][-1] = None

            self.showConfigurationPageByName(pageName)
            if savedState is not None:
                self.configStack.currentWidget().setState(savedState)

    def getExpandedEntries(self):
        """
        Public method to get a list of expanded entries.

        @return list of expanded entries (list of string)
        """
        return self.__expandedEntries

    @pyqtSlot(QTreeWidgetItem)
    def on_configList_itemCollapsed(self, item):
        """
        Private slot handling a list entry being collapsed.

        @param item reference to the collapsed item (QTreeWidgetItem)
        """
        pageName = item.data(0, Qt.ItemDataRole.UserRole)
        if pageName in self.__expandedEntries:
            self.__expandedEntries.remove(pageName)

    @pyqtSlot(QTreeWidgetItem)
    def on_configList_itemExpanded(self, item):
        """
        Private slot handling a list entry being expanded.

        @param item reference to the expanded item (QTreeWidgetItem)
        """
        pageName = item.data(0, Qt.ItemDataRole.UserRole)
        if pageName not in self.__expandedEntries:
            self.__expandedEntries.append(pageName)

    def isUsingWebEngine(self):
        """
        Public method to get an indication, if QtWebEngine is being used.

        @return flag indicating the use of QtWebEngine
        @rtype bool
        """
        return self.__webEngine or self.displayMode == ConfigurationMode.WEBBROWSERMODE


class ConfigurationDialog(QDialog):
    """
    Class for the dialog variant.

    @signal preferencesChanged() emitted after settings have been changed
    @signal mainPasswordChanged(str, str) emitted after the main
        password has been changed with the old and the new password
    """

    preferencesChanged = pyqtSignal()
    mainPasswordChanged = pyqtSignal(str, str)

    def __init__(
        self,
        parent=None,
        name=None,
        modal=False,
        fromEric=True,
        displayMode=ConfigurationMode.DEFAULTMODE,
        expandedEntries=None,
    ):
        """
        Constructor

        @param parent reference to the parent widget
        @type QWidget
        @param name name of the dialog
        @type str
        @param modal flag indicating a modal dialog
        @type bool
        @param fromEric flag indicating a dialog generation from within the
            eric IDE
        @type bool
        @param displayMode mode of the configuration dialog
        @type ConfigurationMode
        @param expandedEntries list of entries to be shown expanded
        @type list of str
        """
        super().__init__(parent)
        if name:
            self.setObjectName(name)
        self.setModal(modal)
        self.setWindowFlags(Qt.WindowType.Window)

        self.layout = QVBoxLayout(self)
        self.layout.setContentsMargins(0, 0, 0, 0)
        self.layout.setSpacing(0)

        self.cw = ConfigurationWidget(
            self,
            fromEric=fromEric,
            displayMode=displayMode,
            expandedEntries=expandedEntries,
        )
        size = self.cw.size()
        self.layout.addWidget(self.cw)
        self.resize(size)
        self.setWindowTitle(self.cw.windowTitle())

        self.cw.accepted.connect(self.accept)
        self.cw.rejected.connect(self.reject)
        self.cw.preferencesChanged.connect(self.__preferencesChanged)
        self.cw.mainPasswordChanged.connect(self.__mainPasswordChanged)

    def __preferencesChanged(self):
        """
        Private slot to handle a change of the preferences.
        """
        self.preferencesChanged.emit()

    def __mainPasswordChanged(self, oldPassword, newPassword):
        """
        Private slot to handle the change of the main password.

        @param oldPassword current password
        @type str
        @param newPassword new password
        @type str
        """
        self.mainPasswordChanged.emit(oldPassword, newPassword)

    def showConfigurationPageByName(self, pageName):
        """
        Public slot to show a named configuration page.

        @param pageName name of the configuration page to show (string)
        """
        self.cw.showConfigurationPageByName(pageName)

    def getConfigurationPageName(self):
        """
        Public method to get the page name of the current page.

        @return page name of the current page (string)
        """
        return self.cw.getConfigurationPageName()

    def getExpandedEntries(self):
        """
        Public method to get a list of expanded entries.

        @return list of expanded entries (list of string)
        """
        return self.cw.getExpandedEntries()

    def setPreferences(self):
        """
        Public method called to store the selected values into the preferences
        storage.
        """
        self.cw.setPreferences()

    def accept(self):
        """
        Public method to accept the dialog.
        """
        super().accept()


class ConfigurationWindow(EricMainWindow):
    """
    Main window class for the standalone dialog.
    """

    def __init__(self, parent=None):
        """
        Constructor

        @param parent reference to the parent widget (QWidget)
        """
        super().__init__(parent)

        self.cw = ConfigurationWidget(self, fromEric=False)
        size = self.cw.size()
        self.setCentralWidget(self.cw)
        self.resize(size)
        self.setWindowTitle(self.cw.windowTitle())

        self.setStyle(Preferences.getUI("Style"), Preferences.getUI("StyleSheet"))

        self.cw.accepted.connect(self.accept)
        self.cw.rejected.connect(self.close)

    def showConfigurationPageByName(self, pageName):
        """
        Public slot to show a named configuration page.

        @param pageName name of the configuration page to show (string)
        """
        self.cw.showConfigurationPageByName(pageName)

    def accept(self):
        """
        Public slot called by the Ok button.
        """
        self.cw.setPreferences()
        Preferences.saveResetLayout()
        Preferences.syncPreferences()
        self.close()

eric ide

mercurial