diff -r d6557db39585 -r 6cc80e4db8a7 PluginProjectFlask.py --- 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