PluginSelectionEncloser.py

Sat, 23 Dec 2023 18:14:27 +0100

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Sat, 23 Dec 2023 18:14:27 +0100
branch
eric7
changeset 61
4cd8dfb2c924
parent 60
44349feb5af7
child 62
5d418352a1bc
permissions
-rw-r--r--

Corrected some code style issues.

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

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

"""
Module implementing the Selection Encloser plug-in.
"""

import contextlib
import json
import os

from PyQt6.QtCore import QCoreApplication, QObject, QTranslator, pyqtSlot
from PyQt6.QtGui import QAction
from PyQt6.QtWidgets import QMenu

from eric7 import Preferences
from eric7.EricWidgets.EricApplication import ericApp

# Start-Of-Header
name = "Selection Encloser Plug-in"
author = "Detlev Offenbach <detlev@die-offenbachs.de>"
autoactivate = True
deactivateable = True
version = "10.1.0"
className = "SelectionEncloserPlugin"
packageName = "SelectionEncloser"
shortDescription = "Enclose the selection with a string."
longDescription = (
    """This plug-in implements a tool to enclose the selection of"""
    """ the current editor with a string. The enclosing string is"""
    """ selectable via a configurable menu hierarchy."""
)
needsRestart = False
pyqtApi = 2
# End-Of-Header

error = ""

selectionEncloserPluginObject = None


def createSelectionEncloserPage(configDlg):  # noqa: U100
    """
    Module function to create the Selection Encloser configuration page.

    @param configDlg reference to the configuration dialog
    @type ConfigurationWidget
    @return reference to the configuration page
    @rtype SelectionEncloserPage
    """
    from SelectionEncloser.ConfigurationPage.SelectionEncloserPage import (
        SelectionEncloserPage,
    )

    global selectionEncloserPluginObject

    return SelectionEncloserPage(selectionEncloserPluginObject)


def getConfigData():
    """
    Module function returning data as required by the configuration dialog.

    @return dictionary containing the relevant data
    @rtype dict
    """
    usesDarkPalette = ericApp().usesDarkPalette()
    iconSuffix = "dark" if usesDarkPalette else "light"

    return {
        "selectionEncloserPage": [
            QCoreApplication.translate("SelectionEncloserPlugin", "Selection Encloser"),
            os.path.join(
                "SelectionEncloser", "icons", "selectionEncloser-{0}".format(iconSuffix)
            ),
            createSelectionEncloserPage,
            None,
            None,
        ],
    }


def prepareUninstall():
    """
    Module function to prepare for an uninstallation.
    """
    Preferences.Prefs.settings.remove(SelectionEncloserPlugin.PreferencesKey)


