PluginProjectDjango.py

Mon, 28 Oct 2024 16:24:54 +0100

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Mon, 28 Oct 2024 16:24:54 +0100
branch
eric7
changeset 195
b027b4f90994
parent 193
bf4c1a7833b4
child 197
2667e16a3379
permissions
-rw-r--r--

- changed to the new style header
- ensured proper parent relationship of modal dialogs
- included compiled form files

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

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

"""
Module implementing the Django project plugin.
"""

import fnmatch
import glob
import os

from PyQt6.QtCore import QCoreApplication, QObject, QTranslator

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

try:
    from eric7.SystemUtilities.OSUtilities import isMacPlatform, isWindowsPlatform
except ImportError:
    # imports for eric < 23.1
    from eric7.Globals import isWindowsPlatform, isMacPlatform

from ProjectDjango.Project import Project

# Start-of-Header
__header__ = {
    "name": "Django Project Plugin",
    "author": "Detlev Offenbach <detlev@die-offenbachs.de>",
    "autoactivate": True,
    "deactivateable": True,
    "version": "10.3.2",
    "className": "ProjectDjangoPlugin",
    "packageName": "ProjectDjango",
    "shortDescription": "Project support for Django projects.",
    "longDescription": "This plugin implements project support for Django projects.",
    "needsRestart": False,
    "hasCompiledForms": True,
    "pyqtApi": 2,
}
# End-of-Header

error = ""

djangoPluginObject = None


def apiFiles(language):
    """
    Module function to return the API files made available by this plugin.

    @param language language to get APIs for
    @type str
    @return list of API filenames
    @rtype list of str
    """
    if language in ["Python3"]:
        apisDir = os.path.join(os.path.dirname(__file__), "ProjectDjango", "APIs")
        apis = glob.glob(os.path.join(apisDir, "*.api"))
    else:
        apis = []
    return apis


def createDjangoPage(configDlg):  # noqa: U100
    """
    Module function to create the Django configuration page.

    @param configDlg reference to the configuration dialog
    @type ConfigurationWidget
    @return reference to the configuration page
    @rtype DjangoPage
    """
    from ProjectDjango.ConfigurationPage.DjangoPage import DjangoPage

    global djangoPluginObject

    page = DjangoPage(djangoPluginObject)
    return page


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 {
        "djangoPage": [
            QCoreApplication.translate("ProjectDjangoPlugin", "Django"),
            os.path.join("ProjectDjango", "icons", "django-{0}".format(iconSuffix)),
            createDjangoPage,
            None,
            None,
        ],
    }


def prepareUninstall():
    """
    Module function to prepare for an uninstallation.
    """
    try:
        Preferences.removeProjectBrowsers(ProjectDjangoPlugin.PreferencesKey)
    except AttributeError:
        # backward compatibility for eric7 < 22.12
        Preferences.removeProjectBrowserFlags(ProjectDjangoPlugin.PreferencesKey)
    Preferences.Prefs.settings.remove(ProjectDjangoPlugin.PreferencesKey)
    Preferences.Prefs.rsettings.remove(ProjectDjangoPlugin.PreferencesKey)


