PluginProjectFlask.py

changeset 2
6cc80e4db8a7
parent 0
6cd192942503
child 6
d491ccab7343
--- a/PluginProjectFlask.py	Sun Nov 08 17:53:06 2020 +0100
+++ b/PluginProjectFlask.py	Sun Nov 08 17:54:22 2020 +0100
@@ -0,0 +1,461 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2020 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing the Flask project plugin.
+"""
+
+import os
+import glob
+import fnmatch
+
+from PyQt5.QtCore import QCoreApplication, QObject, QTranslator
+
+from E5Gui.E5Application import e5App
+
+import Preferences
+
+from Globals import isWindowsPlatform, isMacPlatform
+
+from ProjectFlask.Project import Project
+
+# Start-of-Header
+name = "Flask Project Plugin"
+author = "Detlev Offenbach <detlev@die-offenbachs.de>"
+autoactivate = True
+deactivateable = True
+version = "1.0.0"
+className = "ProjectFlaskPlugin"
+packageName = "ProjectFlask"
+shortDescription = "Project support for Flask projects."
+longDescription = (
+    """This plugin implements project support for Flask projects."""
+)
+needsRestart = False
+pyqtApi = 2
+# End-of-Header
+
+error = ""
+
+flaskPluginObject = None
+
+
+def apiFiles(language):
+    """
+    Module function to return the API files made available by this plugin.
+    
+    @param language language to get APIs for (string)
+    @return list of API filenames (list of string)
+    """
+    if language in ["Python3"]:
+        apisDir = os.path.join(os.path.dirname(__file__),
+                               "ProjectFlask", "APIs")
+        apis = glob.glob(os.path.join(apisDir, '*.api'))
+    else:
+        apis = []
+    return apis
+
+
+def createFlaskPage(configDlg):
+    """
+    Module function to create the Flask configuration page.
+    
+    @param configDlg reference to the configuration dialog
+    @return reference to the configuration page
+    """
+    global flaskPluginObject
+    from ProjectFlask.ConfigurationPage.FlaskPage import FlaskPage
+    page = FlaskPage(flaskPluginObject)
+    return page
+
+
+def getConfigData():
+    """
+    Module function returning data as required by the configuration dialog.
+    
+    @return dictionary containing the relevant data
+    @rtype dict
+    """
+    try:
+        usesDarkPalette = e5App().usesDarkPalette()
+    except AttributeError:
+        from PyQt5.QtGui import QPalette
+        palette = e5App().palette()
+        lightness = palette.color(QPalette.Window).lightness()
+        usesDarkPalette = lightness <= 128
+    if usesDarkPalette:
+        iconSuffix = "dark"
+    else:
+        iconSuffix = "light"
+    
+    return {
+        "flaskPage": [
+            QCoreApplication.translate("ProjectFlaskPlugin", "Flask"),
+            os.path.join("ProjectFlask", "icons",
+                         "flask-{0}".format(iconSuffix)),
+            createFlaskPage, None, None],
+    }
+
+
+def prepareUninstall():
+    """
+    Module function to prepare for an uninstallation.
+    """
+    Preferences.removeProjectBrowserFlags(ProjectFlaskPlugin.PreferencesKey)
+    Preferences.Prefs.settings.remove(ProjectFlaskPlugin.PreferencesKey)
+    Preferences.Prefs.rsettings.remove(ProjectFlaskPlugin.PreferencesKey)
+
+
+class ProjectFlaskPlugin(QObject):
+    """
+    Class implementing the Flask project plugin.
+    """
+    PreferencesKey = "Flask"
+    
+    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 UI.UserInterface
+        """
+        QObject.__init__(self, ui)
+        self.__ui = ui
+        self.__initialize()
+        
+        self.__defaults = {
+            "VirtualEnvironmentNamePy3": "",
+            
+            "FlaskDocUrl": "https://flask.palletsprojects.com",
+#            "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.__e5project = e5App().getObject("Project")
+        
+        self.__supportedVariants = []
+    
+    def activate(self):
+        """
+        Public method to activate this plugin.
+        
+        @return tuple of None and activation status
+        @rtype bool
+        """
+        global flaskPluginObject
+        flaskPluginObject = self
+        
+        try:
+            usesDarkPalette = e5App().usesDarkPalette()
+        except AttributeError:
+            from PyQt5.QtGui import QPalette
+            palette = e5App().palette()
+            lightness = palette.color(QPalette.Window).lightness()
+            usesDarkPalette = lightness <= 128
+        if usesDarkPalette:
+            iconSuffix = "dark"
+        else:
+            iconSuffix = "light"
+        
+        self.__object = Project(self, iconSuffix, self.__ui)
+        self.__object.initActions()
+        e5App().registerPluginObject("ProjectFlask", self.__object)
+        
+        self.__mainMenu = self.__object.initMenu()
+        
+        self.__supportedVariants = self.__object.supportedPythonVariants()
+        
+        if self.__supportedVariants:
+            self.__e5project.registerProjectType(
+                "Flask", self.tr("Flask"),
+                self.fileTypesCallback,
+                lexerAssociationCallback=self.lexerAssociationCallback,
+#                binaryTranslationsCallback=self.binaryTranslationsCallback,
+                progLanguages=self.__supportedVariants[:])
+        
+        from Project.ProjectBrowser import (
+            SourcesBrowserFlag, FormsBrowserFlag, TranslationsBrowserFlag,
+            OthersBrowserFlag
+        )
+        Preferences.setProjectBrowserFlagsDefault(
+            "Flask",
+            SourcesBrowserFlag | FormsBrowserFlag |
+            TranslationsBrowserFlag | OthersBrowserFlag,
+        )
+        
+        if self.__e5project.isOpen():
+            self.__projectOpened()
+#            self.__object.projectOpenedHooks()
+        
+        e5App().getObject("Project").projectOpened.connect(
+            self.__projectOpened)
+        e5App().getObject("Project").projectClosed.connect(
+            self.__projectClosed)
+        e5App().getObject("Project").newProject.connect(
+            self.__projectOpened)
+#        
+#        e5App().getObject("Project").projectOpenedHooks.connect(
+#            self.__object.projectOpenedHooks)
+#        e5App().getObject("Project").projectClosedHooks.connect(
+#            self.__object.projectClosedHooks)
+#        e5App().getObject("Project").newProjectHooks.connect(
+#            self.__object.projectOpenedHooks)
+        
+        return None, True
+    
+    def deactivate(self):
+        """
+        Public method to deactivate this plugin.
+        """
+        e5App().unregisterPluginObject("ProjectFlask")
+        
+        e5App().getObject("Project").projectOpened.disconnect(
+            self.__projectOpened)
+        e5App().getObject("Project").projectClosed.disconnect(
+            self.__projectClosed)
+        e5App().getObject("Project").newProject.disconnect(
+            self.__projectOpened)
+#        
+#        e5App().getObject("Project").projectOpenedHooks.disconnect(
+#            self.__object.projectOpenedHooks)
+#        e5App().getObject("Project").projectClosedHooks.disconnect(
+#            self.__object.projectClosedHooks)
+#        e5App().getObject("Project").newProjectHooks.disconnect(
+#            self.__object.projectOpenedHooks)
+        
+        self.__e5project.unregisterProjectType("Flask")
+        
+#        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__), "ProjectFlask", "i18n")
+                translation = "flask_{0}".format(loc)
+                translator = QTranslator(None)
+                loaded = translator.load(translation, locale_dir)
+                if loaded:
+                    self.__translator = translator
+                    e5App().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.__e5project.getProjectType() == "Flask":
+            projectToolsMenu = self.__ui.getMenu("project_tools")
+            if projectToolsMenu is not None:
+                insertBeforeAct = projectToolsMenu.actions()[0]
+                self.__mainAct = projectToolsMenu.insertMenu(
+                    insertBeforeAct, self.__mainMenu)
+                self.__separatorAct = projectToolsMenu.insertSeparator(
+                    insertBeforeAct)
+            else:
+                projectAct = self.__ui.getMenuBarAction("project")
+                actions = self.__ui.menuBar().actions()
+                insertBeforeAct = actions[actions.index(projectAct) + 1]
+                self.__mainAct = self.__ui.menuBar().insertMenu(
+                    insertBeforeAct, self.__mainMenu)
+    
+    def __projectClosed(self):
+        """
+        Private slot to handle the projectClosed signal.
+        """
+        if self.__mainAct is not None:
+            projectToolsMenu = self.__ui.getMenu("project_tools")
+            if projectToolsMenu is not None:
+                projectToolsMenu.removeAction(self.__separatorAct)
+                projectToolsMenu.removeAction(self.__mainAct)
+                self.__mainAct = None
+                self.__separatorAct = None
+            else:
+                self.__ui.menuBar().removeAction(self.__mainAct)
+                self.__mainAct = 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
+        """
+        if self.__e5project.getProjectType() == "Flask":
+            fileTypes = {
+                "*.py": "SOURCES",
+                "*.js": "SOURCES",
+                "*.html": "FORMS",
+                "*.htm": "FORMS",
+                "*.pot": "TRANSLATIONS",
+                "*.po": "TRANSLATIONS",
+                "*.mo": "TRANSLATIONS",
+            }
+        else:
+            fileTypes = {}
+        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 getDefaultPreference(self, key):
+        """
+        Public method to get the default value for a setting.
+        
+        @param key the key of the value to get
+        @type str
+        @return the requested setting
+        @rtype any
+        """
+        return self.__defaults[key]
+    
+    def getPreferences(self, key):
+        """
+        Public method to retrieve the various settings.
+        
+        @param key the key of the value to get
+        @type str
+        @return the requested setting
+        @rtype any
+        """
+        if key in ["UseExternalBrowser"]:
+            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 the value to be set
+        @type any
+        """
+        Preferences.Prefs.settings.setValue(
+            self.PreferencesKey + "/" + key, value)
+        
+        if key in ["VirtualEnvironmentNamePy3"]:
+            self.__reregisterProjectType()
+    
+    def __reregisterProjectType(self):
+        """
+        Private method to re-register the project type.
+        """
+        supportedVariants = self.__object.supportedPythonVariants()
+        if supportedVariants != self.__supportedVariants:
+            # step 1: unregister
+            self.__e5project.unregisterProjectType("Flask")
+            
+            # step 2: register again with new language settings
+            self.__supportedVariants = supportedVariants
+            if self.__supportedVariants:
+                self.__e5project.registerProjectType(
+                    "Flask",
+                    self.tr("Pyramid"), 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 or None
+        """
+        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

eric ide

mercurial