--- a/PluginProjectDjango.py Fri Mar 22 14:12:00 2013 +0100 +++ b/PluginProjectDjango.py Fri Mar 22 19:26:49 2013 +0100 @@ -0,0 +1,356 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2013 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing the Django project plugin. +""" + +import os +import glob +import fnmatch + +from PyQt4.QtCore import QCoreApplication, QObject, QTranslator + +from E5Gui.E5Application import e5App + +import Preferences + +from Globals import isWindowsPlatform, isMacPlatform + +from ProjectDjango.Project import Project + +# Start-of-Header +name = "Django Project Plugin" +author = "Detlev Offenbach <detlev@die-offenbachs.de>" +autoactivate = True +deactivateable = True +version = "3.0.0" +className = "ProjectDjangoPlugin" +packageName = "ProjectDjango" +shortDescription = "Project support for Django projects." +longDescription = """This plugin implements project support for Django projects.""" +needsRestart = False +pyqtApi = 2 +# End-of-Header + +error = "" + +djangoPluginObject = None + + +def apiFiles(language): + """ + Module function to return the API files made available by this plugin. + + @return list of API filenames (list of string) + """ + if language in ["Python3", "Python2"]: + apisDir = \ + os.path.join(os.path.dirname(__file__), "ProjectDjango", "APIs") + apis = glob.glob(os.path.join(apisDir, '*.api')) + else: + apis = [] + return apis + + +def createDjangoPage(configDlg): + """ + Module function to create the Django configuration page. + + @return reference to the configuration page + """ + global djangoPluginObject + from ProjectDjango.ConfigurationPage.DjangoPage import DjangoPage + page = DjangoPage(djangoPluginObject) + return page + + +def getConfigData(): + """ + Module function returning data as required by the configuration dialog. + + @return dictionary containing the relevant data + """ + if e5App().getObject("UserInterface").versionIsNewer('5.0.99', '20120101'): + return { + "djangoPage": \ + [QCoreApplication.translate("ProjectDjangoPlugin", "Django"), + os.path.join("ProjectDjango", "icons", + "django.png"), + createDjangoPage, None, None], + } + else: + return {} + + +def prepareUninstall(): + """ + Module function to prepare for an uninstallation. + """ + Preferences.removeProjectBrowserFlags(ProjectDjangoPlugin.PreferencesKey) + Preferences.Prefs.settings.remove(ProjectDjangoPlugin.PreferencesKey) + Preferences.Prefs.rsettings.remove(ProjectDjangoPlugin.PreferencesKey) + + +class ProjectDjangoPlugin(QObject): + """ + Class implementing the Pyramid project plugin. + """ + PreferencesKey = "Django" + + lexerAssociations = { + "*.html" : "Pygments|HTML+Django/Jinja", + "*.htm" : "Pygments|HTML+Django/Jinja", + } + + def __init__(self, ui): + """ + Constructor + + @param ui reference to the user interface object (UI.UserInterface) + """ + QObject.__init__(self, ui) + self.__ui = ui + self.__initialize() + + self.__defaults = { + "ServerAddress" : "", + + "RecentNumberApps" : 10, + "UsePlainPython" : False, + } + 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.__mainAct = None + self.__mainMenu = None + + self.__e5project = e5App().getObject("Project") + + def __checkVersions(self): + """ + Private function to check that the eric5 version is ok. + + @return flag indicating version is ok (boolean) + """ + global error + + if self.__ui.versionIsNewer('5.0.99', '20120101'): + error = "" + else: + error = self.trUtf8("eric5 version is too old, {0}, {1} or newer needed.")\ + .format("5.1.0", "20120101") + return False + + return True + + def activate(self): + """ + Public method to activate this plugin. + + @return tuple of None and activation status (boolean) + """ + if not self.__checkVersions(): + return None, False + + global djangoPluginObject + djangoPluginObject = self + + self.__object = Project(self, self.__ui) + self.__object.initActions() + e5App().registerPluginObject("ProjectDjango", self.__object) + + self.__mainMenu = self.__object.initMenu() + + try: + self.__e5project.registerProjectType("Django", self.trUtf8("Django"), + self.fileTypesCallback, + lexerAssociationCallback=self.lexerAssociationCallback, + binaryTranslationsCallback=self.binaryTranslationsCallback, + progLanguages=["Python2", "Python3"]) + except TypeError: + # for backward compatibility + self.__e5project.registerProjectType("Django", self.trUtf8("Django"), + self.fileTypesCallback, + lexerAssociationCallback=self.lexerAssociationCallback, + binaryTranslationsCallback=self.binaryTranslationsCallback) + + from Project.ProjectBrowser import SourcesBrowserFlag, FormsBrowserFlag, \ + TranslationsBrowserFlag, OthersBrowserFlag + Preferences.setProjectBrowserFlagsDefault("Pyramid", + 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("ProjectDjango") + + 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("Django") + + self.__object.projectClosedHooks() + self.__projectClosed() + + self.__initialize() + + def __loadTranslator(self): + """ + Private method to load the translation file. + """ + if self.__ui is not None: + loc = self.__ui.getLocale() + if loc and loc != "C": + locale_dir = \ + os.path.join(os.path.dirname(__file__), "ProjectDjango", "i18n") + translation = "django_%s" % 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() == "Django": + projectAct = self.__ui.getMenuBarAction("project") + actions = self.__ui.menuBar().actions() + insertAct = actions[actions.index(projectAct) + 1] + self.__mainAct = self.__ui.menuBar().insertMenu(insertAct, self.__mainMenu) + + def __projectClosed(self): + """ + Private slot to handle the projectClosed signal. + """ + if self.__mainAct is not None: + 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 + """ + if self.__e5project.getProjectType() == "Django": + fileTypes = { + "*.html" : "FORMS", + "*.htm" : "FORMS", + "*.js": "SOURCES", + "*.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 (string) + @return name of the lexer (string) (Pygments lexers are prefixed with 'Pygments|') + """ + 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 (string) + @return name of the binary translation file (string) + """ + if filename.endswith(".po"): + filename = filename.replace(".po", ".mo") + return filename + + def getPreferences(self, key): + """ + Public method to retrieve the various settings. + + @param key the key of the value to get + @param prefClass preferences class used as the storage area + @return the requested setting + """ + if key in ["RecentNumberApps"]: + return int(Preferences.Prefs.settings.value(self.PreferencesKey + "/" + key, + self.__defaults[key])) + elif key in ["UsePlainPython"]: + 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 (string) + @param value the value to be set + @param prefClass preferences class used as the storage area + """ + Preferences.Prefs.settings.setValue(self.PreferencesKey + "/" + key, value)