class ProjectDjangoPlugin(QObject):
    """
    Class implementing the Django project plugin.
    """

    PreferencesKey = "Django"

    lexerAssociations = {
        "*.htm": "Pygments|HTML+Django/Jinja",
        "*.html": "Pygments|HTML+Django/Jinja",
    }

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

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

        self.__defaults = {
            "VirtualEnvironmentNamePy3": "",
            "Python3ConsoleType": "ipython",
            "ServerAddress": "",
            "RecentNumberApps": 10,
            "UseIPv6": False,
            "UseThreading": True,
            "TranslationsEditor": "",
            "FuzzyTranslations": False,
            "UseExternalBrowser": False,
            "CheckDeployMode": False,
            "RecentNumberTestData": 10,
            "KeepTestDatabase": False,
            "RecentNumberDatabaseNames": 10,
        }
        if isWindowsPlatform():
            self.__defaults["ConsoleCommandNoClose"] = "cmd.exe /k"
            self.__defaults["ConsoleCommand"] = "cmd.exe /c"
        elif isMacPlatform():
            self.__defaults["ConsoleCommandNoClose"] = "xterm -hold -e"
            self.__defaults["ConsoleCommand"] = "xterm -e"
        else:
            self.__defaults["ConsoleCommandNoClose"] = "konsole --noclose -e"
            self.__defaults["ConsoleCommand"] = "konsole -e"

        self.__translator = None
        self.__loadTranslator()

    def __initialize(self):
        """
        Private slot to (re)initialize the plugin.
        """
        self.__object = None

        self.__mainMenu = None
        self.__mainAct = None
        self.__separatorAct = None

        self.__ericProject = ericApp().getObject("Project")

        self.__supportedVariants = []

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

        @return tuple of None and activation status
        @rtype bool
        """
        global djangoPluginObject
        djangoPluginObject = self

        usesDarkPalette = ericApp().usesDarkPalette()
        iconSuffix = "dark" if usesDarkPalette else "light"

        self.__object = Project(self, iconSuffix, self.__ui)
        self.__object.initActions()
        ericApp().registerPluginObject("ProjectDjango", self.__object)

        self.__mainMenu = self.__object.initMenu()

        self.__supportedVariants = self.__object.supportedPythonVariants()

        if self.__supportedVariants:
            self.__ericProject.registerProjectType(
                "Django",
                self.tr("Django"),
                self.fileTypesCallback,
                lexerAssociationCallback=self.lexerAssociationCallback,
                binaryTranslationsCallback=self.binaryTranslationsCallback,
                progLanguages=self.__supportedVariants[:],
            )

        Preferences.setProjectBrowsersDefault(
            "Django",
            ("sources", "forms", "translations", "others"),
        )

        if self.__ericProject.isOpen():
            self.__projectOpened()
            self.__object.projectOpenedHooks()

        ericApp().getObject("Project").projectOpened.connect(self.__projectOpened)
        ericApp().getObject("Project").projectClosed.connect(self.__projectClosed)
        ericApp().getObject("Project").newProject.connect(self.__projectOpened)

        ericApp().getObject("Project").projectOpenedHooks.connect(
            self.__object.projectOpenedHooks
        )
        ericApp().getObject("Project").projectClosedHooks.connect(
            self.__object.projectClosedHooks
        )
        ericApp().getObject("Project").newProjectHooks.connect(
            self.__object.projectOpenedHooks
        )

        ericApp().getObject("Project").projectAboutToBeCreated.connect(
            self.__object.startProjectOrApplication
        )
        ericApp().getObject("Project").newProject.connect(
            self.__object.newProjectCreated
        )

        return None, True

    def deactivate(self):
        """
        Public method to deactivate this plugin.
        """
        ericApp().unregisterPluginObject("ProjectDjango")

        ericApp().getObject("Project").projectOpened.disconnect(self.__projectOpened)
        ericApp().getObject("Project").projectClosed.disconnect(self.__projectClosed)
        ericApp().getObject("Project").newProject.disconnect(self.__projectOpened)

        ericApp().getObject("Project").projectOpenedHooks.disconnect(
            self.__object.projectOpenedHooks
        )
        ericApp().getObject("Project").projectClosedHooks.disconnect(
            self.__object.projectClosedHooks
        )
        ericApp().getObject("Project").newProjectHooks.disconnect(
            self.__object.projectOpenedHooks
        )

        ericApp().getObject("Project").projectAboutToBeCreated.disconnect(
            self.__object.startProjectOrApplication
        )
        ericApp().getObject("Project").newProject.disconnect(
            self.__object.newProjectCreated
        )

        self.__ericProject.unregisterProjectType("Django")

        self.__object.projectClosedHooks()
        self.__projectClosed()

        self.__initialize()

    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__), "ProjectDjango", "i18n"
                )
                translation = "django_{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 __projectOpened(self):
        """
        Private slot to handle the projectOpened signal.
        """
        if self.__ericProject.getProjectType() == "Django":
            projectToolsMenu = self.__ui.getMenu("project_tools")
            insertBeforeAct = projectToolsMenu.actions()[0]
            self.__mainAct = projectToolsMenu.insertMenu(
                insertBeforeAct, self.__mainMenu
            )
            self.__separatorAct = projectToolsMenu.insertSeparator(insertBeforeAct)

    def __projectClosed(self):
        """
        Private slot to handle the projectClosed signal.
        """
        if self.__mainAct is not None:
            projectToolsMenu = self.__ui.getMenu("project_tools")
            projectToolsMenu.removeAction(self.__separatorAct)
            projectToolsMenu.removeAction(self.__mainAct)
            self.__mainAct = None
            self.__separatorAct = None
            self.__object.projectClosed()

    def fileTypesCallback(self):
        """
        Public method get the filetype associations of the Django project type.

        @return dictionary with file type associations
        @rtype dict
        """
        fileTypes = (
            {
                "*.html": "FORMS",
                "*.htm": "FORMS",
                "*.js": "SOURCES",
                "*.pot": "TRANSLATIONS",
                "*.po": "TRANSLATIONS",
                "*.mo": "TRANSLATIONS",
                "*.py": "SOURCES",
            }
            if self.__ericProject.getProjectType() == "Django"
            else {}
        )
        return fileTypes

    def lexerAssociationCallback(self, filename):
        """
        Public method to get the lexer association of the Django project type
        for a file.

        @param filename name of the file
        @type str
        @return name of the lexer (Pygments lexers are prefixed with
            'Pygments|')
        @rtype str
        """
        for pattern, language in self.lexerAssociations.items():
            if fnmatch.fnmatch(filename, pattern):
                return language

        return ""

    def binaryTranslationsCallback(self, filename):
        """
        Public method to determine the filename of a compiled translation file
        given the translation source file.

        @param filename name of the translation source file
        @type str
        @return name of the binary translation file
        @rtype str
        """
        if filename.endswith(".po"):
            filename = filename.replace(".po", ".mo")
        return filename

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

        @param key the key of the value to get
        @type str
        @return value of the requested setting
        @rtype Any
        """
        if key in ["RecentNumberApps", "RecentNumberTestData"]:
            return int(
                Preferences.Prefs.settings.value(
                    self.PreferencesKey + "/" + key, self.__defaults[key]
                )
            )
        elif key in [
            "UseIPv6",
            "UseThreading",
            "UseExternalBrowser",
            "CheckDeployMode",
            "KeepTestDatabase",
            "FuzzyTranslations",
        ]:
            return Preferences.toBool(
                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 the key of the setting to be set
        @type str
        @param value value to be set
        @type Any
        """
        Preferences.Prefs.settings.setValue(self.PreferencesKey + "/" + key, value)

        if key in ["VirtualEnvironmentNamePy3"]:
            self.__reregisterProjectType()
        elif key == "TranslationsEditor" and self.__object:
            self.__object.registerOpenHook()

    def __reregisterProjectType(self):
        """
        Private method to re-register the project type.
        """
        supportedVariants = self.__object.supportedPythonVariants()
        if supportedVariants != self.__supportedVariants:
            # step 1: unregister
            self.__ericProject.unregisterProjectType("Django")

            # step 2: register again with new language settings
            self.__supportedVariants = supportedVariants
            if self.__supportedVariants:
                self.__ericProject.registerProjectType(
                    "Django",
                    self.tr("Django"),
                    self.fileTypesCallback,
                    lexerAssociationCallback=self.lexerAssociationCallback,
                    binaryTranslationsCallback=self.binaryTranslationsCallback,
                    progLanguages=self.__supportedVariants[:],
                )

    def getMenu(self, name):
        """
        Public method to get a reference to the requested menu.

        @param name name of the menu
        @type str
        @return reference to the menu or None, if no menu with the given name exists
        @rtype QMenu
        """
        if self.__object is not None:
            return self.__object.getMenu(name)
        else:
            return None

    def getMenuNames(self):
        """
        Public method to get the names of all menus.

        @return menu names
        @rtype list of str
        """
        if self.__object is not None:
            return list(self.__menus.keys())
        else:
            return []


#
# eflag: noqa = M801, U200

eric ide

mercurial