ProjectPyramid/Project.py

changeset 2
e691c51ab655
child 3
76c45d31d462
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ProjectPyramid/Project.py	Tue Aug 28 17:15:21 2012 +0200
@@ -0,0 +1,796 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2012 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing the Pyramid project support.
+"""
+
+import os
+import configparser
+
+from PyQt4.QtCore import QObject, QFileInfo, QProcess, QTimer, QUrl
+from PyQt4.QtGui import QMenu, QDialog, QInputDialog, QDesktopServices
+
+from E5Gui.E5Application import e5App
+from E5Gui import E5MessageBox, E5FileDialog
+from E5Gui.E5Action import E5Action
+
+from .FormSelectionDialog import FormSelectionDialog
+from .CreateParametersDialog import CreateParametersDialog
+from .PyramidDialog import PyramidDialog
+from .DistributionTypeSelectionDialog import DistributionTypeSelectionDialog
+
+import Utilities
+from Globals import isWindowsPlatform
+import UI.PixmapCache
+
+
+class PyramidNoProjectSelectedException(Exception):
+    """
+    Exception thrown to signal, that there is no current Pyramid project.
+    """
+    pass
+
+
+class Project(QObject):
+    """
+    Class implementing the Pyramid project support.
+    """
+    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
+    
+    def initActions(self):
+        """
+        Public method to define the Pyramid actions.
+        """
+        self.actions = []
+    
+        self.selectProjectAct = E5Action(self.trUtf8('Current Pyramid Project'),
+                "",
+                0, 0,
+                self,'pyramid_current_project')
+        self.selectProjectAct.setStatusTip(self.trUtf8(
+            'Selects the current Pyramid project'))
+        self.selectProjectAct.setWhatsThis(self.trUtf8(
+            """<b>Current Pyramid Project</b>"""
+            """<p>Selects the Pyramid project. Used for multi-project """
+            """Pyramid projects to switch between the projects.</p>"""
+        ))
+        self.selectProjectAct.triggered[()].connect(self.__selectProject)
+        self.actions.append(self.selectProjectAct)
+        self.__setCurrentProject(None)
+        
+        ###############################
+        ## create actions below      ##
+        ###############################
+        
+        self.createProjectAct = E5Action(self.trUtf8('Create Pyramid Project'),
+                self.trUtf8('Create Pyramid &Project'), 
+                0, 0,
+                self,'pyramid_create_project')
+        self.createProjectAct.setStatusTip(self.trUtf8(
+            'Creates a new Pyramid project'))
+        self.createProjectAct.setWhatsThis(self.trUtf8(
+            """<b>Create Pyramid Project</b>"""
+            """<p>Creates a new Pyramid project using "pcreate".</p>"""
+        ))
+        self.createProjectAct.triggered[()].connect(self.__createProject)
+        self.actions.append(self.createProjectAct)
+        
+        ##############################
+        ## run actions below        ##
+        ##############################
+        
+        self.runServerAct = E5Action(self.trUtf8('Run Server'),
+                self.trUtf8('Run &Server'), 
+                0, 0,
+                self,'pyramid_run_server')
+        self.runServerAct.setStatusTip(self.trUtf8(
+            'Starts the Pyramid Web server'))
+        self.runServerAct.setWhatsThis(self.trUtf8(
+            """<b>Run Server</b>"""
+            """<p>Starts the Pyramid Web server using"""
+            """ "pserve --reload development.ini".</p>"""
+        ))
+        self.runServerAct.triggered[()].connect(self.__runServer)
+        self.actions.append(self.runServerAct)
+        
+        self.runLoggingServerAct = E5Action(self.trUtf8('Run Server with Logging'),
+                self.trUtf8('Run Server with &Logging'), 
+                0, 0,
+                self,'pyramid_run_logging_server')
+        self.runLoggingServerAct.setStatusTip(self.trUtf8(
+            'Starts the Pyramid Web server with logging'))
+        self.runLoggingServerAct.setWhatsThis(self.trUtf8(
+            """<b>Run Server with Logging</b>"""
+            """<p>Starts the Pyramid Web server with logging using"""
+            """ "pserve --log-file=server.log --reload development.ini".</p>"""
+        ))
+        self.runLoggingServerAct.triggered[()].connect(self.__runLoggingServer)
+        self.actions.append(self.runLoggingServerAct)
+        
+        self.runBrowserAct = E5Action(self.trUtf8('Run Web-Browser'),
+                self.trUtf8('Run &Web-Browser'), 
+                0, 0,
+                self,'pyramid_run_browser')
+        self.runBrowserAct.setStatusTip(self.trUtf8(
+            'Starts the default Web-Browser with the URL of the Pyramid Web server'))
+        self.runBrowserAct.setWhatsThis(self.trUtf8(
+            """<b>Run Web-Browser</b>"""
+            """<p>Starts the default Web-Browser with the URL of the """
+            """Pyramid Web server.</p>"""
+        ))
+        self.runBrowserAct.triggered[()].connect(self.__runBrowser)
+        self.actions.append(self.runBrowserAct)
+    
+        self.runPythonShellAct = E5Action(self.trUtf8('Start Pyramid Python Console'),
+                self.trUtf8('Start Pyramid &Python Console'), 
+                0, 0,
+                self,'pyramid_python_console')
+        self.runPythonShellAct.setStatusTip(self.trUtf8(
+            'Starts an interactive Python interpreter'))
+        self.runPythonShellAct.setWhatsThis(self.trUtf8(
+            """<b>Start Pyramid Python Console</b>"""
+            """<p>Starts an interactive Python interpreter.</p>"""
+        ))
+        self.runPythonShellAct.triggered[()].connect(self.__runPythonShell)
+        self.actions.append(self.runPythonShellAct)
+        
+        ##############################
+        ## setup actions below      ##
+        ##############################
+        
+        self.setupDevelopAct = E5Action(self.trUtf8('Setup Development Environment'),
+                self.trUtf8('Setup &Development Environment'), 
+                0, 0,
+                self,'pyramid_setup_development')
+        self.setupDevelopAct.setStatusTip(self.trUtf8(
+            'Setup the Pyramid project in development mode'))
+        self.setupDevelopAct.setWhatsThis(self.trUtf8(
+            """<b>Setup Development Environment</b>"""
+            """<p>Setup the Pyramid project in development mode using"""
+            """ "python setup.py develop".</p>"""
+        ))
+        self.setupDevelopAct.triggered[()].connect(self.__setupDevelop)
+        self.actions.append(self.setupDevelopAct)
+         
+        ##################################
+        ## distribution actions below   ##
+        ##################################
+        
+        self.buildDistroAct = E5Action(self.trUtf8('Build Distribution'),
+                self.trUtf8('Build &Distribution'), 
+                0, 0,
+                self,'pyramid_build_distribution')
+        self.buildDistroAct.setStatusTip(self.trUtf8(
+            'Builds a distribution file for the Pyramid project'))
+        self.buildDistroAct.setWhatsThis(self.trUtf8(
+            """<b>Build Distribution</b>"""
+            """<p>Builds a distribution file for the Pyramid project using"""
+            """ "python setup.py sdist".</p>"""
+        ))
+        self.buildDistroAct.triggered[()].connect(self.__buildDistribution)
+        self.actions.append(self.buildDistroAct)
+        
+        ##################################
+        ## documentation action below   ##
+        ##################################
+        
+        self.documentationAct = E5Action(self.trUtf8('Documentation'),
+                self.trUtf8('D&ocumentation'), 
+                0, 0,
+                self,'pyramid_documentation')
+        self.documentationAct.setStatusTip(self.trUtf8(
+            'Shows the help viewer with the Pyramid documentation'))
+        self.documentationAct.setWhatsThis(self.trUtf8(
+            """<b>Documentation</b>"""
+            """<p>Shows the help viewer with the Pyramid documentation.</p>"""
+        ))
+        self.documentationAct.triggered[()].connect(self.__showDocumentation)
+        self.actions.append(self.documentationAct)
+       
+        ##############################
+        ## about action below       ##
+        ##############################
+        
+        self.aboutPyramidAct = E5Action(self.trUtf8('About Pyramid'),
+                self.trUtf8('About P&yramid'), 
+                0, 0,
+                self,'pyramid_about')
+        self.aboutPyramidAct.setStatusTip(self.trUtf8(
+            'Shows some information about Pyramid'))
+        self.aboutPyramidAct.setWhatsThis(self.trUtf8(
+            """<b>About Pyramid</b>"""
+            """<p>Shows some information about Pyramid.</p>"""
+        ))
+        self.aboutPyramidAct.triggered[()].connect(self.__pyramidInfo)
+        self.actions.append(self.aboutPyramidAct)
+    
+    def initMenu(self):
+        """
+        Public slot to initialize the Pyramid menu.
+        
+        @return the menu generated (QMenu)
+        """
+        menu = QMenu(self.trUtf8('P&yramid'), self.__ui)
+        menu.setTearOffEnabled(True)
+        
+        menu.addAction(self.selectProjectAct)
+        menu.addSeparator()
+        menu.addAction(self.runServerAct)
+        menu.addAction(self.runLoggingServerAct)
+        menu.addAction(self.runBrowserAct)
+        menu.addSeparator()
+        menu.addAction(self.createProjectAct)
+        menu.addSeparator()
+        menu.addAction(self.setupDevelopAct)
+        menu.addSeparator()
+        menu.addAction(self.runPythonShellAct)
+        menu.addSeparator()
+        menu.addAction(self.buildDistroAct)
+        menu.addSeparator()
+        menu.addAction(self.documentationAct)
+        menu.addSeparator()
+        menu.addAction(self.aboutPyramidAct)
+        
+        self.__mainMenu = menu
+        return menu
+    
+    def projectOpenedHooks(self):
+        """
+        Public method to add our hook methods.
+        """
+        if self.__e5project.getProjectType() == "Pyramid":
+            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("extractMessages", 
+##                self.extractMessages, self.trUtf8("Extract messages"))
+##            self.__translationsBrowser.addHookMethodAndMenuEntry("releaseAll", 
+##                self.compileCatalogs, self.trUtf8("Compile all catalogs"))
+##            self.__translationsBrowser.addHookMethodAndMenuEntry("releaseSelected", 
+##                self.compileSelectedCatalogs, 
+##                self.trUtf8("Compile selected catalogs"))
+##            self.__translationsBrowser.addHookMethodAndMenuEntry("generateAll", 
+##                self.updateCatalogs, self.trUtf8("Update all catalogs"))
+##            self.__translationsBrowser.addHookMethodAndMenuEntry("generateSelected", 
+##                self.updateSelectedCatalogs, self.trUtf8("Update 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("extractMessages")
+##            self.__translationsBrowser.removeHookMethod("releaseAll")
+##            self.__translationsBrowser.removeHookMethod("releaseSelected")
+##            self.__translationsBrowser.removeHookMethod("generateAll")
+##            self.__translationsBrowser.removeHookMethod("generateSelected")
+##            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)
+        """
+        dlg = FormSelectionDialog()
+        if dlg.exec_() == QDialog.Accepted:
+            template = dlg.getTemplateText()
+            
+            filter = self.trUtf8(
+                "Chameleon Templates (*.pt);;"
+                "Chameleon Text Templates (*.txt);;"
+                "Mako Templates (*.mako);;"
+                "Mako Templates (*.mak);;"
+                "HTML Files (*.html);;"
+                "HTML Files (*.htm);;"
+                "All Files (*)")
+            fname, selectedFilter = E5FileDialog.getSaveFileNameAndFilter(
+                self.__ui,
+                self.trUtf8("New Form"),
+                path,
+                filter,
+                None,
+                E5FileDialog.Options(E5FileDialog.DontConfirmOverwrite))
+            if fname:
+                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", encoding="utf-8")
+                    f.write(template)
+                    f.close()
+                except IOError as e:
+                    E5MessageBox.critical(self,
+                        self.trUtf8("New Form"),
+                        self.trUtf8("<p>The new form file <b>{0}</b> could not be"
+                            " created.<br/>"
+                            "Problem: {1}</p>").format(fname, e))
+                    return
+                
+                self.__e5project.appendFile(fname)
+                self.__formsBrowser.sourceFile.emit(fname)
+
+    ##################################################################
+    ## methods 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.__setCurrentProject(None)
+    
+    def __getVirtualEnvironment(self):
+        """
+        Private method to get the path of the virtual environment.
+        
+        @return path of the virtual environment (string)
+        """
+        language = self.__e5project.getProjectLanguage()
+        if language == "Python3":
+            virtEnv = self.__plugin.getPreferences("VirtualEnvironmentPy3")
+        elif language == "Python2":
+            virtEnv = self.__plugin.getPreferences("VirtualEnvironmentPy2")
+        else:
+            virtEnv = ""
+        if virtEnv and not os.path.exists(virtEnv):
+            virtEnv = ""
+        return virtEnv
+    
+    def getPyramidCommand(self, cmd):
+        """
+        Public method to build a Pyramid command.
+        
+        @param cmd command (string)
+        @return full pyramid command (string)
+        """
+        virtualEnv = self.__getVirtualEnvironment()
+        if virtualEnv:
+            if isWindowsPlatform():
+                cmd = os.path.join(virtualEnv, "Scripts", cmd)
+            else:
+                cmd = os.path.join(virtualEnv, "bin", cmd)
+        return cmd
+    
+    def getPythonCommand(self):
+        """
+        Public method to build the Python command.
+        
+        @return python command (string)
+        """
+        python = "python"
+        if isWindowsPlatform():
+            python += ".exe"
+        virtualEnv = self.__getVirtualEnvironment()
+        if virtualEnv:
+            if isWindowsPlatform():
+                python = os.path.join(virtualEnv, "Scripts", python)
+            else:
+                python = os.path.join(virtualEnv, "bin", python)
+        return python
+    
+    def __pyramidInfo(self):
+        """
+        Private slot to show some info about Pyramid.
+        """
+        url = "http://www.pylonsproject.org/projects/pyramid/about"
+        msgBox = E5MessageBox.E5MessageBox(E5MessageBox.Question,
+            self.trUtf8("About Pyramid"),
+            self.trUtf8(
+                "<p>Pyramid is a high-level Python Web framework that encourages rapid "
+                "development and clean, pragmatic design.</p>"
+                "<p>URL: <a href=\"{0}\">{0}</a></p>"
+            ).format(url),
+            modal=True,
+            buttons=E5MessageBox.Ok)
+        msgBox.setIconPixmap(UI.PixmapCache.getPixmap(
+            os.path.join("ProjectPyramid", "icons", "pyramid64.png")))
+        msgBox.exec_()
+    
+    def isSpawningConsole(self, consoleCmd):
+        """
+        Public 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 __createProject(self):
+        """
+        Private slot to create a new Pyramid project.
+        """
+        dlg = CreateParametersDialog(self)
+        if dlg.exec_() == QDialog.Accepted:
+            scaffold, project, overwrite, simulate = dlg.getData()
+            
+            cmd = self.getPyramidCommand("pcreate")
+            args = []
+            if overwrite:
+                args.append("--overwrite")
+            else:
+                args.append("--interactive")
+            if simulate:
+                args.append("--simulate")
+            args.append("--scaffold={0}".format(scaffold))
+            args.append(project)
+            dlg = PyramidDialog(self.trUtf8("Create Pyramid Project"),
+                linewrap=False, parent=self.__ui)
+            if dlg.startProcess(cmd, args, self.__e5project.getProjectPath()):
+                dlg.exec_()
+                if dlg.normalExit() and not simulate:
+                    # search for files created by pcreate and add them to the project
+                    projectPath = os.path.join(self.__e5project.getProjectPath(), project)
+                    for entry in os.walk(projectPath):
+                        for fileName in entry[2]:
+                            fullName = os.path.join(entry[0], fileName)
+                            self.__e5project.appendFile(fullName)
+                    
+                    # create the base directory for translations
+                    i18nPath = os.path.join(projectPath, project.lower(), "i18n")
+                    if not os.path.exists(i18nPath):
+                        os.makedirs(i18nPath)
+                    self.__e5project.setDirty(True)
+                    
+                    self.__setCurrentProject(project)
+    
+    ##################################################################
+    ## methods below implement site related functions
+    ##################################################################
+    
+    def __findProjects(self):
+        """
+        Private method to determine the relative path of all Pyramid 
+        projects (= top level dirs).
+        
+        @return list of projects (list of string)
+        """
+        projects = []
+        ppath = self.__e5project.getProjectPath()
+        for entry in os.listdir(ppath):
+            if entry[0] not in "._" and \
+               os.path.isdir(os.path.join(ppath, entry)):
+                projects.append(entry)
+        return projects
+    
+    def __selectProject(self):
+        """
+        Private method to select a Pyramid project to work with.
+        
+        @return selected project (string)
+        """
+        projects = self.__findProjects()
+        if len(projects) == 0:
+            project = None
+        elif len(projects) == 1:
+            project = projects[0]
+        else:
+            if self.__currentProject is not None:
+                try:
+                    cur = projects.index(self.__currentProject)
+                except ValueError:
+                    cur = 0
+            else:
+                cur = 0
+            project, ok = QInputDialog.getItem(
+                self.__ui,
+                self.trUtf8("Select Pyramid Project"),
+                self.trUtf8("Select the Pyramid project to work with."),
+                projects,
+                cur, False)
+            if not ok:
+                projects = None
+        self.__setCurrentProject(project)
+    
+    def __projectPath(self):
+        """
+        Private method to calculate the full path of the Pyramid project.
+        
+        @exception PyramidNoProjectSelectedException raised, if no project is selected
+        @return path of the project (string)
+        """
+        if self.__currentProject is None:
+            self.__selectProject()
+        
+        if self.__currentProject is None:
+            raise PyramidNoProjectSelectedException
+        else:
+            return os.path.join(self.__e5project.getProjectPath(), 
+                                self.__currentProject)
+    
+    def __setCurrentProject(self, project):
+        """
+        Private slot to set the current project.
+        
+        @param project name of the project (string)
+        """
+        if project is not None and len(project) == 0:
+            self.__currentProject = None
+        else:
+            self.__currentProject = project
+        
+        if self.__currentProject is None:
+            curProject = self.trUtf8("None")
+        else:
+            curProject = self.__currentProject
+        self.selectProjectAct.setText(
+            self.trUtf8('&Current Pyramid Project ({0})').format(curProject))
+        
+        if self.__currentProject is None:
+            self.__e5project.pdata["TRANSLATIONPATTERN"] = []
+        else:
+            # TODO: adjust this to the Pyramid docu
+            self.__e5project.pdata["TRANSLATIONPATTERN"] = [
+                os.path.join(project, project.lower(), "i18n", "%language%", 
+                    "LC_MESSAGES", "%s.po" % project.lower())
+            ]
+    
+    def __project(self):
+        """
+        Private method to get the name of the current Pyramid project.
+        
+        @exception PyramidNoProjectSelectedException raised, if no project is selected
+        @return name of the project (string)
+        """
+        if self.__currentProject is None:
+            self.__selectProject()
+        
+        if self.__currentProject is None:
+            raise PyramidNoProjectSelectedException
+        else:
+            return self.__currentProject
+    
+    ##################################################################
+    ## 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 (boolean)
+        """
+        consoleCmd = self.isSpawningConsole(
+            self.__plugin.getPreferences("ConsoleCommand"))[1]
+        if consoleCmd:
+            try:
+                projectPath = self.__projectPath()
+            except PyramidNoProjectSelectedException:
+                E5MessageBox.warning(self.__ui,
+                    self.trUtf8('Run Server'),
+                    self.trUtf8('No current Pyramid project selected or no Pyramid '
+                                'project created yet. Aborting...'))
+                return
+            
+            args = Utilities.parseOptionString(consoleCmd)
+            args[0] = Utilities.getExecutablePath(args[0])
+            args.append(self.getPyramidCommand("pserve"))
+            if logging:
+                args.append("--log-file=server.log")
+            args.append("--reload")
+            args.append(os.path.join(projectPath, "development.ini"))
+            
+            if isWindowsPlatform():
+                serverProcStarted, pid = \
+                    QProcess.startDetached(args[0], args[1:], projectPath)
+            else:
+                if self.__serverProc is not None:
+                    self.__serverProcFinished()
+                
+                self.__serverProc = QProcess()
+                self.__serverProc.finished.connect(self.__serverProcFinished)
+                self.__serverProc.setWorkingDirectory(projectPath)
+                self.__serverProc.start(args[0], args[1:])
+                serverProcStarted = self.__serverProc.waitForStarted()
+            if not serverProcStarted:
+                E5MessageBox.critical(self.__ui,
+                    self.trUtf8('Process Generation Error'),
+                    self.trUtf8('The Pyramid server could not be started.'))
+    
+    def __runLoggingServer(self):
+        """
+        Private slot to start the Pyramid Web server with logging.
+        """
+        self.__runServer(True)
+    
+    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.
+        """
+        try:
+            projectPath = self.__projectPath()
+        except PyramidNoProjectSelectedException:
+            E5MessageBox.warning(self.__ui,
+                self.trUtf8('Run Web-Browser'),
+                self.trUtf8('No current Pyramid project selected or no Pyramid project'
+                            ' created yet. Aborting...'))
+            return
+        
+        config = configparser.ConfigParser()
+        config.read(os.path.join(projectPath, "development.ini"))
+        port = config.get("server:main", "port", fallback="6543")
+        url = QUrl("http://localhost:{0}".format(port))
+        res = QDesktopServices.openUrl(url)
+        if not res:
+            E5MessageBox.critical(self.__ui,
+                self.trUtf8('Run Web-Browser'),
+                self.trUtf8('Could not start the web-browser for the URL "{0}".')\
+                    .format(url.toString()))
+    
+    def __runPythonShell(self):
+        """
+        Private slot to start a Python console for a Pyramid project.
+        """
+        consoleCmd = self.isSpawningConsole(
+            self.__plugin.getPreferences("ConsoleCommand"))[1]
+        if consoleCmd:
+            try:
+                projectPath = self.__projectPath()
+            except PyramidNoProjectSelectedException:
+                E5MessageBox.warning(self.__ui,
+                    self.trUtf8('Start Pyramid Python Console'),
+                    self.trUtf8('No current Pyramid project selected or no Pyramid '
+                                'project created yet. Aborting...'))
+                return
+            
+            args = Utilities.parseOptionString(consoleCmd)
+            args[0] = Utilities.getExecutablePath(args[0])
+            args.append(self.getPyramidCommand("pshell"))
+            language = self.__e5project.getProjectLanguage()
+            if language == "Python2":
+                consoleType = self.__plugin.getPreferences("Python2ConsoleType")
+            else:
+                consoleType = self.__plugin.getPreferences("Python3ConsoleType")
+            args.append("--python-shell={0}".format(consoleType))
+            args.append(os.path.join(projectPath, "development.ini"))
+            
+            started, pid = QProcess.startDetached(args[0], args[1:], projectPath)
+            if not started:
+                E5MessageBox.critical(self.__ui,
+                    self.trUtf8('Process Generation Error'),
+                    self.trUtf8('The Pyramid Shell process could not be started.'))
+
+    ##################################################################
+    ## slots below implement setup functions
+    ##################################################################
+    
+    def __setupDevelop(self):
+        """
+        Private slot to set up the development environment for the current project.
+        """
+        title = self.trUtf8("Setup Development Environment")
+        
+        cmd = self.getPythonCommand()
+        args = []
+        args.append("setup.py")
+        args.append("develop")
+        
+        try:
+            wd = self.__projectPath()
+        except PyramidNoProjectSelectedException:
+            E5MessageBox.warning(self.__ui,
+                title,
+                self.trUtf8('No current Pyramid project selected or no Pyramid project'
+                            ' created yet. Aborting...'))
+            return
+        
+        dia = PyramidDialog(title, 
+            msgSuccess = \
+                self.trUtf8("Pyramid development environment setup successfully."))
+        res = dia.startProcess(cmd, args, wd)
+        if res:
+            dia.exec_()
+    
+    ##################################################################
+    ## slots below implement distribution functions
+    ##################################################################
+    
+    def __buildDistribution(self):
+        """
+        Private slot to build a distribution file for the current Pyramid project.
+        """
+        title = self.trUtf8("Build Distribution File")
+        try:
+            projectPath = self.__projectPath()
+        except PyramidNoProjectSelectedException:
+            E5MessageBox.warning(self.__ui,
+                title,
+                self.trUtf8('No current Pyramid project selected or no Pyramid project'
+                            ' created yet. Aborting...'))
+            return
+        
+        dlg = DistributionTypeSelectionDialog(self, projectPath, self.__ui)
+        if dlg.exec_() == QDialog.Accepted:
+            formats = dlg.getFormats()
+            cmd = self.getPythonCommand()
+            args = []
+            args.append("setup.py")
+            args.append("sdist")
+            if formats:
+                args.append("--formats={0}".format(','.join(formats)))
+            
+            dia = PyramidDialog(title, 
+                msgSuccess = \
+                    self.trUtf8("Python distribution file built successfully."))
+            res = dia.startProcess(cmd, args, projectPath)
+            if res:
+                dia.exec_()
+    
+    ##################################################################
+    ## slots below implement documentation functions
+    ##################################################################
+    
+    def __showDocumentation(self):
+        """
+        Private slot to show the helpviewer with the Pylons documentation.
+        """
+        page = self.__plugin.getPreferences("PyramidDocUrl")
+        self.__ui.launchHelpViewer(page)

eric ide

mercurial