Sun, 08 Nov 2020 17:54:22 +0100
Added code for the basic project support.
--- a/.hgignore Sun Nov 08 17:53:06 2020 +0100 +++ b/.hgignore Sun Nov 08 17:54:22 2020 +0100 @@ -11,3 +11,4 @@ glob:tmp glob:__pycache__ glob:**.DS_Store +glob:Ui_*.py
--- a/PluginFlask.e4p Sun Nov 08 17:53:06 2020 +0100 +++ b/PluginFlask.e4p Sun Nov 08 17:54:22 2020 +0100 @@ -11,14 +11,27 @@ <Version>1.x</Version> <Author>Detlev Offenbach</Author> <Email>detlev@die-offenbachs.de</Email> - <TranslationPattern>ProjectDjango/i18n/flask_%language%.ts</TranslationPattern> + <TranslationPattern>ProjectFlask/i18n/flask_%language%.ts</TranslationPattern> <Eol index="1"/> <Sources> <Source>PluginProjectFlask.py</Source> + <Source>ProjectFlask/ConfigurationPage/FlaskPage.py</Source> + <Source>ProjectFlask/ConfigurationPage/__init__.py</Source> + <Source>ProjectFlask/Project.py</Source> + <Source>ProjectFlask/__init__.py</Source> <Source>__init__.py</Source> </Sources> + <Forms> + <Form>ProjectFlask/ConfigurationPage/FlaskPage.ui</Form> + </Forms> <Others> <Other>.hgignore</Other> + <Other>PluginFlask.e4p</Other> + <Other>ProjectFlask/APIs</Other> + <Other>ProjectFlask/icons/flask-dark.svg</Other> + <Other>ProjectFlask/icons/flask-light.svg</Other> + <Other>ProjectFlask/icons/flask64-dark.svg</Other> + <Other>ProjectFlask/icons/flask64-light.svg</Other> </Others> <MainScript>PluginProjectFlask.py</MainScript> <Vcs> @@ -143,6 +156,7 @@ <FiletypeAssociation pattern="Makefile" type="OTHERS"/> <FiletypeAssociation pattern="README" type="OTHERS"/> <FiletypeAssociation pattern="README.*" type="OTHERS"/> + <FiletypeAssociation pattern="Ui_*.py" type="__IGNORE__"/> <FiletypeAssociation pattern="makefile" type="OTHERS"/> </FiletypeAssociations> </Project>
--- 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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ProjectFlask/ConfigurationPage/FlaskPage.py Sun Nov 08 17:54:22 2020 +0100 @@ -0,0 +1,98 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2020 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing the Flask configuration page. +""" + +from PyQt5.QtCore import pyqtSlot + +from E5Gui.E5Application import e5App + +from Preferences.ConfigurationPages.ConfigurationPageBase import ( + ConfigurationPageBase +) +from .Ui_FlaskPage import Ui_FlaskPage + +import UI.PixmapCache + + +class FlaskPage(ConfigurationPageBase, Ui_FlaskPage): + """ + Class implementing the Flask configuration page. + """ + def __init__(self, plugin): + """ + Constructor + + @param plugin reference to the plugin object + """ + super(FlaskPage, self).__init__() + self.setupUi(self) + self.setObjectName("FlaskPage") + + self.__plugin = plugin + + self.urlResetButton.setIcon( + UI.PixmapCache.getIcon("editUndo")) + self.py3VenvNamesReloadButton.setIcon( + UI.PixmapCache.getIcon("reload")) + + venvManager = e5App().getObject("VirtualEnvManager") + self.py3VenvNameComboBox.addItems( + [""] + sorted(venvManager.getVirtualenvNames())) + + # set initial values + self.externalBrowserCheckBox.setChecked( + self.__plugin.getPreferences("UseExternalBrowser")) + + venvName = self.__plugin.getPreferences( + "VirtualEnvironmentNamePy3") + if venvName: + index = self.py3VenvNameComboBox.findText(venvName) + if index < 0: + index = 0 + self.py3VenvNameComboBox.setCurrentIndex(index) + + self.urlEdit.setText( + self.__plugin.getPreferences("FlaskDocUrl")) + + def save(self): + """ + Public slot to save the Flask configuration. + """ + self.__plugin.setPreferences( + "UseExternalBrowser", self.externalBrowserCheckBox.isChecked()) + + self.__plugin.setPreferences( + "VirtualEnvironmentNamePy3", + self.py3VenvNameComboBox.currentText()) + + self.__plugin.setPreferences( + "FlaskDocUrl", self.urlEdit.text()) + + @pyqtSlot() + def on_py3VenvNamesReloadButton_clicked(self): + """ + Private slot to reload the virtual environment names. + """ + currentVenvName = self.py3VenvNameComboBox.currentText() + self.py3VenvNameComboBox.clear() + venvManager = e5App().getObject("VirtualEnvManager") + self.py3VenvNameComboBox.addItems( + [""] + sorted(venvManager.getVirtualenvNames())) + if currentVenvName: + index = self.py3VenvNameComboBox.findText(currentVenvName) + if index < 0: + index = 0 + self.py3VenvNameComboBox.setCurrentIndex(index) + + @pyqtSlot() + def on_urlResetButton_clicked(self): + """ + Private slot to reset the Flask documentation URL. + """ + self.urlEdit.setText( + self.__plugin.getDefaultPreference("FlaskDocUrl"))
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ProjectFlask/ConfigurationPage/FlaskPage.ui Sun Nov 08 17:54:22 2020 +0100 @@ -0,0 +1,133 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>FlaskPage</class> + <widget class="QWidget" name="FlaskPage"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>500</width> + <height>373</height> + </rect> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QLabel" name="headerLabel"> + <property name="text"> + <string><b>Configure Flask</b></string> + </property> + </widget> + </item> + <item> + <widget class="Line" name="line15"> + <property name="frameShape"> + <enum>QFrame::HLine</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Sunken</enum> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item> + <widget class="QGroupBox" name="flaskBrowserGroup"> + <property name="title"> + <string>Web-Browser</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_5"> + <item> + <widget class="QCheckBox" name="externalBrowserCheckBox"> + <property name="toolTip"> + <string>Select to use an external web-browser</string> + </property> + <property name="text"> + <string>Use external web-browser</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="flaskVirtualEnvironmentPy3Group"> + <property name="title"> + <string>Flak Virtual Environment</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QLabel" name="label_13"> + <property name="text"> + <string>Select the Virtual Environment to be used with Flask</string> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QComboBox" name="py3VenvNameComboBox"/> + </item> + <item> + <widget class="QToolButton" name="py3VenvNamesReloadButton"> + <property name="toolTip"> + <string>Press to reload the names of the virtual environments</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="flaskDocumentationGroup"> + <property name="title"> + <string>Pyramid Documentation</string> + </property> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QLabel" name="label_6"> + <property name="text"> + <string>URL:</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="urlEdit"> + <property name="toolTip"> + <string>Enter the URL of the Flask documentation</string> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="urlResetButton"> + <property name="toolTip"> + <string>Press to reset the URL to the default URL</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>64</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ProjectFlask/ConfigurationPage/__init__.py Sun Nov 08 17:54:22 2020 +0100 @@ -0,0 +1,8 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2020 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Package implementing the Flask page of the configuration dialog. +"""
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ProjectFlask/Project.py Sun Nov 08 17:54:22 2020 +0100 @@ -0,0 +1,319 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2020 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing the Flask project support. +""" + +import os + +from PyQt5.QtCore import pyqtSlot, QObject, QProcess, QTimer +from PyQt5.QtWidgets import QMenu + +from E5Gui import E5MessageBox +from E5Gui.E5Action import E5Action +from E5Gui.E5Application import e5App + +from Globals import isWindowsPlatform + +import UI.PixmapCache +import Utilities + + +class Project(QObject): + """ + Class implementing the Flask project support. + """ + def __init__(self, plugin, iconSuffix, parent=None): + """ + Constructor + + @param plugin reference to the plugin object + @type ProjectFlaskPlugin + @param iconSuffix suffix for the icons + @type str + @param parent parent + @type QObject + """ + super(Project, self).__init__(parent) + + self.__plugin = plugin + self.__iconSuffix = iconSuffix + self.__ui = parent + + self.__e5project = e5App().getObject("Project") + self.__virtualEnvManager = e5App().getObject("VirtualEnvManager") + + self.__menus = {} # dictionary with references to menus + + self.__serverProc = None + + self.__flaskVersions = { + "python": "", + "flask": "", + "werkzeug": "", + } + + def initActions(self): + """ + Public method to define the Flask actions. + """ + self.actions = [] + + ############################## + ## about action below ## + ############################## + + self.aboutFlaskAct = E5Action( + self.tr('About Flask'), + self.tr('About &Flask'), + 0, 0, + self, 'flask_about') + self.aboutFlaskAct.setStatusTip(self.tr( + 'Shows some information about Flask')) + self.aboutFlaskAct.setWhatsThis(self.tr( + """<b>About Flask</b>""" + """<p>Shows some information about Flask.</p>""" + )) + self.aboutFlaskAct.triggered.connect(self.__flaskInfo) + self.actions.append(self.aboutFlaskAct) + + def initMenu(self): + """ + Public method to initialize the Flask menu. + + @return the menu generated + @rtype QMenu + """ + self.__menus = {} # clear menus references + + menu = QMenu(self.tr('&Flask'), self.__ui) + menu.setTearOffEnabled(True) + + menu.addAction(self.aboutFlaskAct) + + self.__menus["main"] = menu + + return menu + + 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 name in self.__menus: + return self.__menus[name] + else: + return None + + def getMenuNames(self): + """ + Public method to get the names of all menus. + + @return menu names + @rtype list of str + """ + return list(self.__menus.keys()) + + ################################################################## + ## slots below implement general functionality + ################################################################## + + def projectClosed(self): + """ + Public method to handle the closing of a project. + """ + if self.__serverProc is not None: + self.__serverProcFinished() + + # TODO: implement this correctly + def supportedPythonVariants(self): + """ + Public method to get the supported Python variants. + + @return list of supported Python variants + @rtype list of str + """ + variants = [] + + virtEnv = self.__getVirtualEnvironment() + if virtEnv: + fullCmd = self.getFlaskCommand() + if fullCmd: + variants.append("Python3") + else: + fullCmd = self.getFlaskCommand() + if isWindowsPlatform(): + if fullCmd: + variants.append("Python3") + else: + fullCmds = Utilities.getExecutablePaths("flask") + for fullCmd in fullCmds: + try: + with open(fullCmd, 'r', encoding='utf-8') as f: + l0 = f.readline() + except (IOError, OSError): + l0 = "" + if self.__isSuitableForVariant("Python3", l0): + variants.append("Python3") + break + + return variants + + def __isSuitableForVariant(self, variant, line0): + """ + Private method to test, if a detected command file is suitable for the + given Python variant. + + @param variant Python variant to test for + @type str + @param line0 first line of the executable + @type str + @return flag indicating a suitable file was found + @rtype bool + """ + l0 = line0.lower() + ok = (variant.lower() in l0 or + "{0}.".format(variant[-1]) in l0) + ok |= "pypy3" in l0 + + return ok + + def __getVirtualEnvironment(self): + """ + Private method to get the path of the virtual environment. + + @return path of the virtual environment + @rtype str + """ + language = self.__e5project.getProjectLanguage() + if language == "Python3": + venvName = self.__plugin.getPreferences( + "VirtualEnvironmentNamePy3") + else: + venvName = "" + if venvName: + virtEnv = self.__virtualEnvManager.getVirtualenvDirectory( + venvName) + else: + virtEnv = "" + + if virtEnv and not os.path.exists(virtEnv): + virtEnv = "" + + return virtEnv # __IGNORE_WARNING_M834__ + + def getFlaskCommand(self): + """ + Public method to build the Flask command. + + @return full flask command + @rtype str + """ + cmd = "flask" + + virtualEnv = self.__getVirtualEnvironment() + if isWindowsPlatform(): + fullCmds = [ + os.path.join(virtualEnv, "Scripts", cmd + '.exe'), + os.path.join(virtualEnv, "bin", cmd + '.exe'), + cmd # fall back to just cmd + ] + for cmd in fullCmds: + if os.path.exists(cmd): + break + else: + fullCmds = [ + os.path.join(virtualEnv, "bin", cmd), + os.path.join(virtualEnv, "local", "bin", cmd), + Utilities.getExecutablePath(cmd), + cmd # fall back to just cmd + ] + for cmd in fullCmds: + if os.path.exists(cmd): + break + return cmd + + @pyqtSlot() + def __flaskInfo(self): + """ + Private slot to show some info about Flask. + """ + versions = self.getFlaskVersionStrings() + url = "https://flask.palletsprojects.com" + + msgBox = E5MessageBox.E5MessageBox( + E5MessageBox.Question, + self.tr("About Flask"), + self.tr( + "<p>Flask is a lightweight WSGI web application framework." + " It is designed to make getting started quick and easy," + " with the ability to scale up to complex applications.</p>" + "<p><table>" + "<tr><td>Flask Version:</td><td>{0}</td></tr>" + "<tr><td>Werkzeug Version:</td><td>{1}</td></tr>" + "<tr><td>Python Version:</td><td>{2}</td></tr>" + "<tr><td>Flask URL:</td><td><a href=\"{3}\">" + "{3}</a></td></tr>" + "</table></p>" + ).format(versions["flask"], versions["werkzeug"], + versions["python"], url), + modal=True, + buttons=E5MessageBox.Ok) + msgBox.setIconPixmap(UI.PixmapCache.getPixmap( + os.path.join("ProjectFlask", "icons", + "flask64-{0}".format(self.__iconSuffix)))) + msgBox.exec() + + def getFlaskVersionStrings(self): + """ + Public method to get the Flask, Werkzeug and Python versions as a + string. + + @return dictionary containing the Flask, Werkzeug and Python versions + @rtype dict + """ + if not self.__flaskVersions["flask"]: + cmd = self.getFlaskCommand() + proc = QProcess() + proc.start(cmd, ["--version"]) + if proc.waitForFinished(10000): + output = str(proc.readAllStandardOutput(), "utf-8") + for line in output.lower().splitlines(): + key, version = line.strip().split(None, 1) + self.__flaskVersions[key] = version + + return self.__flaskVersions + + ################################################################## + ## slots below implement run functions + ################################################################## + + def __runServer(self, logging=False): + """ + Private slot to start the Pyramid Web server. + + @param logging flag indicating to enable logging + @type bool + """ + # TODO: implement this + + def __serverProcFinished(self): + """ + Private slot connected to the finished signal. + """ + if ( + self.__serverProc is not None and + self.__serverProc.state() != QProcess.NotRunning + ): + self.__serverProc.terminate() + QTimer.singleShot(2000, self.__serverProc.kill) + self.__serverProc.waitForFinished(3000) + self.__serverProc = None
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ProjectFlask/__init__.py Sun Nov 08 17:54:22 2020 +0100 @@ -0,0 +1,8 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2020 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Package implementing project support for eric6 Flask projects. +"""
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ProjectFlask/icons/flask-dark.svg Sun Nov 08 17:54:22 2020 +0100 @@ -0,0 +1,172 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:osb="http://www.openswatchbook.org/uri/2009/osb" + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="22" + height="22" + id="svg2" + version="1.1" + inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)" + sodipodi:docname="flask-dark.svg"> + <defs + id="defs4"> + <linearGradient + id="linearGradient2322" + osb:paint="solid"> + <stop + style="stop-color:#000000;stop-opacity:1;" + offset="0" + id="stop2320" /> + </linearGradient> + <inkscape:perspective + sodipodi:type="inkscape:persp3d" + inkscape:vp_x="0 : 526.18109 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_z="744.09448 : 526.18109 : 1" + inkscape:persp3d-origin="372.04724 : 350.78739 : 1" + id="perspective10" /> + <inkscape:perspective + id="perspective2824" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <inkscape:perspective + id="perspective2840" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <inkscape:perspective + id="perspective2878" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <inkscape:perspective + id="perspective2894" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <inkscape:perspective + id="perspective2910" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <inkscape:perspective + id="perspective2926" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <inkscape:perspective + id="perspective2976" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <inkscape:perspective + id="perspective3020" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <inkscape:perspective + id="perspective3036" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <inkscape:perspective + id="perspective3052" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <inkscape:perspective + id="perspective3866" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="24.577155" + inkscape:cx="26.929966" + inkscape:cy="9.5499179" + inkscape:document-units="px" + inkscape:current-layer="layer1" + showgrid="false" + inkscape:window-width="2560" + inkscape:window-height="1377" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="1" + fit-margin-top="10" + fit-margin-left="10" + fit-margin-right="10" + fit-margin-bottom="10" /> + <metadata + id="metadata7"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(-29.820801,-188.71498)"> + <path + style="fill:#eff0f1;stroke:#232629;stroke-width:0.20519325;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;fill-opacity:1" + d="m 30.923396,195.74806 c 3.145523,-1.0064 2.468667,-0.9463 6.110325,-1.58477 0.871154,0.2475 2.349849,0.58367 2.28106,1.26197 -0.640202,0.23817 -1.574558,-0.66251 -2.077416,-0.15803 0.001,1.8906 0.611821,3.92047 1.38264,5.7213 0.770819,1.80084 1.936492,3.37264 3.516943,4.34706 2.094978,1.30012 4.299555,1.53282 6.528075,1.6067 0.68396,0.0244 1.775303,-0.15172 2.053185,0 -0.503838,0.89318 -1.977451,1.31486 -3.509599,1.50982 -1.532147,0.19497 -3.122831,0.16323 -3.860809,0.14956 -1.62967,-0.0513 -3.035316,-0.27209 -4.314541,-0.74821 -3.300834,-1.33007 -5.168705,-4.00553 -6.580061,-6.92574 -0.810575,-1.70004 -1.372105,-3.48921 -1.529802,-5.17966 z" + id="path3826" + inkscape:connector-curvature="0" + sodipodi:nodetypes="ccccscccscccc" /> + <path + style="fill:#eff0f1;stroke:#232629;stroke-width:0.20519325;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;fill-opacity:1" + d="m 32.409908,191.27103 c -0.04381,0.0897 -0.03947,0.20507 -0.0029,0.2979 0.08019,0.2036 0.287169,0.33376 0.451026,0.48043 0.07471,0.0668 0.232755,0.0825 0.242494,0.18156 0.02208,0.22478 -0.277003,0.36603 -0.457053,0.50508 -0.135007,0.10429 -0.39442,0.0797 -0.456615,0.23752 -0.04282,0.10864 0.08588,0.21557 0.119784,0.32724 0.04778,0.15736 0.168456,0.32332 0.117539,0.4797 -0.06128,0.1882 -0.276932,0.29214 -0.4534,0.38531 -0.194166,0.10251 -0.456466,0.0511 -0.636685,0.17601 -0.171707,0.11903 -0.357539,0.29835 -0.364548,0.50551 -0.0032,0.094 -0.03944,0.27471 -0.02398,0.31958 1.319307,-0.42649 2.071305,-0.6679 2.943016,-0.88241 0.87171,-0.21451 1.652197,-0.34889 3.033831,-0.58391 -0.007,-0.0469 -0.122777,-0.19045 -0.169009,-0.27224 -0.101974,-0.18042 -0.349628,-0.2534 -0.556884,-0.27945 -0.217528,-0.0273 -0.426311,0.13965 -0.645844,0.13863 -0.199523,-9.2e-4 -0.438768,0.007 -0.580097,-0.13175 -0.117432,-0.11508 -0.08715,-0.31808 -0.117539,-0.47971 -0.02156,-0.1147 0.04311,-0.26907 -0.04508,-0.34557 -0.128078,-0.11109 -0.346725,0.0307 -0.514621,7.7e-4 -0.223911,-0.0399 -0.554373,-0.0267 -0.638703,-0.23625 -0.0372,-0.0924 0.09574,-0.17934 0.131059,-0.27321 0.07747,-0.20588 0.200808,-0.41708 0.177788,-0.6347 -0.0105,-0.0993 -0.05998,-0.20352 -0.14029,-0.26277 -0.172516,-0.12226 -0.447889,-0.13586 -0.772479,-0.0539 -0.324587,0.0819 -0.547919,0.21939 -0.640796,0.4007 z" + id="path3832" + inkscape:connector-curvature="0" + sodipodi:nodetypes="csssssscssscccssscssssssccc" /> + <path + style="fill:none;stroke:#232629;stroke-width:0.20519325;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;fill-opacity:1" + d="m 37.291027,195.21739 c 0,0 -2.518612,0.54167 -3.683949,0.87768 -0.826288,0.23825 -2.438425,0.84257 -2.438425,0.84257" + id="path3847" + inkscape:connector-curvature="0" + sodipodi:nodetypes="csc" /> + </g> +</svg>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ProjectFlask/icons/flask-light.svg Sun Nov 08 17:54:22 2020 +0100 @@ -0,0 +1,172 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:osb="http://www.openswatchbook.org/uri/2009/osb" + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="22" + height="22" + id="svg2" + version="1.1" + inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)" + sodipodi:docname="flask-light.svg"> + <defs + id="defs4"> + <linearGradient + id="linearGradient2322" + osb:paint="solid"> + <stop + style="stop-color:#000000;stop-opacity:1;" + offset="0" + id="stop2320" /> + </linearGradient> + <inkscape:perspective + sodipodi:type="inkscape:persp3d" + inkscape:vp_x="0 : 526.18109 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_z="744.09448 : 526.18109 : 1" + inkscape:persp3d-origin="372.04724 : 350.78739 : 1" + id="perspective10" /> + <inkscape:perspective + id="perspective2824" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <inkscape:perspective + id="perspective2840" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <inkscape:perspective + id="perspective2878" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <inkscape:perspective + id="perspective2894" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <inkscape:perspective + id="perspective2910" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <inkscape:perspective + id="perspective2926" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <inkscape:perspective + id="perspective2976" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <inkscape:perspective + id="perspective3020" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <inkscape:perspective + id="perspective3036" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <inkscape:perspective + id="perspective3052" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <inkscape:perspective + id="perspective3866" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="24.577155" + inkscape:cx="18.873704" + inkscape:cy="9.5499179" + inkscape:document-units="px" + inkscape:current-layer="layer1" + showgrid="false" + inkscape:window-width="2560" + inkscape:window-height="1377" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="1" + fit-margin-top="10" + fit-margin-left="10" + fit-margin-right="10" + fit-margin-bottom="10" /> + <metadata + id="metadata7"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(-29.820801,-188.71498)"> + <path + style="fill:#232629;stroke:#eff0f1;stroke-width:0.20519325;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;fill-opacity:1" + d="m 30.923396,195.74806 c 3.145523,-1.0064 2.468667,-0.9463 6.110325,-1.58477 0.871154,0.2475 2.349849,0.58367 2.28106,1.26197 -0.640202,0.23817 -1.574558,-0.66251 -2.077416,-0.15803 0.001,1.8906 0.611821,3.92047 1.38264,5.7213 0.770819,1.80084 1.936492,3.37264 3.516943,4.34706 2.094978,1.30012 4.299555,1.53282 6.528075,1.6067 0.68396,0.0244 1.775303,-0.15172 2.053185,0 -0.503838,0.89318 -1.977451,1.31486 -3.509599,1.50982 -1.532147,0.19497 -3.122831,0.16323 -3.860809,0.14956 -1.62967,-0.0513 -3.035316,-0.27209 -4.314541,-0.74821 -3.300834,-1.33007 -5.168705,-4.00553 -6.580061,-6.92574 -0.810575,-1.70004 -1.372105,-3.48921 -1.529802,-5.17966 z" + id="path3826" + inkscape:connector-curvature="0" + sodipodi:nodetypes="ccccscccscccc" /> + <path + style="fill:#232629;stroke:#eff0f1;stroke-width:0.20519325;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;fill-opacity:1" + d="m 32.409908,191.27103 c -0.04381,0.0897 -0.03947,0.20507 -0.0029,0.2979 0.08019,0.2036 0.287169,0.33376 0.451026,0.48043 0.07471,0.0668 0.232755,0.0825 0.242494,0.18156 0.02208,0.22478 -0.277003,0.36603 -0.457053,0.50508 -0.135007,0.10429 -0.39442,0.0797 -0.456615,0.23752 -0.04282,0.10864 0.08588,0.21557 0.119784,0.32724 0.04778,0.15736 0.168456,0.32332 0.117539,0.4797 -0.06128,0.1882 -0.276932,0.29214 -0.4534,0.38531 -0.194166,0.10251 -0.456466,0.0511 -0.636685,0.17601 -0.171707,0.11903 -0.357539,0.29835 -0.364548,0.50551 -0.0032,0.094 -0.03944,0.27471 -0.02398,0.31958 1.319307,-0.42649 2.071305,-0.6679 2.943016,-0.88241 0.87171,-0.21451 1.652197,-0.34889 3.033831,-0.58391 -0.007,-0.0469 -0.122777,-0.19045 -0.169009,-0.27224 -0.101974,-0.18042 -0.349628,-0.2534 -0.556884,-0.27945 -0.217528,-0.0273 -0.426311,0.13965 -0.645844,0.13863 -0.199523,-9.2e-4 -0.438768,0.007 -0.580097,-0.13175 -0.117432,-0.11508 -0.08715,-0.31808 -0.117539,-0.47971 -0.02156,-0.1147 0.04311,-0.26907 -0.04508,-0.34557 -0.128078,-0.11109 -0.346725,0.0307 -0.514621,7.7e-4 -0.223911,-0.0399 -0.554373,-0.0267 -0.638703,-0.23625 -0.0372,-0.0924 0.09574,-0.17934 0.131059,-0.27321 0.07747,-0.20588 0.200808,-0.41708 0.177788,-0.6347 -0.0105,-0.0993 -0.05998,-0.20352 -0.14029,-0.26277 -0.172516,-0.12226 -0.447889,-0.13586 -0.772479,-0.0539 -0.324587,0.0819 -0.547919,0.21939 -0.640796,0.4007 z" + id="path3832" + inkscape:connector-curvature="0" + sodipodi:nodetypes="csssssscssscccssscssssssccc" /> + <path + style="fill:none;stroke:#eff0f1;stroke-width:0.20519325;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;fill-opacity:1" + d="m 37.291027,195.21739 c 0,0 -2.518612,0.54167 -3.683949,0.87768 -0.826288,0.23825 -2.438425,0.84257 -2.438425,0.84257" + id="path3847" + inkscape:connector-curvature="0" + sodipodi:nodetypes="csc" /> + </g> +</svg>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ProjectFlask/icons/flask64-dark.svg Sun Nov 08 17:54:22 2020 +0100 @@ -0,0 +1,172 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:osb="http://www.openswatchbook.org/uri/2009/osb" + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="64" + height="64" + id="svg2" + version="1.1" + inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)" + sodipodi:docname="flask64-dark.svg"> + <defs + id="defs4"> + <linearGradient + id="linearGradient2322" + osb:paint="solid"> + <stop + style="stop-color:#000000;stop-opacity:1;" + offset="0" + id="stop2320" /> + </linearGradient> + <inkscape:perspective + sodipodi:type="inkscape:persp3d" + inkscape:vp_x="0 : 526.18109 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_z="744.09448 : 526.18109 : 1" + inkscape:persp3d-origin="372.04724 : 350.78739 : 1" + id="perspective10" /> + <inkscape:perspective + id="perspective2824" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <inkscape:perspective + id="perspective2840" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <inkscape:perspective + id="perspective2878" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <inkscape:perspective + id="perspective2894" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <inkscape:perspective + id="perspective2910" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <inkscape:perspective + id="perspective2926" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <inkscape:perspective + id="perspective2976" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <inkscape:perspective + id="perspective3020" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <inkscape:perspective + id="perspective3036" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <inkscape:perspective + id="perspective3052" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <inkscape:perspective + id="perspective3866" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="12.288577" + inkscape:cx="3.3305988" + inkscape:cy="22.365175" + inkscape:document-units="px" + inkscape:current-layer="layer1" + showgrid="false" + inkscape:window-width="2560" + inkscape:window-height="1377" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="1" + fit-margin-top="10" + fit-margin-left="10" + fit-margin-right="10" + fit-margin-bottom="10" /> + <metadata + id="metadata7"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(-29.820801,-146.71498)"> + <path + style="fill:#eff0f1;fill-opacity:1;stroke:#232629;stroke-width:0.6155774;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 32.128588,166.81452 c 9.436568,-3.01919 7.406001,-2.83889 18.330974,-4.75427 2.613463,0.74249 7.049548,1.75098 6.843181,3.78587 -1.920606,0.7145 -4.723674,-1.98751 -6.232249,-0.47409 0.003,5.67175 1.835464,11.76133 4.147921,17.16377 2.312457,5.40248 5.809476,10.11785 10.550829,13.04109 6.284933,3.90033 12.898666,4.59842 19.584225,4.82007 2.05188,0.0732 5.325909,-0.45517 6.159555,0 -1.511514,2.67951 -5.932353,3.94455 -10.528796,4.52942 -4.596443,0.5849 -9.368494,0.48969 -11.582429,0.44867 -4.88901,-0.1539 -9.105947,-0.81626 -12.943622,-2.24461 -9.902503,-3.99017 -15.506116,-12.01651 -19.740183,-20.77707 -2.431725,-5.10008 -4.116315,-10.46754 -4.589406,-15.53885 z" + id="path3826" + inkscape:connector-curvature="0" + sodipodi:nodetypes="ccccscccscccc" /> + <path + style="fill:#eff0f1;fill-opacity:1;stroke:#232629;stroke-width:0.6155774;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 36.588124,153.38352 c -0.13143,0.2691 -0.11841,0.61521 -0.0087,0.8937 0.24057,0.6108 0.861507,1.00127 1.353078,1.44128 0.22413,0.20039 0.698265,0.24749 0.727482,0.54467 0.06624,0.67434 -0.831009,1.09808 -1.371159,1.51523 -0.405021,0.31287 -1.18326,0.2391 -1.369845,0.71255 -0.12846,0.32592 0.25764,0.64672 0.359352,0.98172 0.14334,0.47207 0.505368,0.96995 0.352617,1.43908 -0.18384,0.5646 -0.830796,0.87642 -1.3602,1.15593 -0.582498,0.30752 -1.369398,0.15329 -1.910055,0.52802 -0.515121,0.35709 -1.072616,0.89504 -1.093644,1.51653 -0.0096,0.282 -0.11832,0.82412 -0.07194,0.95872 3.95792,-1.27946 6.213915,-2.00368 8.829047,-2.64721 2.61513,-0.64352 4.956591,-1.04666 9.101492,-1.75171 -0.021,-0.1407 -0.36833,-0.57135 -0.507026,-0.81672 -0.305922,-0.54124 -1.048884,-0.76019 -1.670652,-0.83834 -0.652584,-0.0819 -1.278933,0.41895 -1.937532,0.4159 -0.598569,-0.003 -1.316304,0.021 -1.740291,-0.39525 -0.352296,-0.34525 -0.26145,-0.95424 -0.352617,-1.43912 -0.06468,-0.3441 0.12933,-0.80721 -0.13524,-1.03671 -0.384234,-0.33327 -1.040175,0.0921 -1.543863,0.002 -0.671733,-0.1197 -1.663119,-0.0801 -1.916109,-0.70875 -0.1116,-0.2772 0.28722,-0.53802 0.393177,-0.81963 0.23241,-0.61763 0.602424,-1.25123 0.533364,-1.90408 -0.0315,-0.2979 -0.17994,-0.61056 -0.42087,-0.78831 -0.517548,-0.36677 -1.343667,-0.40757 -2.317437,-0.1617 -0.973761,0.2457 -1.643757,0.65817 -1.922388,1.20209 z" + id="path3832" + inkscape:connector-curvature="0" + sodipodi:nodetypes="csssssscssscccssscssssssccc" /> + <path + style="fill:none;fill-opacity:1;stroke:#232629;stroke-width:0.6155774;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 51.23148,165.22252 c 0,0 -7.555836,1.625 -11.051846,2.63301 -2.478864,0.71474 -7.315275,2.5277 -7.315275,2.5277" + id="path3847" + inkscape:connector-curvature="0" + sodipodi:nodetypes="csc" /> + </g> +</svg>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ProjectFlask/icons/flask64-light.svg Sun Nov 08 17:54:22 2020 +0100 @@ -0,0 +1,172 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:osb="http://www.openswatchbook.org/uri/2009/osb" + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="64" + height="64" + id="svg2" + version="1.1" + inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)" + sodipodi:docname="flask64-light.svg"> + <defs + id="defs4"> + <linearGradient + id="linearGradient2322" + osb:paint="solid"> + <stop + style="stop-color:#000000;stop-opacity:1;" + offset="0" + id="stop2320" /> + </linearGradient> + <inkscape:perspective + sodipodi:type="inkscape:persp3d" + inkscape:vp_x="0 : 526.18109 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_z="744.09448 : 526.18109 : 1" + inkscape:persp3d-origin="372.04724 : 350.78739 : 1" + id="perspective10" /> + <inkscape:perspective + id="perspective2824" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <inkscape:perspective + id="perspective2840" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <inkscape:perspective + id="perspective2878" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <inkscape:perspective + id="perspective2894" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <inkscape:perspective + id="perspective2910" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <inkscape:perspective + id="perspective2926" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <inkscape:perspective + id="perspective2976" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <inkscape:perspective + id="perspective3020" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <inkscape:perspective + id="perspective3036" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <inkscape:perspective + id="perspective3052" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <inkscape:perspective + id="perspective3866" + inkscape:persp3d-origin="0.5 : 0.33333333 : 1" + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="8.6893365" + inkscape:cx="1.3620805" + inkscape:cy="41.288557" + inkscape:document-units="px" + inkscape:current-layer="layer1" + showgrid="false" + inkscape:window-width="2560" + inkscape:window-height="1377" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="1" + fit-margin-top="10" + fit-margin-left="10" + fit-margin-right="10" + fit-margin-bottom="10" /> + <metadata + id="metadata7"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(-29.820801,-146.71498)"> + <path + style="fill:#232629;fill-opacity:1;stroke:#eff0f1;stroke-width:0.61557972;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 32.128589,166.81422 c 9.436568,-3.0192 7.406001,-2.8389 18.330974,-4.75431 2.613462,0.7425 7.049547,1.75101 6.84318,3.78591 -1.920606,0.71451 -4.723674,-1.98753 -6.232248,-0.47409 0.003,5.6718 1.835463,11.76141 4.14792,17.1639 2.312457,5.40252 5.809476,10.11792 10.550829,13.04118 6.284933,3.90036 12.898664,4.59846 19.584224,4.8201 2.05188,0.0732 5.325909,-0.45516 6.159555,0 -1.511514,2.67954 -5.932353,3.94458 -10.528797,4.52946 -4.596441,0.58491 -9.368493,0.48969 -11.582427,0.44868 -4.889009,-0.1539 -9.105947,-0.81627 -12.943622,-2.24463 C 46.555675,199.14021 40.952062,191.11383 36.717995,182.3532 34.28627,177.25308 32.60168,171.88557 32.128589,166.81422 Z" + id="path3826" + inkscape:connector-curvature="0" + sodipodi:nodetypes="ccccscccscccc" /> + <path + style="fill:#232629;fill-opacity:1;stroke:#eff0f1;stroke-width:0.61557972;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 36.588125,153.38313 c -0.13143,0.2691 -0.11841,0.61521 -0.0087,0.8937 0.24057,0.6108 0.861507,1.00128 1.353078,1.44129 0.22413,0.2004 0.698265,0.2475 0.727482,0.54468 0.06624,0.67434 -0.831009,1.09809 -1.371159,1.51524 -0.405021,0.31287 -1.18326,0.2391 -1.369845,0.71256 -0.12846,0.32592 0.25764,0.64671 0.359352,0.98172 0.14334,0.47208 0.505368,0.96996 0.352617,1.4391 -0.18384,0.5646 -0.830796,0.87642 -1.3602,1.15593 -0.582498,0.30753 -1.369398,0.1533 -1.910055,0.52803 -0.515121,0.35709 -1.072617,0.89505 -1.093644,1.51653 -0.0096,0.282 -0.11832,0.82413 -0.07194,0.95874 3.957921,-1.27947 6.213915,-2.0037 8.829047,-2.64723 2.61513,-0.64353 4.956591,-1.04667 9.101493,-1.75173 -0.021,-0.1407 -0.368331,-0.57135 -0.507027,-0.81672 -0.305922,-0.54126 -1.048884,-0.7602 -1.670652,-0.83835 -0.652584,-0.0819 -1.278933,0.41895 -1.937532,0.41589 -0.598569,-0.003 -1.316304,0.021 -1.740291,-0.39525 -0.352296,-0.34524 -0.26145,-0.95424 -0.352617,-1.43913 -0.06468,-0.3441 0.12933,-0.80721 -0.13524,-1.03671 -0.384234,-0.33327 -1.040175,0.0921 -1.543863,0.002 -0.671733,-0.1197 -1.663119,-0.0801 -1.916109,-0.70875 -0.1116,-0.2772 0.28722,-0.53802 0.393177,-0.81963 0.23241,-0.61764 0.602424,-1.25124 0.533364,-1.9041 -0.0315,-0.2979 -0.17994,-0.61056 -0.42087,-0.78831 -0.517548,-0.36678 -1.343666,-0.40758 -2.317436,-0.1617 -0.973761,0.2457 -1.643757,0.65817 -1.922388,1.2021 z" + id="path3832" + inkscape:connector-curvature="0" + sodipodi:nodetypes="csssssscssscccssscssssssccc" /> + <path + style="fill:none;fill-opacity:1;stroke:#eff0f1;stroke-width:0.61557972;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 51.231481,165.22221 c 0,0 -7.555836,1.62501 -11.051847,2.63304 -2.478863,0.71475 -7.315274,2.52771 -7.315274,2.52771" + id="path3847" + inkscape:connector-curvature="0" + sodipodi:nodetypes="csc" /> + </g> +</svg>