Sun, 24 Mar 2013 15:29:37 +0100
Extended the functions by
- Create Superuser
- Change Password
- Clear Sessions
# -*- coding: utf-8 -*- # Copyright (c) 2013 Detlev Offenbach <detlev@die-offenbachs.de> # """ Module implementing the Django project support. """ import sys import os import re from PyQt4.QtCore import QObject, QProcess, QTimer, QUrl, QFileInfo from PyQt4.QtGui import QMenu, QInputDialog, QLineEdit, QDesktopServices, QDialog, \ QFileDialog from E5Gui.E5Application import e5App from E5Gui import E5MessageBox, E5FileDialog from E5Gui.E5Action import E5Action from .DjangoDialog import DjangoDialog import Preferences import Utilities class DjangoNoSiteSelectedException(Exception): """ Exception thrown to signal, that there is no current site. """ pass class Project(QObject): """ Class implementing the Django project support. """ RecentApplicationsKey = "Django/RecentApplications" def __init__(self, plugin, parent=None): """ Constructor @param plugin reference to the plugin object @param parent parent (QObject) """ super().__init__(parent) self.__plugin = plugin self.__ui = parent self.__e5project = e5App().getObject("Project") self.__hooksInstalled = False self.__mainMenu = None self.__serverProc = None self.__testServerProc = None self.__recentApplications = [] self.__loadRecentApplications() def initActions(self): """ Public method to define the Pyramid actions. """ # TODO: add support for manage.py changepassword # TODO: add support for manage.py createsuperuser # TODO: add support for manage.py clearsession self.actions = [] self.selectSiteAct = E5Action(self.trUtf8('Current Project'), "", 0, 0, self,'django_current_project') self.selectSiteAct.setStatusTip(self.trUtf8( 'Selects the current project')) self.selectSiteAct.setWhatsThis(self.trUtf8( """<b>Current Project</b>""" """<p>Selects the current project. Used for multi-project """ """Django projects to switch between the projects.</p>""" )) self.selectSiteAct.triggered[()].connect(self.__selectSite) self.actions.append(self.selectSiteAct) self.__setCurrentSite(None) ############################## ## start actions below ## ############################## self.startProjectAct = E5Action(self.trUtf8('Start Project'), self.trUtf8('Start &Project'), 0, 0, self,'django_start_project') self.startProjectAct.setStatusTip(self.trUtf8( 'Starts a new Django project')) self.startProjectAct.setWhatsThis(self.trUtf8( """<b>Start Project</b>""" """<p>Starts a new Django project using "django-admin.py startproject".</p>""" )) self.startProjectAct.triggered[()].connect(self.__startProject) self.actions.append(self.startProjectAct) self.startGlobalApplicationAct = E5Action( self.trUtf8('Start Application (global)'), self.trUtf8('Start Application (&global)'), 0, 0, self,'django_start_global_application') self.startGlobalApplicationAct.setStatusTip(self.trUtf8( 'Starts a new global Django application')) self.startGlobalApplicationAct.setWhatsThis(self.trUtf8( """<b>Start Application (global)</b>""" """<p>Starts a new global Django application using""" """ "django-admin.py startapp".</p>""" )) self.startGlobalApplicationAct.triggered[()].connect( self.__startGlobalApplication) self.actions.append(self.startGlobalApplicationAct) self.startLocalApplicationAct = E5Action( self.trUtf8('Start Application (local)'), self.trUtf8('Start Application (&local)'), 0, 0, self,'django_start_local_application') self.startLocalApplicationAct.setStatusTip(self.trUtf8( 'Starts a new local Django application')) self.startLocalApplicationAct.setWhatsThis(self.trUtf8( """<b>Start Application (local)</b>""" """<p>Starts a new local Django application using""" """ "manage.py startapp".</p>""" )) self.startLocalApplicationAct.triggered[()].connect( self.__startLocalApplication) self.actions.append(self.startLocalApplicationAct) ############################## ## run actions below ## ############################## self.runServerAct = E5Action(self.trUtf8('Run Server'), self.trUtf8('Run &Server'), 0, 0, self,'django_run_server') self.runServerAct.setStatusTip(self.trUtf8( 'Starts the Django Web server')) self.runServerAct.setWhatsThis(self.trUtf8( """<b>Run Server</b>""" """<p>Starts the Django Web server using "manage.py runserver".</p>""" )) self.runServerAct.triggered[()].connect(self.__runServer) self.actions.append(self.runServerAct) self.runBrowserAct = E5Action(self.trUtf8('Run Web-Browser'), self.trUtf8('Run &Web-Browser'), 0, 0, self,'django_run_browser') self.runBrowserAct.setStatusTip(self.trUtf8( 'Starts the default Web-Browser with the URL of the Django Web server')) self.runBrowserAct.setWhatsThis(self.trUtf8( """<b>Run Web-Browser</b>""" """<p>Starts the default Web-Browser with the URL of the """ """Django Web server.</p>""" )) self.runBrowserAct.triggered[()].connect(self.__runBrowser) self.actions.append(self.runBrowserAct) ############################## ## caching actions below ## ############################## self.createCacheTableAct = E5Action(self.trUtf8('Create Cache Tables'), self.trUtf8('C&reate Cache Tables'), 0, 0, self,'django_create_cache_tables') self.createCacheTableAct.setStatusTip(self.trUtf8( 'Creates the tables needed to use the SQL cache backend')) self.createCacheTableAct.setWhatsThis(self.trUtf8( """<b>Create Cache Tables</b>""" """<p>Creates the tables needed to use the SQL cache backend.</p>""" )) self.createCacheTableAct.triggered[()].connect(self.__createCacheTables) self.actions.append(self.createCacheTableAct) ############################## ## help action below ## ############################## self.helpAct = E5Action(self.trUtf8('Help'), self.trUtf8('&Help'), 0, 0, self,'django_help') self.helpAct.setStatusTip(self.trUtf8( 'Shows the Django help index')) self.helpAct.setWhatsThis(self.trUtf8( """<b>Help</b>""" """<p>Shows the Django help index page.</p>""" )) self.helpAct.triggered[()].connect(self.__showHelpIndex) self.actions.append(self.helpAct) ############################## ## about action below ## ############################## self.aboutDjangoAct = E5Action(self.trUtf8('About Django'), self.trUtf8('About D&jango'), 0, 0, self,'django_about') self.aboutDjangoAct.setStatusTip(self.trUtf8( 'Shows some information about Django')) self.aboutDjangoAct.setWhatsThis(self.trUtf8( """<b>About Django</b>""" """<p>Shows some information about Django.</p>""" )) self.aboutDjangoAct.triggered[()].connect(self.__djangoInfo) self.actions.append(self.aboutDjangoAct) self.__initDatabaseActions() self.__initDatabaseSqlActions() self.__initToolsActions() self.__initTestingActions() self.__initAuthorizationActions() self.__initSessionActions() def __initDatabaseActions(self): """ Private method to define the database related actions. """ self.syncDatabaseAct = E5Action(self.trUtf8('Synchronize'), self.trUtf8('&Synchronize'), 0, 0, self,'django_database_syncdb') self.syncDatabaseAct.setStatusTip(self.trUtf8( 'Synchronizes the database')) self.syncDatabaseAct.setWhatsThis(self.trUtf8( """<b>Synchronize</b>""" """<p>Synchronizes the database.</p>""" )) self.syncDatabaseAct.triggered[()].connect(self.__databaseSynchronize) self.actions.append(self.syncDatabaseAct) self.inspectDatabaseAct = E5Action(self.trUtf8('Introspect'), self.trUtf8('&Introspect'), 0, 0, self,'django_database_inspect') self.inspectDatabaseAct.setStatusTip(self.trUtf8( 'Introspects the database tables and outputs a Django model module')) self.inspectDatabaseAct.setWhatsThis(self.trUtf8( """<b>Introspect</b>""" """<p>Introspects the database tables and outputs a """ """Django model module.</p>""" )) self.inspectDatabaseAct.triggered[()].connect(self.__databaseInspect) self.actions.append(self.inspectDatabaseAct) self.flushDatabaseAct = E5Action(self.trUtf8('Flush'), self.trUtf8('&Flush'), 0, 0, self,'django_database_flush') self.flushDatabaseAct.setStatusTip(self.trUtf8( 'Returns all database tables to the state just after their installation')) self.flushDatabaseAct.setWhatsThis(self.trUtf8( """<b>Flush</b>""" """<p>Returns all database tables to the state """ """just after their installation.</p>""" )) self.flushDatabaseAct.triggered[()].connect(self.__databaseFlush) self.actions.append(self.flushDatabaseAct) self.databaseClientAct = E5Action(self.trUtf8('Start Client Console'), self.trUtf8('Start &Client Console'), 0, 0, self,'django_database_client') self.databaseClientAct.setStatusTip(self.trUtf8( 'Starts a console window for the database client')) self.databaseClientAct.setWhatsThis(self.trUtf8( """<b>Start Client Console</b>""" """<p>Starts a console window for the database client.</p>""" )) self.databaseClientAct.triggered[()].connect(self.__runDatabaseClient) self.actions.append(self.databaseClientAct) def __initDatabaseSqlActions(self): """ Private method to define the database SQL related actions. """ self.databaseSqlCreateTablesAct = E5Action(self.trUtf8('Create Tables'), self.trUtf8('Create &Tables'), 0, 0, self,'django_database_sql_create_tables') self.databaseSqlCreateTablesAct.setStatusTip(self.trUtf8( 'Prints the CREATE TABLE SQL statements for one or more applications')) self.databaseSqlCreateTablesAct.setWhatsThis(self.trUtf8( """<b>Create Tables</b>""" """<p>Prints the CREATE TABLE SQL statements for one or """ """more applications.</p>""" )) self.databaseSqlCreateTablesAct.triggered[()].connect( self.__databaseSqlCreateTables) self.actions.append(self.databaseSqlCreateTablesAct) self.databaseSqlCreateIndexesAct = E5Action(self.trUtf8('Create Indexes'), self.trUtf8('Create &Indexes'), 0, 0, self,'django_database_sql_create_indexes') self.databaseSqlCreateIndexesAct.setStatusTip(self.trUtf8( 'Prints the CREATE INDEX SQL statements for one or more applications')) self.databaseSqlCreateIndexesAct.setWhatsThis(self.trUtf8( """<b>Create Indexes</b>""" """<p>Prints the CREATE INDEX SQL statements for one or """ """more applications.</p>""" )) self.databaseSqlCreateIndexesAct.triggered[()].connect( self.__databaseSqlCreateIndexes) self.actions.append(self.databaseSqlCreateIndexesAct) self.databaseSqlCreateEverythingAct = E5Action(self.trUtf8('Create Everything'), self.trUtf8('Create &Everything'), 0, 0, self,'django_database_sql_create_everything') self.databaseSqlCreateEverythingAct.setStatusTip(self.trUtf8( 'Prints the CREATE ... SQL statements for one or more applications')) self.databaseSqlCreateEverythingAct.setWhatsThis(self.trUtf8( """<b>Create Everything</b>""" """<p>Prints the CREATE TABLE, custom SQL and CREATE INDEX SQL """ """statements for one or more applications.</p>""" )) self.databaseSqlCreateEverythingAct.triggered[()].connect( self.__databaseSqlCreateEverything) self.actions.append(self.databaseSqlCreateEverythingAct) self.databaseSqlCustomAct = E5Action(self.trUtf8('Custom Statements'), self.trUtf8('&Custom Statements'), 0, 0, self,'django_database_sql_custom') self.databaseSqlCustomAct.setStatusTip(self.trUtf8( 'Prints the custom table modifying SQL statements for ' 'one or more applications')) self.databaseSqlCustomAct.setWhatsThis(self.trUtf8( """<b>Custom Statements</b>""" """<p>Prints the custom table modifying SQL statements """ """for one or more applications.</p>""" )) self.databaseSqlCustomAct.triggered[()].connect( self.__databaseSqlCustom) self.actions.append(self.databaseSqlCustomAct) self.databaseSqlDropTablesAct = E5Action(self.trUtf8('Drop Tables'), self.trUtf8('&Drop Tables'), 0, 0, self,'django_database_sql_drop_tables') self.databaseSqlDropTablesAct.setStatusTip(self.trUtf8( 'Prints the DROP TABLE SQL statements for ' 'one or more applications')) self.databaseSqlDropTablesAct.setWhatsThis(self.trUtf8( """<b>Drop Tables</b>""" """<p>Prints the DROP TABLE SQL statements """ """for one or more applications.</p>""" )) self.databaseSqlDropTablesAct.triggered[()].connect( self.__databaseSqlDropTables) self.actions.append(self.databaseSqlDropTablesAct) self.databaseSqlFlushAct = E5Action(self.trUtf8('Flush Database'), self.trUtf8('&Flush Database'), 0, 0, self,'django_database_sql_flush_database') self.databaseSqlFlushAct.setStatusTip(self.trUtf8( 'Prints a list of statements to return all database tables to the state ' 'just after their installation')) self.databaseSqlFlushAct.setWhatsThis(self.trUtf8( """<b>Flush Database</b>""" """<p>Prints a list of statements to return all database tables to """ """the state just after their installation.</p>""" )) self.databaseSqlFlushAct.triggered[()].connect( self.__databaseSqlFlushDatabase) self.actions.append(self.databaseSqlFlushAct) self.databaseSqlResetSeqAct = E5Action(self.trUtf8('Reset Sequences'), self.trUtf8('Reset &Sequences'), 0, 0, self,'django_database_sql_reset_sequences') self.databaseSqlResetSeqAct.setStatusTip(self.trUtf8( 'Prints the SQL statements for resetting sequences for ' 'one or more applications')) self.databaseSqlResetSeqAct.setWhatsThis(self.trUtf8( """<b>Reset Sequences</b>""" """<p>Prints the SQL statements for resetting sequences for """ """one or more applications.</p>""" )) self.databaseSqlResetSeqAct.triggered[()].connect( self.__databaseSqlResetSequences) self.actions.append(self.databaseSqlResetSeqAct) def __initToolsActions(self): """ Private method to define the tool actions. """ self.diffSettingsAct = E5Action(self.trUtf8('Diff Settings'), self.trUtf8('&Diff Settings'), 0, 0, self,'django_tools_diffsettings') self.diffSettingsAct.setStatusTip(self.trUtf8( 'Shows the modification made to the settings')) self.diffSettingsAct.setWhatsThis(self.trUtf8( """<b>Diff Settings</b>""" """<p>Shows the modification made to the settings.</p>""" )) self.diffSettingsAct.triggered[()].connect(self.__diffSettings) self.actions.append(self.diffSettingsAct) self.cleanupAct = E5Action(self.trUtf8('Cleanup'), self.trUtf8('&Cleanup'), 0, 0, self,'django_tools_cleanup') self.cleanupAct.setStatusTip(self.trUtf8( 'Cleans out old data from the database')) self.cleanupAct.setWhatsThis(self.trUtf8( """<b>Cleanup</b>""" """<p>Cleans out old data from the database.</p>""" )) self.cleanupAct.triggered[()].connect(self.__cleanup) self.actions.append(self.cleanupAct) self.validateAct = E5Action(self.trUtf8('Validate'), self.trUtf8('&Validate'), 0, 0, self,'django_tools_validate') self.validateAct.setStatusTip(self.trUtf8( 'Validates all installed models')) self.validateAct.setWhatsThis(self.trUtf8( """<b>Validate</b>""" """<p>Validates all installed models.</p>""" )) self.validateAct.triggered[()].connect(self.__validate) self.actions.append(self.validateAct) self.runPythonShellAct = E5Action(self.trUtf8('Start Python Console'), self.trUtf8('Start &Python Console'), 0, 0, self,'django_tools_pythonconsole') self.runPythonShellAct.setStatusTip(self.trUtf8( 'Starts a Python interactive interpreter')) self.runPythonShellAct.setWhatsThis(self.trUtf8( """<b>Start Python Console</b>""" """<p>Starts a Python interactive interpreter.</p>""" )) self.runPythonShellAct.triggered[()].connect(self.__runPythonShell) self.actions.append(self.runPythonShellAct) def __initTestingActions(self): """ Private method to define the testing actions. """ self.dumpDataAct = E5Action(self.trUtf8('Dump Data'), self.trUtf8('&Dump Data'), 0, 0, self,'django_tools_dumpdata') self.dumpDataAct.setStatusTip(self.trUtf8( 'Dump the database data to a fixture')) self.dumpDataAct.setWhatsThis(self.trUtf8( """<b>Dump Data</b>""" """<p>Dump the database data to a fixture.</p>""" )) self.dumpDataAct.triggered[()].connect(self.__dumpData) self.actions.append(self.dumpDataAct) self.loadDataAct = E5Action(self.trUtf8('Load Data'), self.trUtf8('&Load Data'), 0, 0, self,'django_tools_loaddata') self.loadDataAct.setStatusTip(self.trUtf8( 'Load data from fixture files')) self.loadDataAct.setWhatsThis(self.trUtf8( """<b>Load Data</b>""" """<p>Load data from fixture files.</p>""" )) self.loadDataAct.triggered[()].connect(self.__loadData) self.actions.append(self.loadDataAct) self.runTestAct = E5Action(self.trUtf8('Run Testsuite'), self.trUtf8('Run &Testsuite'), 0, 0, self,'django_tools_run_test') self.runTestAct.setStatusTip(self.trUtf8( 'Run the test suite for applications or the whole site')) self.runTestAct.setWhatsThis(self.trUtf8( """<b>Run Testsuite</b>""" """<p>Run the test suite for applications or the whole site.</p>""" )) self.runTestAct.triggered[()].connect(self.__runTestSuite) self.actions.append(self.runTestAct) self.runTestServerAct = E5Action(self.trUtf8('Run Testserver'), self.trUtf8('Run Test&server'), 0, 0, self,'django_tools_run_test_server') self.runTestServerAct.setStatusTip(self.trUtf8( 'Run a development server with data from a set of fixtures')) self.runTestServerAct.setWhatsThis(self.trUtf8( """<b>Run Testserver</b>""" """<p>Run a development server with data from a set of fixtures.</p>""" )) self.runTestServerAct.triggered[()].connect(self.__runTestServer) self.actions.append(self.runTestServerAct) def __initAuthorizationActions(self): """ Private method to define the authorization actions. """ self.changePasswordAct = E5Action(self.trUtf8('Change Password'), self.trUtf8('Change &Password'), 0, 0, self,'django_auth_changepassword') self.changePasswordAct.setStatusTip(self.trUtf8( 'Change the password of a user')) self.changePasswordAct.setWhatsThis(self.trUtf8( """<b>Change Password</b>""" """<p>Change the password of a user of the Django project.</p>""" )) self.changePasswordAct.triggered[()].connect(self.__changePassword) self.actions.append(self.changePasswordAct) self.createSuperUserAct = E5Action(self.trUtf8('Create Superuser'), self.trUtf8('Create &Superuser'), 0, 0, self,'django_auth_createsuperuser') self.createSuperUserAct.setStatusTip(self.trUtf8( 'Create a superuser account')) self.createSuperUserAct.setWhatsThis(self.trUtf8( """<b>Create Superuser</b>""" """<p>Create a superuser account for the Django project.</p>""" )) self.createSuperUserAct.triggered[()].connect(self.__createSuperUser) self.actions.append(self.createSuperUserAct) def __initSessionActions(self): """ Private method to define the session actions. """ self.clearSessionsAct = E5Action(self.trUtf8('Clear Sessions'), self.trUtf8('Clear &Sessions'), 0, 0, self,'django_session_clearsessions') self.clearSessionsAct.setStatusTip(self.trUtf8( 'Clear expired sessions')) self.clearSessionsAct.setWhatsThis(self.trUtf8( """<b>Clear Sessions</b>""" """<p>Clear expired sessions of the Django project.</p>""" )) self.clearSessionsAct.triggered[()].connect(self.__clearSessions) self.actions.append(self.clearSessionsAct) def initMenu(self): """ Public slot to initialize the Django menu. @return the menu generated (QMenu) """ menu = QMenu(self.trUtf8('D&jango'), self.__ui) menu.setTearOffEnabled(True) menu.addAction(self.selectSiteAct) menu.addSeparator() menu.addAction(self.runServerAct) menu.addAction(self.runBrowserAct) menu.addSeparator() menu.addAction(self.startProjectAct) menu.addAction(self.startGlobalApplicationAct) menu.addAction(self.startLocalApplicationAct) menu.addSeparator() menu.addMenu(self.__initDatabaseMenu()) menu.addSeparator() menu.addMenu(self.__initToolsMenu()) menu.addSeparator() menu.addAction(self.createCacheTableAct) menu.addSeparator() menu.addMenu(self.__initTestingMenu()) menu.addSeparator() menu.addMenu(self.__initAuthorizationMenu()) menu.addSeparator() menu.addMenu(self.__initSessionMenu()) menu.addSeparator() menu.addAction(self.aboutDjangoAct) menu.addSeparator() menu.addAction(self.helpAct) self.__mainMenu = menu return menu def __initDatabaseMenu(self): """ Private slot to initialize the database menu. @return the menu generated (QMenu) """ menu = QMenu(self.trUtf8("&Database"), self.__ui) menu.setTearOffEnabled(True) menu.addAction(self.syncDatabaseAct) menu.addSeparator() menu.addAction(self.inspectDatabaseAct) menu.addSeparator() menu.addAction(self.flushDatabaseAct) menu.addSeparator() menu.addAction(self.databaseClientAct) menu.addSeparator() menu.addMenu(self.__initDatabaseSqlMenu()) return menu def __initDatabaseSqlMenu(self): """ Private slot to initialize the database SQL submenu. @return the menu generated (QMenu) """ menu = QMenu(self.trUtf8("Show &SQL"), self.__ui) menu.setTearOffEnabled(True) menu.addAction(self.databaseSqlCreateTablesAct) menu.addAction(self.databaseSqlCreateIndexesAct) menu.addAction(self.databaseSqlCreateEverythingAct) menu.addSeparator() menu.addAction(self.databaseSqlCustomAct) menu.addSeparator() menu.addAction(self.databaseSqlDropTablesAct) menu.addSeparator() menu.addAction(self.databaseSqlFlushAct) menu.addAction(self.databaseSqlResetSeqAct) return menu def __initToolsMenu(self): """ Private slot to initialize the tools menu. @return the menu generated (QMenu) """ menu = QMenu(self.trUtf8("&Tools"), self.__ui) menu.setTearOffEnabled(True) menu.addAction(self.diffSettingsAct) menu.addAction(self.cleanupAct) menu.addAction(self.validateAct) menu.addSeparator() menu.addAction(self.runPythonShellAct) return menu def __initTestingMenu(self): """ Private slot to initialize the testing menu. @return the menu generated (QMenu) """ menu = QMenu(self.trUtf8("T&esting"), self.__ui) menu.setTearOffEnabled(True) menu.addAction(self.dumpDataAct) menu.addAction(self.loadDataAct) menu.addSeparator() menu.addAction(self.runTestAct) menu.addAction(self.runTestServerAct) return menu def __initAuthorizationMenu(self): """ Private slot to initialize the authorization menu. @return the menu generated (QMenu) """ menu = QMenu(self.trUtf8("&Authorization"), self.__ui) menu.setTearOffEnabled(True) menu.addAction(self.changePasswordAct) menu.addAction(self.createSuperUserAct) return menu def __initSessionMenu(self): """ Private slot to initialize the authorization menu. @return the menu generated (QMenu) """ menu = QMenu(self.trUtf8("&Session"), self.__ui) menu.setTearOffEnabled(True) menu.addAction(self.clearSessionsAct) return menu ################################################################## ## methods below implement the various hook related functions ################################################################## def projectOpenedHooks(self): """ Public method to add our hook methods. """ if self.__e5project.getProjectType() == "Django": self.__formsBrowser = \ e5App().getObject("ProjectBrowser").getProjectBrowser("forms") self.__formsBrowser.addHookMethodAndMenuEntry("newForm", self.newForm, self.trUtf8("New template...")) self.__e5project.projectLanguageAddedByCode.connect( self.__projectLanguageAdded) self.__translationsBrowser = \ e5App().getObject("ProjectBrowser").getProjectBrowser("translations") self.__translationsBrowser.addHookMethodAndMenuEntry("generateAll", self.updateCatalogs, self.trUtf8("Update all catalogs")) self.__translationsBrowser.addHookMethodAndMenuEntry("generateSelected", self.updateSelectedCatalogs, self.trUtf8("Update selected catalogs")) self.__translationsBrowser.addHookMethodAndMenuEntry( "generateAllWithObsolete", self.updateCatalogsWithObsolete, self.trUtf8("Update all catalogs (with obsolete)")) self.__translationsBrowser.addHookMethodAndMenuEntry( "generateSelectedWithObsolete", self.updateSelectedCatalogsWithObsolete, self.trUtf8("Update selected catalogs (with obsolete)")) self.__translationsBrowser.addHookMethodAndMenuEntry("releaseAll", self.compileCatalogs, self.trUtf8("Compile all catalogs")) self.__translationsBrowser.addHookMethodAndMenuEntry("releaseSelected", self.compileSelectedCatalogs, self.trUtf8("Compile selected catalogs")) self.__hooksInstalled = True def projectClosedHooks(self): """ Public method to remove our hook methods. """ if self.__hooksInstalled: self.__formsBrowser.removeHookMethod("newForm") self.__formsBrowser = None self.__e5project.projectLanguageAddedByCode.disconnect( self.__projectLanguageAdded) self.__translationsBrowser.removeHookMethod("generateAll") self.__translationsBrowser.removeHookMethod("generateSelected") self.__translationsBrowser.removeHookMethod("generateAllWithObsolete") self.__translationsBrowser.removeHookMethod("generateSelectedWithObsolete") self.__translationsBrowser.removeHookMethod("releaseAll") self.__translationsBrowser.removeHookMethod("releaseSelected") self.__translationsBrowser = None self.__hooksInstalled = False def newForm(self, path): """ Public method to create a new form. @param path full directory path for the new form file (string) """ fname, selectedFilter = E5FileDialog.getSaveFileNameAndFilter( self.__ui, self.trUtf8("New Form"), path, filter, None, QFileDialog.Options(QFileDialog.DontConfirmOverwrite)) if not fname: # user aborted or didn't enter a filename return ext = QFileInfo(fname).suffix() if not ext: ex = selectedFilter.split("(*")[1].split(")")[0] if ex: fname += ex if os.path.exists(fname): res = E5MessageBox.yesNo(self.__ui, self.trUtf8("New Form"), self.trUtf8("The file already exists! Overwrite it?"), icon=E5MessageBox.Warning) if not res: # user selected to not overwrite return try: f = open(fname, "w") f.write('<!DOCTYPE html>') f.write('<html>\n') f.write(' <head>\n') f.write(' <meta content="" />\n') f.write(' <title></title>\n') f.write(' <link rel="stylesheet" type="text/css" href="style.css"/>') f.write(' <!--[if lte IE 7]>') f.write(' <link rel="stylesheet" type="text/css" href="ie.css"/>') f.write(' <![endif]-->') f.write(' </head>\n') f.write('\n') f.write(' <body class="bodyclass">\n') f.write(' <div id="container">') f.write(' </div>') f.write(' </body>\n') f.close() f.write('</html>\n') f.close() except (IOError, OSError) as e: E5MessageBox.critical(self.__ui, self.trUtf8("New Form"), self.trUtf8("<p>The new form file <b>{0}</b> could not be created.<br>" "Problem: {1}</p>").format(fname, str(e))) return self.__e5project.appendFile(fname) self.__formsBrowser.sourceFile.emit(fname) ################################################################## ## 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() self.__setCurrentSite(None) def __djangoInfo(self): """ Private slot to show some info about Django. """ from django import VERSION version = '.'.join([str(i) for i in VERSION[:-1]]) if VERSION[-1]: version += '-' + VERSION[-1] E5MessageBox.about(self.__ui, self.trUtf8("About Django"), self.trUtf8( "<p>Django is a high-level Python Web framework that encourages rapid " "development and clean, pragmatic design.</p>" "<p><table>" "<tr><td>Version:</td><td>{0}</td></tr>" "<tr><td>URL:</td><td><a href=\"http://www.djangoproject.com\">" "http://www.djangoproject.com</a></td></tr>" "</table></p>" ).format(version) ) def getDjangoVersion(self): """ Public method to get the Django version. @return Django version as a tuple """ from django import VERSION return VERSION def __getApplications(self): """ Private method to ask the user for a list of application names. @return list of application names (list of strings) """ applStr, ok = QInputDialog.getItem( self.__ui, self.trUtf8("Select Applications"), self.trUtf8("Enter the list of applications separated by spaces."), self.getRecentApplications(), 0, True) if ok and applStr != "": self.setMostRecentApplication(applStr) return applStr.split() else: return [] def __loadRecentApplications(self): """ Private method to load the recently used applications list. """ self.__recentApplications = [] Preferences.Prefs.rsettings.sync() ra = Preferences.Prefs.rsettings.value(self.RecentApplicationsKey) if ra is not None: maxRecentApps = self.__plugin.getPreferences("RecentNumberApps") self.__recentApplications = ra[:maxRecentApps] def __saveRecentApplications(self): """ Private method to save the list of recently used applications list. """ Preferences.Prefs.rsettings.setValue(self.RecentApplicationsKey, self.__recentApplications) Preferences.Prefs.rsettings.sync() def getRecentApplications(self): """ Public method to get the list of recent applications. @return list of recent applications entries (list of strings) """ self.__loadRecentApplications() return self.__recentApplications def setMostRecentApplication(self, applStr): """ Public method to set the most recently used applications entry. @param applStr applications entry (string) """ if applStr in self.__recentApplications: self.__recentApplications.remove(applStr) self.__recentApplications.insert(0, applStr) maxRecentApps = self.__plugin.getPreferences("RecentNumberApps") if len(self.__recentApplications) > maxRecentApps: self.__recentApplications = self.recent[:maxRecentApps] self.__saveRecentApplications() def getProjectPath(self): """ Public method to get the path of the eric5 project. @return path of the eric5 project (string) """ return self.__e5project.getProjectPath() def __getPythonExecutable(self): """ Private method to determine the name of the Python executable. @return Python executable (string) """ # TODO: make this differentiate between Python2 and Python3 return sys.executable.replace("pythonw", "python") def __showHelpIndex(self): """ Private slot to show the help index page. """ page = os.path.join(os.path.dirname(__file__), "Documentation", "help", "index.html") self.__ui.launchHelpViewer(page) def __isSpawningConsole(self, consoleCmd): """ Private method to check, if the given console is a spawning console. @param consoleCmd console command (string) @return tuple of two entries giving an indication, if the console is spawning (boolean) and the (possibly) cleaned console command (string) """ if consoleCmd and consoleCmd[0] == '@': return (True, consoleCmd[1:]) else: return (False, consoleCmd) ################################################################## ## slots below implement creation functions ################################################################## def startProjectOrApplication(self): """ Public slot to start a new Django project or application. """ if self.__e5project.getProjectType() == "Django": projectStr = self.trUtf8("Project") applStr = self.trUtf8("Application") selections = ["", projectStr, applStr] selection, ok = QInputDialog.getItem( self.__ui, self.trUtf8("Start Django"), self.trUtf8("Select if this project should be a " "Django Project or Application.<br />" "Select the empty entry for none."), selections, 0, False) if ok and bool(selection): if selection == projectStr: path, projectName = os.path.split(self.__e5project.getProjectPath()) self.__createProject(projectName, path) elif selection == applStr: path, applName = os.path.split(self.__e5project.getProjectPath()) self.__createApplication(applName, path) def __createProject(self, projectName, path): """ Private slot to create a new Django project. @param projectName name of the new project (string) @param path the directory where the project should be created (string) @return flag indicating a successful creation (boolean) """ title = self.trUtf8("Start Django Project") args = [] if Utilities.isWindowsPlatform(): args.append(self.__getPythonExecutable()) args.append(os.path.join(sys.exec_prefix, "Scripts", "django-admin.py")) else: if Utilities.isinpath("django-admin.py"): args.append("django-admin.py") elif Utilities.isinpath("django-admin"): args.append("django-admin") else: # fall back args.append("django-admin.py") args.append("startproject") args.append(projectName) dia = DjangoDialog(title, msgSuccess = self.trUtf8("Django project created successfully.")) res = dia.startProcess(args, path) if res: dia.exec_() # create the base directory for translations i18nPath = os.path.join(path, projectName, "locale") if not os.path.exists(i18nPath): os.makedirs(i18nPath) if os.path.join(path, projectName) == self.__e5project.getProjectPath(): self.__setCurrentSite("") else: self.__setCurrentSite(projectName) return res def __startProject(self): """ Private slot to start a new Django project. """ projectName, ok = QInputDialog.getText( self.__ui, self.trUtf8("Start Django Project"), self.trUtf8("Enter the name of the new Django project."), QLineEdit.Normal) if ok and projectName != "": res = self.__createProject(projectName, self.__e5project.getProjectPath()) if res: # search for new files and add them to the project sitePath = os.path.join(self.__e5project.getProjectPath(), projectName) for entry in os.walk(sitePath): for fileName in entry[2]: fullName = os.path.join(entry[0], fileName) self.__e5project.appendFile(fullName) def __createApplication(self, applName, path, isGlobal = True): """ Private slot to create a new Django application. @param applName name of the new application (string) @param path the directory where the application should be created (string) @param isGlobal flag indicating a standalone Django application (boolean) @return flag indicating a successful creation (boolean) """ title = self.trUtf8("Start Django Application") args = [] if isGlobal: if Utilities.isWindowsPlatform(): args.append(self.__getPythonExecutable()) args.append(os.path.join(sys.exec_prefix, "Scripts", "django-admin.py")) else: if Utilities.isinpath("django-admin.py"): args.append("django-admin.py") elif Utilities.isinpath("django-admin"): args.append("django-admin") else: # fall back args.append("django-admin.py") else: args.append(self.__getPythonExecutable()) args.append("manage.py") try: path = self.__sitePath() except DjangoNoSiteSelectedException: return False args.append("startapp") args.append(applName) dia = DjangoDialog(title, msgSuccess = self.trUtf8("Django application created successfully.")) res = dia.startProcess(args, path) if res: dia.exec_() return res def __startGlobalApplication(self): """ Private slot to start a new global Django application. """ applName, ok = QInputDialog.getText( self.__ui, self.trUtf8("Start Global Django Application"), self.trUtf8("Enter the name of the new global Django application."), QLineEdit.Normal) if ok and applName != "": res = self.__createApplication(applName, self.__e5project.getProjectPath()) if res: # search for new files and add them to the project appPath = os.path.join(self.__e5project.getProjectPath(), applName) for entry in os.walk(appPath): for fileName in entry[2]: fullName = os.path.join(entry[0], fileName) self.__e5project.appendFile(fullName) def __startLocalApplication(self): """ Private slot to start a new local Django application. """ applName, ok = QInputDialog.getText( self.__ui, self.trUtf8("Start Local Django Application"), self.trUtf8("Enter the name of the new local Django application."), QLineEdit.Normal) if ok and applName != "": res = self.__createApplication(applName, "", False) if res: try: # search for new files and add them to the project appPath = os.path.join(self.__sitePath(), applName) for entry in os.walk(appPath): for fileName in entry[2]: fullName = os.path.join(entry[0], fileName) self.__e5project.appendFile(fullName) except DjangoNoSiteSelectedException: return ################################################################## ## methods below implement site related functions ################################################################## def __findSites(self): """ Private method to determine the relative path to all manage.py scripts. @return list of sites (list of strings) """ sites = [] for file in sorted(self.__e5project.getSources()): if os.path.basename(file) == "manage.py": sites.append(os.path.dirname(file)) return sites def __selectSite(self): """ Private method to select a site to work with. @return selected site (string) """ sites = self.__findSites() if len(sites) == 1: site = sites[0] else: if self.__currentSite is not None: if self.__currentSite in sites: cur = sites.index(self.__currentSite) else: cur = 0 else: cur = 0 site, ok = QInputDialog.getItem( self.__ui, self.trUtf8("Select Project"), self.trUtf8("Select the Django project to work with."), sites, cur, False) if not ok: site = None self.__setCurrentSite(site) def __sitePath(self): """ Private method to calculate the full path of the Django site. @exception DjangoNoSiteSelectedException raised, if no site is selected @return path of the site (string) """ if self.__currentSite is None: self.__selectSite() if self.__currentSite is None: raise DjangoNoSiteSelectedException else: return os.path.join(self.__e5project.getProjectPath(), self.__currentSite) def __setCurrentSite(self, site): """ Private slot to set the current site. @param site name of the site (string) """ self.__currentSite = site if self.__currentSite is None: curSite = self.trUtf8("None") elif self.__currentSite == "": curSite = self.trUtf8("Project") else: curSite = self.__currentSite self.selectSiteAct.setText( self.trUtf8('&Current Django project ({0})').format(curSite)) if self.__currentSite is None: self.__e5project.pdata["TRANSLATIONPATTERN"] = [] else: self.__e5project.pdata["TRANSLATIONPATTERN"] = [ os.path.join(site, "locale", "%language%", "LC_MESSAGES", "django.po") ] def __site(self): """ Private method to get the name of the current site. @exception DjangoNoSiteSelectedException raised, if no site is selected @return name of the site (string) """ if self.__currentSite is None: self.__selectSite() if self.__currentSite is None: raise DjangoNoSiteSelectedException else: return self.__currentSite ################################################################## ## slots below implement run functions ################################################################## def __runServer(self): """ Private slot to start the Django Web server. """ consoleCmd = self.__isSpawningConsole( self.__plugin.getPreferences("ConsoleCommand"))[1] if consoleCmd: args = Utilities.parseOptionString(consoleCmd) args[0] = Utilities.getExecutablePath(args[0]) args.append(self.__getPythonExecutable()) args.append("manage.py") args.append("runserver") if self.__plugin.getPreferences("UseIPv6"): args.append("--ipv6") addr = self.__plugin.getPreferences("ServerAddress") if addr: args.append(addr) try: if Utilities.isWindowsPlatform(): serverProcStarted, pid = \ QProcess.startDetached(args[0], args[1:], self.__sitePath()) else: if self.__serverProc is not None: self.__serverProcFinished() self.__serverProc = QProcess() self.__serverProc.finished.connect(self.__serverProcFinished) self.__serverProc.setWorkingDirectory(self.__sitePath()) self.__serverProc.start(args[0], args[1:]) serverProcStarted = self.__serverProc.waitForStarted() if not serverProcStarted: E5MessageBox.critical(None, self.trUtf8('Process Generation Error'), self.trUtf8('The Django server could not be started.')) except DjangoNoSiteSelectedException: pass 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 def __runBrowser(self): """ Private slot to start the default web browser with the server URL. """ addr = self.__plugin.getPreferences("ServerAddress") ipv6 = self.__plugin.getPreferences("UseIPv6") if addr: # test for an IPv6 and port address if ']:' in addr: addr, port = addr.rsplit(':', 1) elif ':' in addr: addr, port = addr.split(':', 1) else: port = addr if ipv6: addr = "[::1]" else: addr = "127.0.0.1" else: port = "8000" if ipv6: addr = "[::1]" else: addr = "127.0.0.1" url = QUrl("http://{0}:{1}".format(addr, port)) res = QDesktopServices.openUrl(url) if not res: E5MessageBox.critical(None, self.trUtf8('Run Web-Browser'), self.trUtf8('Could not start the web-browser for the url "{0}".')\ .format(url.toString())) ################################################################## ## slots below implement database related functions ################################################################## def __databaseSynchronize(self): """ Private slot to synchronize the database. """ consoleCmd = self.__isSpawningConsole( self.__plugin.getPreferences("ConsoleCommandNoClose"))[1] if consoleCmd: args = Utilities.parseOptionString(consoleCmd) args[0] = Utilities.getExecutablePath(args[0]) args.append(self.__getPythonExecutable()) args.append("manage.py") args.append("syncdb") try: wd = self.__sitePath() started, pid = QProcess.startDetached(args[0], args[1:], wd) if not started: E5MessageBox.critical(None, self.trUtf8('Process Generation Error'), self.trUtf8('The Django process could not be started.')) except DjangoNoSiteSelectedException: pass def __databaseInspect(self): """ Private slot to introspect the database and output a Django model module. """ title = self.trUtf8("Introspect Database") args = [] args.append(self.__getPythonExecutable()) args.append("manage.py") args.append("inspectdb") try: path = self.__sitePath() except DjangoNoSiteSelectedException: return dia = DjangoDialog(title, fixed = True, linewrap = False) res = dia.startProcess(args, path, False) if res: dia.exec_() def __databaseFlush(self): """ Private slot to return all database tables to the state just after their installation. """ try: path = self.__sitePath() except DjangoNoSiteSelectedException: return title = self.trUtf8("Flush Database") res = E5MessageBox.yesNo(self.__ui, title, self.trUtf8("""Flushing the database will destroy all data. Are you sure?""")) if res: args = [] args.append(self.__getPythonExecutable()) args.append("manage.py") args.append("flush") args.append("--noinput") dia = DjangoDialog(title, msgSuccess = self.trUtf8("Database tables flushed successfully.")) res = dia.startProcess(args, path) if res: dia.exec_() def __runDatabaseClient(self): """ Private slot to start a database client for a Django project. """ consoleCmd = self.__isSpawningConsole( self.__plugin.getPreferences("ConsoleCommand"))[1] if consoleCmd: args = Utilities.parseOptionString(consoleCmd) args[0] = Utilities.getExecutablePath(args[0]) args.append(self.__getPythonExecutable()) args.append("manage.py") args.append("dbshell") try: wd = self.__sitePath() started, pid = QProcess.startDetached(args[0], args[1:], wd) if not started: E5MessageBox.critical(None, self.trUtf8('Process Generation Error'), self.trUtf8('The Django process could not be started.')) except DjangoNoSiteSelectedException: pass ####################################################################### ## slots below implement database functions outputting SQL statements ####################################################################### def __sqlCommand(self, title, command, requestApps = True): """ Private method to perform an SQL creation function. @param title dialog title (string) @param command Django sql... command (string) @param requestApps flag indicating to request a list of applications to work on (boolean) """ try: path = self.__sitePath() except DjangoNoSiteSelectedException: return if requestApps: apps = self.__getApplications() if not apps: return else: apps = [] args = [] args.append(self.__getPythonExecutable()) args.append("manage.py") args.append(command) args += apps fileFilter = self.trUtf8("SQL Files (*.sql)") dia = DjangoDialog(title, fixed = True, linewrap = False, saveFilters = fileFilter) res = dia.startProcess(args, path, False) if res: dia.exec_() def __databaseSqlCreateTables(self): """ Private slot to print the CREATE TABLE SQL statements for one or more applications. """ self.__sqlCommand(self.trUtf8("Create Tables"), "sql") def __databaseSqlCreateIndexes(self): """ Private slot to print the CREATE INDEX SQL statements for one or more applications. """ self.__sqlCommand(self.trUtf8("Create Indexes"), "sqlindexes") def __databaseSqlCreateEverything(self): """ Private slot to print the CREATE TABLE, custom SQL and CREATE INDEX SQL statements for one or more applications. """ self.__sqlCommand(self.trUtf8("Create Everything"), "sqlall") def __databaseSqlCustom(self): """ Private slot to print the custom table modifying SQL statements for one or more applications. """ self.__sqlCommand(self.trUtf8("Custom Statements"), "sqlcustom") def __databaseSqlDropTables(self): """ Private slot to print the DROP TABLE SQL statements for one or more applications. """ self.__sqlCommand(self.trUtf8("Drop Tables"), "sqlclear") def __databaseSqlFlushDatabase(self): """ Private slot to print a list of statements to return all database tables to their initial state. """ self.__sqlCommand(self.trUtf8("Flush Database"), "sqlflush", False) def __databaseSqlResetSequences(self): """ Private slot to print the SQL statements for resetting sequences for one or more applications. """ self.__sqlCommand(self.trUtf8("Reset Sequences"), "sqlsequencereset") ################################################################## ## slots below implement some tool functions ################################################################## def __diffSettings(self): """ Private slot to show the changes made to the settings.py file. """ title = self.trUtf8("Diff Settings") args = [] args.append(self.__getPythonExecutable()) args.append("manage.py") args.append("diffsettings") try: path = self.__sitePath() except DjangoNoSiteSelectedException: return dia = DjangoDialog(title, fixed = True, linewrap = False) res = dia.startProcess(args, path, False) if res: dia.exec_() def __cleanup(self): """ Private slot to clean out old data from the database. """ title = self.trUtf8("Cleanup") args = [] args.append(self.__getPythonExecutable()) args.append("manage.py") args.append("cleanup") try: path = self.__sitePath() except DjangoNoSiteSelectedException: return dia = DjangoDialog(title, msgSuccess = self.trUtf8("Database cleaned up successfully.")) res = dia.startProcess(args, path) if res: dia.exec_() def __validate(self): """ Private slot to validate all installed models. """ title = self.trUtf8("Validate") args = [] args.append(self.__getPythonExecutable()) args.append("manage.py") args.append("validate") try: path = self.__sitePath() except DjangoNoSiteSelectedException: return dia = DjangoDialog(title) res = dia.startProcess(args, path) if res: dia.exec_() def __runPythonShell(self): """ Private slot to start a Python console for a Django project. """ consoleCmd = self.__isSpawningConsole( self.__plugin.getPreferences("ConsoleCommand"))[1] if consoleCmd: args = Utilities.parseOptionString(consoleCmd) args[0] = Utilities.getExecutablePath(args[0]) args.append(self.__getPythonExecutable()) args.append("manage.py") args.append("shell") if self.__plugin.getPreferences("UsePlainPython"): args.append("--plain") try: wd = self.__sitePath() started, pid = QProcess.startDetached(args[0], args[1:], wd) if not started: E5MessageBox.critical(None, self.trUtf8('Process Generation Error'), self.trUtf8('The Django process could not be started.')) except DjangoNoSiteSelectedException: pass ################################################################## ## slots below implement caching functions ################################################################## def __createCacheTables(self): """ Private slot to create the tables for the SQL caching backend. """ title = self.trUtf8("Create Cache Tables") try: wd = self.__sitePath() except DjangoNoSiteSelectedException: return tblStr, ok = QInputDialog.getText( self.__ui, title, self.trUtf8("Enter the names of the cache tables separated by spaces."), QLineEdit.Normal) if ok and tblStr != "": tableNames = tblStr.split() args = [] args.append(self.__getPythonExecutable()) args.append("manage.py") args.append("createcachetable") args += tableNames dia = DjangoDialog(title, msgSuccess = self.trUtf8("Cache tables created successfully.")) res = dia.startProcess(args, wd) if res: dia.exec_() ################################################################## ## slots below implement testing functions ################################################################## def __dumpData(self): """ Private slot to dump the database data to a fixture. """ title = self.trUtf8("Dump Data") try: wd = self.__sitePath() except DjangoNoSiteSelectedException: return from .DjangoDumpdataDataDialog import DjangoDumpdataDataDialog dlg = DjangoDumpdataDataDialog(self, self.__ui) if dlg.exec_() == QDialog.Accepted: appls, excls, format, indent = dlg.getData() args = [] args.append(self.__getPythonExecutable()) args.append("manage.py") args.append("dumpdata") args.append("--format={0}".format(format)) args.append("--indent={0}".format(indent)) for excl in excls: args.append("--exclude={0}".format(excl)) args += appls if format == "json": fileFilters = self.trUtf8("JSON Files (*.json)") elif format == "xml": fileFilters = self.trUtf8("XML Files (*.xml)") elif format == "yaml": fileFilters = self.trUtf8("YAML Files (*.yaml)") dia = DjangoDialog(title, fixed = True, linewrap = False, saveFilters = fileFilters) res = dia.startProcess(args, wd, showCommand = False) if res: dia.exec_() def __loadData(self): """ Private slot to load data from fixture files. """ title = self.trUtf8("Load Data") try: wd = self.__sitePath() except DjangoNoSiteSelectedException: return from .DjangoLoaddataDataDialog import DjangoLoaddataDataDialog dlg = DjangoLoaddataDataDialog(self, self.__ui) if dlg.exec_() == QDialog.Accepted: fixtures = dlg.getData() args = [] args.append(self.__getPythonExecutable()) args.append("manage.py") args.append("loaddata") args += fixtures dia = DjangoDialog(title) res = dia.startProcess(args, wd) if res: dia.exec_() def __runTestSuite(self): """ Private slot to run the test suite for applications or the whole site. """ consoleCmd = self.__isSpawningConsole( self.__plugin.getPreferences("ConsoleCommandNoClose"))[1] if consoleCmd: try: wd = self.__sitePath() except DjangoNoSiteSelectedException: return args = Utilities.parseOptionString(consoleCmd) args[0] = Utilities.getExecutablePath(args[0]) args.append(self.__getPythonExecutable()) args.append("manage.py") args.append("test") args += self.__getApplications() started, pid = QProcess.startDetached(args[0], args[1:], wd) if not started: E5MessageBox.critical(None, self.trUtf8('Process Generation Error'), self.trUtf8('The Django process could not be started.')) def __runTestServer(self): """ Private slot to run a development server with data from a set of fixtures. """ consoleCmd = self.__isSpawningConsole( self.__plugin.getPreferences("ConsoleCommand"))[1] if consoleCmd: from .DjangoLoaddataDataDialog import DjangoLoaddataDataDialog dlg = DjangoLoaddataDataDialog(self, self.__ui) if dlg.exec_() == QDialog.Accepted: fixtures = dlg.getData() args = Utilities.parseOptionString(consoleCmd) args[0] = Utilities.getExecutablePath(args[0]) args.append(self.__getPythonExecutable()) args.append("manage.py") args.append("testserver") if self.__plugin.getPreferences("UseIPv6"): args.append("--ipv6") addr = self.__plugin.getPreferences("ServerAddress") if addr: args.append("--addrport=%s" % addr) args += fixtures try: if Utilities.isWindowsPlatform(): serverProcStarted, pid = \ QProcess.startDetached(args[0], args[1:], self.__sitePath()) else: if self.__testServerProc is not None: self.__testServerProcFinished() self.__testServerProc = QProcess() self.__testServerProc.finished.connect(self.__serverProcFinished) self.__testServerProc.setWorkingDirectory(self.__sitePath()) self.__testServerProc.start(args[0], args[1:]) serverProcStarted = self.__testServerProc.waitForStarted() if not serverProcStarted: E5MessageBox.critical(None, self.trUtf8('Process Generation Error'), self.trUtf8('The Django test server could not be started.')) except DjangoNoSiteSelectedException: pass def __testServerProcFinished(self): """ Private slot connected to the finished signal of the test server. """ if self.__testServerProc is not None and \ self.__testServerProc.state() != QProcess.NotRunning: self.__testServerProc.terminate() QTimer.singleShot(2000, self.__testServerProc.kill) self.__testServerProc.waitForFinished(3000) self.__testServerProc = None ################################################################## ## slots below implement authorization functions ################################################################## def __changePassword(self): """ Private slot to change the password of a user. """ consoleCmd = self.__isSpawningConsole( self.__plugin.getPreferences("ConsoleCommandNoClose"))[1] if consoleCmd: userName, ok = QInputDialog.getText( self.__ui, self.trUtf8("Change Password"), self.trUtf8("Enter the name of the user:"), QLineEdit.Normal) if ok and userName != "": args = Utilities.parseOptionString(consoleCmd) args[0] = Utilities.getExecutablePath(args[0]) args.append(self.__getPythonExecutable()) args.append("manage.py") args.append("changepassword") args.append(userName) try: wd = self.__sitePath() started, pid = QProcess.startDetached(args[0], args[1:], wd) if not started: E5MessageBox.critical(None, self.trUtf8('Process Generation Error'), self.trUtf8('The Django process could not be started.')) except DjangoNoSiteSelectedException: pass def __createSuperUser(self): """ Private slot to create a super user account. """ consoleCmd = self.__isSpawningConsole( self.__plugin.getPreferences("ConsoleCommandNoClose"))[1] if consoleCmd: args = Utilities.parseOptionString(consoleCmd) args[0] = Utilities.getExecutablePath(args[0]) args.append(self.__getPythonExecutable()) args.append("manage.py") args.append("createsuperuser") try: wd = self.__sitePath() started, pid = QProcess.startDetached(args[0], args[1:], wd) if not started: E5MessageBox.critical(None, self.trUtf8('Process Generation Error'), self.trUtf8('The Django process could not be started.')) except DjangoNoSiteSelectedException: pass ################################################################## ## slots below implement session functions ################################################################## def __clearSessions(self): """ Private slot to clear expired sessions. """ title = self.trUtf8("Clear Sessions") try: wd = self.__sitePath() except DjangoNoSiteSelectedException: return args = [] args.append(self.__getPythonExecutable()) args.append("manage.py") args.append("clearsessions") dia = DjangoDialog(title, msgSuccess = self.trUtf8("Expired sessions cleared successfully.")) res = dia.startProcess(args, wd) if res: dia.exec_() ################################################################## ## slots below implement translation functions ################################################################## def __getLocale(self, filename): """ Private method to extract the locale out of a file name. @param filename name of the file used for extraction (string) @return extracted locale (string) or None """ if self.__e5project.pdata["TRANSLATIONPATTERN"]: pattern = self.__e5project.pdata["TRANSLATIONPATTERN"][0]\ .replace("%language%", "(.*?)") match = re.search(pattern, filename) if match is not None: loc = match.group(1) return loc else: loc = None else: loc = None return loc def __normalizeList(self, filenames): """ Private method to normalize a list of file names. @param filenames list of file names to normalize (list of strings) @return normalized file names (list of strings) """ nfilenames = [] for filename in filenames: if filename.endswith(".mo"): filename = filename.replace(".mo", ".po") if filename not in nfilenames: nfilenames.append(filename) return nfilenames def __siteFilteredList(self, filenames): """ Private method to filter a list of file names by site. @param filenames list of file names to be filtered (list of strings) @return file names belonging to the current site (list of strings) """ site = self.__site() nfilenames = [] for filename in filenames: if site == "" or filename.startswith(site + os.sep): nfilenames.append(filename) return nfilenames def __projectLanguageAdded(self, code): """ Private slot handling the addition of a new language. @param code language code of the new language (string) """ title = self.trUtf8("Initializing message catalog for '{0}'").format(code) args = [] args.append(self.__getPythonExecutable()) args.append("manage.py") args.append("makemessages") args.append("-l") args.append(code) try: wd = self.__sitePath() except DjangoNoSiteSelectedException: E5MessageBox.warning(None, title, self.trUtf8('No current site selected or no site created yet.' ' Aborting...')) return dia = DjangoDialog(title, msgSuccess = \ self.trUtf8("\nMessage catalog initialized successfully.")) res = dia.startProcess(args, wd) if res: dia.exec_() langFile = self.__e5project.pdata["TRANSLATIONPATTERN"][0]\ .replace("%language%", code) self.__e5project.appendFile(langFile) def updateSelectedCatalogs(self, filenames): """ Public method to update the message catalogs. @param filenames list of file names (list of strings) """ title = self.trUtf8("Updating message catalogs") try: wd = self.__sitePath() except DjangoNoSiteSelectedException: E5MessageBox.warning(None, title, self.trUtf8('No current site selected or no site created yet.' ' Aborting...')) return argsLists = [] for filename in self.__normalizeList(self.__siteFilteredList(filenames)): locale = self.__getLocale(filename) if locale: args = [] args.append(self.__getPythonExecutable()) args.append("manage.py") args.append("makemessages") args.append("--no-obsolete") args.append("-l") args.append(locale) argsLists.append(args) if len(argsLists) == 0: E5MessageBox.warning(None, title, self.trUtf8('No locales detected. Aborting...')) return dia = DjangoDialog(title, msgSuccess = \ self.trUtf8("\nMessage catalogs updated successfully.")) res = dia.startBatchProcesses(argsLists, wd) if res: dia.exec_() def updateSelectedCatalogsWithObsolete(self, filenames): """ Public method to update the message catalogs keeping obsolete messages. @param filenames list of filenames """ title = self.trUtf8("Updating message catalogs (keeping obsolete messages)") try: wd = self.__sitePath() except DjangoNoSiteSelectedException: E5MessageBox.warning(None, title, self.trUtf8('No current site selected or no site created yet.' ' Aborting...')) return argsLists = [] for filename in self.__normalizeList(self.__siteFilteredList(filenames)): locale = self.__getLocale(filename) if locale: args = [] args.append(self.__getPythonExecutable()) args.append("manage.py") args.append("makemessages") args.append("-l") args.append(locale) argsLists.append(args) if len(argsLists) == 0: E5MessageBox.warning(None, title, self.trUtf8('No locales detected. Aborting...')) return dia = DjangoDialog(title, msgSuccess = \ self.trUtf8("\nMessage catalogs updated successfully.")) res = dia.startBatchProcesses(argsLists, wd) if res: dia.exec_() def updateCatalogs(self, filenames): """ Public method to update the message catalogs. @param filenames list of filenames (not used) """ title = self.trUtf8("Updating message catalogs") args = [] args.append(self.__getPythonExecutable()) args.append("manage.py") args.append("makemessages") args.append("-a") args.append("--no-obsolete") try: wd = self.__sitePath() except DjangoNoSiteSelectedException: E5MessageBox.warning(None, title, self.trUtf8('No current site selected or no site created yet.' ' Aborting...')) return dia = DjangoDialog(title, msgSuccess = \ self.trUtf8("\nMessage catalogs updated successfully.")) res = dia.startProcess(args, wd) if res: dia.exec_() def updateCatalogsWithObsolete(self, filenames): """ Public method to update the message catalogs keeping obsolete messages. @param filenames list of filenames (not used) """ title = self.trUtf8("Updating message catalogs (keeping obsolete messages)") args = [] args.append(self.__getPythonExecutable()) args.append("manage.py") args.append("makemessages") args.append("-a") try: wd = self.__sitePath() except DjangoNoSiteSelectedException: E5MessageBox.warning(None, title, self.trUtf8('No current site selected or no site created yet.' ' Aborting...')) return dia = DjangoDialog(title, msgSuccess = \ self.trUtf8("\nMessage catalogs updated successfully.")) res = dia.startProcess(args, wd) if res: dia.exec_() def compileSelectedCatalogs(self, filenames): """ Public method to update the message catalogs. @param filenames list of filenames """ title = self.trUtf8("Compiling message catalogs") try: wd = self.__sitePath() except DjangoNoSiteSelectedException: E5MessageBox.warning(None, title, self.trUtf8('No current site selected or no site created yet.' ' Aborting...')) return argsLists = [] for filename in self.__normalizeList(self.__siteFilteredList(filenames)): locale = self.__getLocale(filename) if locale: args = [] args.append(self.__getPythonExecutable()) args.append("manage.py") args.append("compilemessages") args.append("-l") args.append(locale) argsLists.append(args) if len(argsLists) == 0: E5MessageBox.warning(None, title, self.trUtf8('No locales detected. Aborting...')) return dia = DjangoDialog(title, msgSuccess = \ self.trUtf8("\nMessage catalogs compiled successfully.")) res = dia.startBatchProcesses(argsLists, wd, mergedOutput = True) if res: dia.exec_() for entry in os.walk(self.__sitePath()): for fileName in entry[2]: fullName = os.path.join(entry[0], fileName) if fullName.endswith('.mo'): self.__e5project.appendFile(fullName) def compileCatalogs(self, filenames): """ Public method to compile the message catalogs. @param filenames list of filenames (not used) """ title = self.trUtf8("Compiling message catalogs") args = [] args.append(self.__getPythonExecutable()) args.append("manage.py") args.append("compilemessages") try: wd = self.__sitePath() except DjangoNoSiteSelectedException: E5MessageBox.warning(None, title, self.trUtf8('No current site selected or no site created yet.' ' Aborting...')) return dia = DjangoDialog(title, msgSuccess = \ self.trUtf8("\nMessage catalogs compiled successfully.")) res = dia.startProcess(args, wd, mergedOutput = True) if res: dia.exec_() for entry in os.walk(self.__sitePath()): for fileName in entry[2]: fullName = os.path.join(entry[0], fileName) if fullName.endswith('.mo'): self.__e5project.appendFile(fullName)