Sat, 31 Dec 2022 16:27:49 +0100
Updated copyright for 2023.
# -*- coding: utf-8 -*- # Copyright (c) 2020 - 2023 Detlev Offenbach <detlev@die-offenbachs.de> # """ Module implementing the Flask 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 isMacPlatform, isWindowsPlatform from ProjectFlask.Project import Project # Start-of-Header name = "Flask Project Plugin" author = "Detlev Offenbach <detlev@die-offenbachs.de>" autoactivate = True deactivateable = True version = "10.4.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 @type str @return list of API filenames @rtype list of str """ 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 @type ConfigurationWidget @return reference to the configuration page @rtype FlaskPage """ 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 """ usesDarkPalette = ericApp().usesDarkPalette() iconSuffix = "dark" if usesDarkPalette else "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. """ try: Preferences.removeProjectBrowsers(ProjectFlaskPlugin.PreferencesKey) except AttributeError: # backward compatibility for eric7 < 22.12 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 UserInterface """ QObject.__init__(self, ui) self.__ui = ui self.__initialize() self.__defaults = { "VirtualEnvironmentNamePy3": "", "FlaskDocUrl": "https://flask.palletsprojects.com", "TranslationsEditor": "", "UseExternalBrowser": False, } if isWindowsPlatform(): self.__defaults["AnsiColorScheme"] = "Windows 10" self.__defaults["ConsoleCommand"] = "cmd.exe /c" elif isMacPlatform(): self.__defaults["AnsiColorScheme"] = "xterm" self.__defaults["ConsoleCommand"] = "xterm -e" else: self.__defaults["AnsiColorScheme"] = "Ubuntu" 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 tuple of (None, bool) """ global flaskPluginObject flaskPluginObject = self usesDarkPalette = ericApp().usesDarkPalette() iconSuffix = "dark" if usesDarkPalette else "light" self.__object = Project(self, iconSuffix, self.__ui) self.__object.initActions() ericApp().registerPluginObject("ProjectFlask", self.__object) self.__mainMenu = self.__object.initMenu() self.__supportedVariants = self.__object.supportedPythonVariants() if self.__supportedVariants: self.__ericProject.registerProjectType( "Flask", self.tr("Flask"), self.fileTypesCallback, lexerAssociationCallback=self.lexerAssociationCallback, binaryTranslationsCallback=self.binaryTranslationsCallback, progLanguages=self.__supportedVariants[:], ) try: # backward compatibility for eric7 < 22.12 from eric7.Project.ProjectBrowser import ( FormsBrowserFlag, OthersBrowserFlag, SourcesBrowserFlag, TranslationsBrowserFlag, ) Preferences.setProjectBrowserFlagsDefault( "Flask", SourcesBrowserFlag | FormsBrowserFlag | TranslationsBrowserFlag | OthersBrowserFlag, ) except ImportError: Preferences.setProjectBrowsersDefault( "Flask", ("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 ) return None, True def deactivate(self): """ Public method to deactivate this plugin. """ ericApp().unregisterPluginObject("ProjectFlask") 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 ) self.__ericProject.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 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() == "Flask": 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 = ( { "*.py": "SOURCES", "*.js": "SOURCES", "*.html": "FORMS", "*.htm": "FORMS", "*.pot": "TRANSLATIONS", "*.po": "TRANSLATIONS", "*.mo": "TRANSLATIONS", } if self.__ericProject.getProjectType() == "Flask" 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"): return filename.replace(".po", ".mo") return filename 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.__ericProject.unregisterProjectType("Flask") # step 2: register again with new language settings self.__supportedVariants = supportedVariants if self.__supportedVariants: self.__ericProject.registerProjectType( "Flask", self.tr("Flask"), 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