PluginPySide2PyQt.py

Sat, 23 Dec 2023 18:11:52 +0100

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Sat, 23 Dec 2023 18:11:52 +0100
branch
eric7
changeset 69
8424325c236b
parent 68
4094f1fb16a7
child 70
1007fc8b0da0
permissions
-rw-r--r--

Checked code style.

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

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

"""
Module implementing the PySide to PyQt (and vice versa) plug-in.
"""

import contextlib
import os

from PyQt6.QtCore import QObject, QTranslator
from PyQt6.QtWidgets import QMenu

from eric7.EricWidgets.EricApplication import ericApp

# Start-Of-Header
name = "PySide to PyQt (and vice versa) Plug-in"
author = "Detlev Offenbach <detlev@die-offenbachs.de>"
autoactivate = True
deactivateable = True
version = "10.1.0"
className = "PySide2PyQtPlugin"
packageName = "PySide2PyQt"
shortDescription = "Convert PySide file to PyQt and vice versa"
longDescription = (
    """This plug-in implements a tool to convert a PySide2 file to PyQt5"""
    """ and vice versa or a PySide6 file to PyQt6 and vice versa. It works"""
    """ with the text of the current editor."""
)
needsRestart = False
pyqtApi = 2
# End-Of-Header

error = ""


class PySide2PyQtPlugin(QObject):
    """
    Class implementing the PySide to PyQt (and vice versa) plugin.
    """

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

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

        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

        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__), "PySide2PyQt", "i18n"
                )
                translation = "pyside2pyqt_{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 __initMenu(self):
        """
        Private method to initialize the menu.
        """
        self.__menu = QMenu(self.tr("PySide to/from PyQt"))
        self.__menu.addAction(
            self.tr("PySide2 to PyQt5"), lambda: self.__pyside2Pyqt("pyside2", "pyqt5")
        )
        self.__menu.addAction(
            self.tr("PyQt5 to PySide2"), lambda: self.__pyqt2Pyside("pyqt5", "pyside2")
        )
        self.__menu.addSeparator()
        self.__menu.addAction(
            self.tr("PySide6 to PyQt6"), lambda: self.__pyside2Pyqt("pyside6", "pyqt6")
        )
        self.__menu.addAction(
            self.tr("PyQt6 to PySide6"), lambda: self.__pyqt2Pyside("pyqt6", "pyside6")
        )
        self.__menu.setEnabled(False)

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

        @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)
        elif name == "PluginTools" and self.__mainActions:
            self.__mainActions[-1].setEnabled(editor is not None)

    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.__editors[editor].append(act)
            self.__menu.setEnabled(True)
            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" and 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)

    def __pyside2Pyqt(self, pyside, pyqt):
        """
        Private slot to convert the code of the current editor from PySide
        to PyQt.

        @param pyside PySide variant (pyside2 or pyside6)
        @type str
        @param pyqt PyQt variant (pyqt5 or pyqt6)
        @type str
        """
        editor = ericApp().getObject("ViewManager").activeWindow()
        if editor is None:
            return

        text = editor.text()
        if pyqt == "pyqt5" and pyside == "pyside2":
            newText = (
                text.replace("PySide2", "PyQt5")
                .replace("Signal", "pyqtSignal")
                .replace("Slot", "pyqtSlot")
                .replace("Property", "pyqtProperty")
                .replace("pyside2-uic", "pyuic5")
                .replace("pyside2-rcc", "pyrcc5")
                .replace("pyside2-lupdate", "pylupdate5")
            )
        elif pyqt == "pyqt6" and pyside == "pyside6":
            newText = (
                text.replace("PySide6", "PyQt6")
                .replace("Signal", "pyqtSignal")
                .replace("Slot", "pyqtSlot")
                .replace("Property", "pyqtProperty")
                .replace("pyside6-uic", "pyuic6")
                .replace("pyside6-lupdate", "pylupdate6")
            )
        else:
            return

        if newText != text:
            editor.beginUndoAction()
            editor.selectAll()
            editor.replaceSelectedText(newText)
            editor.endUndoAction()

    def __pyqt2Pyside(self, pyqt, pyside):
        """
        Private slot to convert the code of the current editor from PyQt
        to PySide.

        @param pyqt PyQt variant (pyqt5 or pyqt6)
        @type str
        @param pyside PySide variant (pyside2 or pyside6)
        @type str
        """
        editor = ericApp().getObject("ViewManager").activeWindow()
        if editor is None:
            return

        text = editor.text()
        if pyqt == "pyqt5" and pyside == "pyside2":
            newText = (
                text.replace("PyQt5", "PySide2")
                .replace("pyqtSignal", "Signal")
                .replace("pyqtSlot", "Slot")
                .replace("pyqtProperty", "Property")
                .replace("pyuic5", "pyside2-uic")
                .replace("pyrcc5", "pyside2-rcc")
                .replace("pylupdate5", "pyside2-lupdate")
            )
        elif pyqt == "pyqt6" and pyside == "pyside6":
            newText = (
                text.replace("PyQt6", "PySide6")
                .replace("pyqtSignal", "Signal")
                .replace("pyqtSlot", "Slot")
                .replace("pyqtProperty", "Property")
                .replace("pyuic6", "pyside6-uic")
                .replace("pylupdate6", "pyside6-lupdate")
            )
        else:
            return

        if newText != text:
            editor.beginUndoAction()
            editor.selectAll()
            editor.replaceSelectedText(newText)
            editor.endUndoAction()


#
# eflag: noqa = M801, U200

eric ide

mercurial