class SelectionEncloserPlugin(QObject):
    """
    Class implementing the Selection Encloser plugin.
    """

    PreferencesKey = "SelectionEncloser"

    def __init__(self, ui):
        """
        Constructor

        @param ui reference to the user interface object
        @type UserInterface
        """
        super().__init__(ui)
        self.__ui = ui

        # menu is a list of lists; each list consists of a string for the
        # submenu title and a list of submenu entries. Each submenu entry
        # consists of another list giving the title and the enclosing string
        # or formatting string.
        defaultMenu = [
            [
                self.tr("Quotes"),
                [['"', '"'], ["'", "'"], ['"""', '"""'], ["'''", "'''"]],
            ],
            [
                self.tr("HTML"),
                [
                    ["<h1>", "<h1>{0}</h1>"],
                    ["<h2>", "<h2>{0}</h2>"],
                    ["<h3>", "<h3>{0}</h3>"],
                    ["--Separator--", ""],
                    ["<p>", "<p>{0}</p>"],
                    ["<div>", "<div>{0}</div>"],
                    ["<span>", "<span>{0}</span>"],
                ],
            ],
        ]
        self.__defaults = {
            "MenuHierarchy": json.dumps(defaultMenu),
        }

        self.__translator = None
        self.__loadTranslator()

        self.__initMenu()

        self.__editors = {}
        self.__mainActions = []

    def activate(self):
        """
        Public method to activate this plugin.

        @return tuple of None and activation status
        @rtype (None, bool)
        """
        global error
        error = ""  # clear previous error

        global selectionEncloserPluginObject
        selectionEncloserPluginObject = self

        self.__ui.showMenu.connect(self.__populateMenu)

        menu = self.__ui.getMenu("plugin_tools")
        if menu is not None:
            if not menu.isEmpty():
                act = menu.addSeparator()
                self.__mainActions.append(act)
            act = menu.addMenu(self.__menu)
            self.__mainActions.append(act)

        ericApp().getObject("ViewManager").editorOpenedEd.connect(self.__editorOpened)
        ericApp().getObject("ViewManager").editorClosedEd.connect(self.__editorClosed)

        for editor in ericApp().getObject("ViewManager").getOpenEditors():
            self.__editorOpened(editor)

        return None, True

    def deactivate(self):
        """
        Public method to deactivate this plugin.
        """
        self.__ui.showMenu.disconnect(self.__populateMenu)

        menu = self.__ui.getMenu("plugin_tools")
        if menu is not None:
            for act in self.__mainActions:
                menu.removeAction(act)
        self.__mainActions = []

        ericApp().getObject("ViewManager").editorOpenedEd.disconnect(
            self.__editorOpened
        )
        ericApp().getObject("ViewManager").editorClosedEd.disconnect(
            self.__editorClosed
        )

        for editor, acts in self.__editors.items():
            editor.showMenu.disconnect(self.__editorShowMenu)
            menu = editor.getMenu("Tools")
            if menu is not None:
                for act in acts:
                    menu.removeAction(act)
        self.__editors = {}

    def __loadTranslator(self):
        """
        Private method to load the translation file.
        """
        if self.__ui is not None:
            loc = self.__ui.getLocale()
            if loc and loc != "C":
                locale_dir = os.path.join(
                    os.path.dirname(__file__), "SelectionEncloser", "i18n"
                )
                translation = "selectionencloser_{0}".format(loc)
                translator = QTranslator(None)
                loaded = translator.load(translation, locale_dir)
                if loaded:
                    self.__translator = translator
                    ericApp().installTranslator(self.__translator)
                else:
                    print(
                        "Warning: translation file '{0}' could not be"
                        " loaded.".format(translation)
                    )
                    print("Using default.")

    def getPreferences(self, key):
        """
        Public method to retrieve the various settings.

        @param key key of the value to get
        @type str
        @return value of the requested setting
        @rtype Any
        """
        if key in ["MenuHierarchy"]:
            return json.loads(
                Preferences.Prefs.settings.value(
                    self.PreferencesKey + "/" + key, self.__defaults[key]
                )
            )
        else:
            return Preferences.Prefs.settings.value(
                self.PreferencesKey + "/" + key, self.__defaults[key]
            )

    def setPreferences(self, key, value):
        """
        Public method to store the various settings.

        @param key key of the setting to be set
        @type str
        @param value value to be set
        @type Any
        """
        if key in ["MenuHierarchy"]:
            Preferences.Prefs.settings.setValue(
                self.PreferencesKey + "/" + key, json.dumps(value)
            )
        else:
            Preferences.Prefs.settings.setValue(self.PreferencesKey + "/" + key, value)

    def __initMenu(self):
        """
        Private method to initialize the menu.
        """
        self.__menu = QMenu("Enclose Selection")
        self.__menu.setEnabled(False)
        self.__menu.aboutToShow.connect(self.__showMenu)

    def __populateMenu(self, name, menu):
        """
        Private slot to populate the tools menu with our entry.

        @param name name of the menu
        @type str
        @param menu reference to the menu to be populated
        @type QMenu
        """
        if name not in ["Tools", "PluginTools"]:
            return

        editor = ericApp().getObject("ViewManager").activeWindow()

        if name == "Tools":
            if not menu.isEmpty():
                menu.addSeparator()
            act = menu.addMenu(self.__menu)
            act.setEnabled(editor is not None and editor.hasSelectedText())
        elif name == "PluginTools" and self.__mainActions:
            self.__menu.setEnabled(editor is not None and editor.hasSelectedText())

    def __editorOpened(self, editor):
        """
        Private slot called, when a new editor was opened.

        @param editor reference to the new editor
        @type Editor
        """
        menu = editor.getMenu("Tools")
        if menu is not None:
            self.__editors[editor] = []
            if not menu.isEmpty():
                act = menu.addSeparator()
                self.__editors[editor].append(act)
            act = menu.addMenu(self.__menu)
            self.__menu.setEnabled(True)
            self.__editors[editor].append(act)
            editor.showMenu.connect(self.__editorShowMenu)

    def __editorClosed(self, editor):
        """
        Private slot called, when an editor was closed.

        @param editor reference to the editor
        @type Editor
        """
        with contextlib.suppress(KeyError):
            del self.__editors[editor]
            if not self.__editors:
                self.__menu.setEnabled(False)

    def __editorShowMenu(self, menuName, menu, editor):
        """
        Private slot called, when the the editor context menu or a submenu is
        about to be shown.

        @param menuName name of the menu to be shown
        @type str
        @param menu reference to the menu
        @type QMenu
        @param editor reference to the editor
        @type Editor
        """
        if menuName == "Tools":
            if self.__menu.menuAction() not in menu.actions():
                # Re-add our menu
                self.__editors[editor] = []
                if not menu.isEmpty():
                    act = menu.addSeparator()
                    self.__editors[editor].append(act)
                act = menu.addMenu(self.__menu)
                self.__editors[editor].append(act)

            self.__menu.setEnabled(editor.selectedText() != "")

    def __showMenu(self):
        """
        Private slot to build the menu hierarchy.
        """
        self.__menu.clear()
        hierarchy = self.getPreferences("MenuHierarchy")
        for menuTitle, entries in hierarchy:
            if menuTitle == "--Separator--":
                self.__menu.addSeparator()
            else:
                submenu = QMenu(menuTitle, self.__menu)
                for title, encString in entries:
                    if title == "--Separator--":
                        submenu.addSeparator()
                    else:
                        act = submenu.addAction(title)
                        act.setData(encString)
                submenu.triggered.connect(self.__encloseSelection)
                self.__menu.addMenu(submenu)

    @pyqtSlot(QAction)
    def __encloseSelection(self, act):
        """
        Private slot to enclose the selection with the selected string.

        @param act action that triggered
        @type QAction
        """
        if act is None:
            return

        editor = ericApp().getObject("ViewManager").activeWindow()
        if editor is None:
            return

        if not editor.hasSelectedText():
            return

        encloseString = act.data()
        if not encloseString:
            return

        if "%s" in encloseString:
            newText = encloseString % editor.selectedText()
        elif "{0}" in encloseString or "{}" in encloseString:
            # __IGNORE_WARNING_M613__
            newText = encloseString.format(editor.selectedText())
        else:
            newText = encloseString + editor.selectedText() + encloseString
        editor.beginUndoAction()
        editor.replaceSelectedText(newText)
        editor.endUndoAction()


#
# eflag: noqa = M801, U200

eric ide

mercurial