|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2012 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 """ |
|
7 Module implementing the Pyramid project support. |
|
8 """ |
|
9 |
|
10 import os |
|
11 import configparser |
|
12 |
|
13 from PyQt4.QtCore import QObject, QFileInfo, QProcess, QTimer, QUrl |
|
14 from PyQt4.QtGui import QMenu, QDialog, QInputDialog, QDesktopServices |
|
15 |
|
16 from E5Gui.E5Application import e5App |
|
17 from E5Gui import E5MessageBox, E5FileDialog |
|
18 from E5Gui.E5Action import E5Action |
|
19 |
|
20 from .FormSelectionDialog import FormSelectionDialog |
|
21 from .CreateParametersDialog import CreateParametersDialog |
|
22 from .PyramidDialog import PyramidDialog |
|
23 from .DistributionTypeSelectionDialog import DistributionTypeSelectionDialog |
|
24 |
|
25 import Utilities |
|
26 from Globals import isWindowsPlatform |
|
27 import UI.PixmapCache |
|
28 |
|
29 |
|
30 class PyramidNoProjectSelectedException(Exception): |
|
31 """ |
|
32 Exception thrown to signal, that there is no current Pyramid project. |
|
33 """ |
|
34 pass |
|
35 |
|
36 |
|
37 class Project(QObject): |
|
38 """ |
|
39 Class implementing the Pyramid project support. |
|
40 """ |
|
41 def __init__(self, plugin, parent = None): |
|
42 """ |
|
43 Constructor |
|
44 |
|
45 @param plugin reference to the plugin object |
|
46 @param parent parent (QObject) |
|
47 """ |
|
48 super().__init__(parent) |
|
49 |
|
50 self.__plugin = plugin |
|
51 self.__ui = parent |
|
52 self.__e5project = e5App().getObject("Project") |
|
53 self.__hooksInstalled = False |
|
54 |
|
55 self.__mainMenu = None |
|
56 |
|
57 self.__serverProc = None |
|
58 |
|
59 def initActions(self): |
|
60 """ |
|
61 Public method to define the Pyramid actions. |
|
62 """ |
|
63 self.actions = [] |
|
64 |
|
65 self.selectProjectAct = E5Action(self.trUtf8('Current Pyramid Project'), |
|
66 "", |
|
67 0, 0, |
|
68 self,'pyramid_current_project') |
|
69 self.selectProjectAct.setStatusTip(self.trUtf8( |
|
70 'Selects the current Pyramid project')) |
|
71 self.selectProjectAct.setWhatsThis(self.trUtf8( |
|
72 """<b>Current Pyramid Project</b>""" |
|
73 """<p>Selects the Pyramid project. Used for multi-project """ |
|
74 """Pyramid projects to switch between the projects.</p>""" |
|
75 )) |
|
76 self.selectProjectAct.triggered[()].connect(self.__selectProject) |
|
77 self.actions.append(self.selectProjectAct) |
|
78 self.__setCurrentProject(None) |
|
79 |
|
80 ############################### |
|
81 ## create actions below ## |
|
82 ############################### |
|
83 |
|
84 self.createProjectAct = E5Action(self.trUtf8('Create Pyramid Project'), |
|
85 self.trUtf8('Create Pyramid &Project'), |
|
86 0, 0, |
|
87 self,'pyramid_create_project') |
|
88 self.createProjectAct.setStatusTip(self.trUtf8( |
|
89 'Creates a new Pyramid project')) |
|
90 self.createProjectAct.setWhatsThis(self.trUtf8( |
|
91 """<b>Create Pyramid Project</b>""" |
|
92 """<p>Creates a new Pyramid project using "pcreate".</p>""" |
|
93 )) |
|
94 self.createProjectAct.triggered[()].connect(self.__createProject) |
|
95 self.actions.append(self.createProjectAct) |
|
96 |
|
97 ############################## |
|
98 ## run actions below ## |
|
99 ############################## |
|
100 |
|
101 self.runServerAct = E5Action(self.trUtf8('Run Server'), |
|
102 self.trUtf8('Run &Server'), |
|
103 0, 0, |
|
104 self,'pyramid_run_server') |
|
105 self.runServerAct.setStatusTip(self.trUtf8( |
|
106 'Starts the Pyramid Web server')) |
|
107 self.runServerAct.setWhatsThis(self.trUtf8( |
|
108 """<b>Run Server</b>""" |
|
109 """<p>Starts the Pyramid Web server using""" |
|
110 """ "pserve --reload development.ini".</p>""" |
|
111 )) |
|
112 self.runServerAct.triggered[()].connect(self.__runServer) |
|
113 self.actions.append(self.runServerAct) |
|
114 |
|
115 self.runLoggingServerAct = E5Action(self.trUtf8('Run Server with Logging'), |
|
116 self.trUtf8('Run Server with &Logging'), |
|
117 0, 0, |
|
118 self,'pyramid_run_logging_server') |
|
119 self.runLoggingServerAct.setStatusTip(self.trUtf8( |
|
120 'Starts the Pyramid Web server with logging')) |
|
121 self.runLoggingServerAct.setWhatsThis(self.trUtf8( |
|
122 """<b>Run Server with Logging</b>""" |
|
123 """<p>Starts the Pyramid Web server with logging using""" |
|
124 """ "pserve --log-file=server.log --reload development.ini".</p>""" |
|
125 )) |
|
126 self.runLoggingServerAct.triggered[()].connect(self.__runLoggingServer) |
|
127 self.actions.append(self.runLoggingServerAct) |
|
128 |
|
129 self.runBrowserAct = E5Action(self.trUtf8('Run Web-Browser'), |
|
130 self.trUtf8('Run &Web-Browser'), |
|
131 0, 0, |
|
132 self,'pyramid_run_browser') |
|
133 self.runBrowserAct.setStatusTip(self.trUtf8( |
|
134 'Starts the default Web-Browser with the URL of the Pyramid Web server')) |
|
135 self.runBrowserAct.setWhatsThis(self.trUtf8( |
|
136 """<b>Run Web-Browser</b>""" |
|
137 """<p>Starts the default Web-Browser with the URL of the """ |
|
138 """Pyramid Web server.</p>""" |
|
139 )) |
|
140 self.runBrowserAct.triggered[()].connect(self.__runBrowser) |
|
141 self.actions.append(self.runBrowserAct) |
|
142 |
|
143 self.runPythonShellAct = E5Action(self.trUtf8('Start Pyramid Python Console'), |
|
144 self.trUtf8('Start Pyramid &Python Console'), |
|
145 0, 0, |
|
146 self,'pyramid_python_console') |
|
147 self.runPythonShellAct.setStatusTip(self.trUtf8( |
|
148 'Starts an interactive Python interpreter')) |
|
149 self.runPythonShellAct.setWhatsThis(self.trUtf8( |
|
150 """<b>Start Pyramid Python Console</b>""" |
|
151 """<p>Starts an interactive Python interpreter.</p>""" |
|
152 )) |
|
153 self.runPythonShellAct.triggered[()].connect(self.__runPythonShell) |
|
154 self.actions.append(self.runPythonShellAct) |
|
155 |
|
156 ############################## |
|
157 ## setup actions below ## |
|
158 ############################## |
|
159 |
|
160 self.setupDevelopAct = E5Action(self.trUtf8('Setup Development Environment'), |
|
161 self.trUtf8('Setup &Development Environment'), |
|
162 0, 0, |
|
163 self,'pyramid_setup_development') |
|
164 self.setupDevelopAct.setStatusTip(self.trUtf8( |
|
165 'Setup the Pyramid project in development mode')) |
|
166 self.setupDevelopAct.setWhatsThis(self.trUtf8( |
|
167 """<b>Setup Development Environment</b>""" |
|
168 """<p>Setup the Pyramid project in development mode using""" |
|
169 """ "python setup.py develop".</p>""" |
|
170 )) |
|
171 self.setupDevelopAct.triggered[()].connect(self.__setupDevelop) |
|
172 self.actions.append(self.setupDevelopAct) |
|
173 |
|
174 ################################## |
|
175 ## distribution actions below ## |
|
176 ################################## |
|
177 |
|
178 self.buildDistroAct = E5Action(self.trUtf8('Build Distribution'), |
|
179 self.trUtf8('Build &Distribution'), |
|
180 0, 0, |
|
181 self,'pyramid_build_distribution') |
|
182 self.buildDistroAct.setStatusTip(self.trUtf8( |
|
183 'Builds a distribution file for the Pyramid project')) |
|
184 self.buildDistroAct.setWhatsThis(self.trUtf8( |
|
185 """<b>Build Distribution</b>""" |
|
186 """<p>Builds a distribution file for the Pyramid project using""" |
|
187 """ "python setup.py sdist".</p>""" |
|
188 )) |
|
189 self.buildDistroAct.triggered[()].connect(self.__buildDistribution) |
|
190 self.actions.append(self.buildDistroAct) |
|
191 |
|
192 ################################## |
|
193 ## documentation action below ## |
|
194 ################################## |
|
195 |
|
196 self.documentationAct = E5Action(self.trUtf8('Documentation'), |
|
197 self.trUtf8('D&ocumentation'), |
|
198 0, 0, |
|
199 self,'pyramid_documentation') |
|
200 self.documentationAct.setStatusTip(self.trUtf8( |
|
201 'Shows the help viewer with the Pyramid documentation')) |
|
202 self.documentationAct.setWhatsThis(self.trUtf8( |
|
203 """<b>Documentation</b>""" |
|
204 """<p>Shows the help viewer with the Pyramid documentation.</p>""" |
|
205 )) |
|
206 self.documentationAct.triggered[()].connect(self.__showDocumentation) |
|
207 self.actions.append(self.documentationAct) |
|
208 |
|
209 ############################## |
|
210 ## about action below ## |
|
211 ############################## |
|
212 |
|
213 self.aboutPyramidAct = E5Action(self.trUtf8('About Pyramid'), |
|
214 self.trUtf8('About P&yramid'), |
|
215 0, 0, |
|
216 self,'pyramid_about') |
|
217 self.aboutPyramidAct.setStatusTip(self.trUtf8( |
|
218 'Shows some information about Pyramid')) |
|
219 self.aboutPyramidAct.setWhatsThis(self.trUtf8( |
|
220 """<b>About Pyramid</b>""" |
|
221 """<p>Shows some information about Pyramid.</p>""" |
|
222 )) |
|
223 self.aboutPyramidAct.triggered[()].connect(self.__pyramidInfo) |
|
224 self.actions.append(self.aboutPyramidAct) |
|
225 |
|
226 def initMenu(self): |
|
227 """ |
|
228 Public slot to initialize the Pyramid menu. |
|
229 |
|
230 @return the menu generated (QMenu) |
|
231 """ |
|
232 menu = QMenu(self.trUtf8('P&yramid'), self.__ui) |
|
233 menu.setTearOffEnabled(True) |
|
234 |
|
235 menu.addAction(self.selectProjectAct) |
|
236 menu.addSeparator() |
|
237 menu.addAction(self.runServerAct) |
|
238 menu.addAction(self.runLoggingServerAct) |
|
239 menu.addAction(self.runBrowserAct) |
|
240 menu.addSeparator() |
|
241 menu.addAction(self.createProjectAct) |
|
242 menu.addSeparator() |
|
243 menu.addAction(self.setupDevelopAct) |
|
244 menu.addSeparator() |
|
245 menu.addAction(self.runPythonShellAct) |
|
246 menu.addSeparator() |
|
247 menu.addAction(self.buildDistroAct) |
|
248 menu.addSeparator() |
|
249 menu.addAction(self.documentationAct) |
|
250 menu.addSeparator() |
|
251 menu.addAction(self.aboutPyramidAct) |
|
252 |
|
253 self.__mainMenu = menu |
|
254 return menu |
|
255 |
|
256 def projectOpenedHooks(self): |
|
257 """ |
|
258 Public method to add our hook methods. |
|
259 """ |
|
260 if self.__e5project.getProjectType() == "Pyramid": |
|
261 self.__formsBrowser = \ |
|
262 e5App().getObject("ProjectBrowser").getProjectBrowser("forms") |
|
263 self.__formsBrowser.addHookMethodAndMenuEntry("newForm", |
|
264 self.newForm, self.trUtf8("New template...")) |
|
265 |
|
266 ## self.__e5project.projectLanguageAddedByCode.connect( |
|
267 ## self.__projectLanguageAdded) |
|
268 ## self.__translationsBrowser = \ |
|
269 ## e5App().getObject("ProjectBrowser").getProjectBrowser("translations") |
|
270 ## self.__translationsBrowser.addHookMethodAndMenuEntry("extractMessages", |
|
271 ## self.extractMessages, self.trUtf8("Extract messages")) |
|
272 ## self.__translationsBrowser.addHookMethodAndMenuEntry("releaseAll", |
|
273 ## self.compileCatalogs, self.trUtf8("Compile all catalogs")) |
|
274 ## self.__translationsBrowser.addHookMethodAndMenuEntry("releaseSelected", |
|
275 ## self.compileSelectedCatalogs, |
|
276 ## self.trUtf8("Compile selected catalogs")) |
|
277 ## self.__translationsBrowser.addHookMethodAndMenuEntry("generateAll", |
|
278 ## self.updateCatalogs, self.trUtf8("Update all catalogs")) |
|
279 ## self.__translationsBrowser.addHookMethodAndMenuEntry("generateSelected", |
|
280 ## self.updateSelectedCatalogs, self.trUtf8("Update selected catalogs")) |
|
281 |
|
282 self.__hooksInstalled = True |
|
283 |
|
284 def projectClosedHooks(self): |
|
285 """ |
|
286 Public method to remove our hook methods. |
|
287 """ |
|
288 if self.__hooksInstalled: |
|
289 self.__formsBrowser.removeHookMethod("newForm") |
|
290 self.__formsBrowser = None |
|
291 |
|
292 ## self.__e5project.projectLanguageAddedByCode.disconnect( |
|
293 ## self.__projectLanguageAdded) |
|
294 ## self.__translationsBrowser.removeHookMethod("extractMessages") |
|
295 ## self.__translationsBrowser.removeHookMethod("releaseAll") |
|
296 ## self.__translationsBrowser.removeHookMethod("releaseSelected") |
|
297 ## self.__translationsBrowser.removeHookMethod("generateAll") |
|
298 ## self.__translationsBrowser.removeHookMethod("generateSelected") |
|
299 ## self.__translationsBrowser = None |
|
300 |
|
301 self.__hooksInstalled = False |
|
302 |
|
303 def newForm(self, path): |
|
304 """ |
|
305 Public method to create a new form. |
|
306 |
|
307 @param path full directory path for the new form file (string) |
|
308 """ |
|
309 dlg = FormSelectionDialog() |
|
310 if dlg.exec_() == QDialog.Accepted: |
|
311 template = dlg.getTemplateText() |
|
312 |
|
313 filter = self.trUtf8( |
|
314 "Chameleon Templates (*.pt);;" |
|
315 "Chameleon Text Templates (*.txt);;" |
|
316 "Mako Templates (*.mako);;" |
|
317 "Mako Templates (*.mak);;" |
|
318 "HTML Files (*.html);;" |
|
319 "HTML Files (*.htm);;" |
|
320 "All Files (*)") |
|
321 fname, selectedFilter = E5FileDialog.getSaveFileNameAndFilter( |
|
322 self.__ui, |
|
323 self.trUtf8("New Form"), |
|
324 path, |
|
325 filter, |
|
326 None, |
|
327 E5FileDialog.Options(E5FileDialog.DontConfirmOverwrite)) |
|
328 if fname: |
|
329 ext = QFileInfo(fname).suffix() |
|
330 if not ext: |
|
331 ex = selectedFilter.split("(*")[1].split(")")[0] |
|
332 if ex: |
|
333 fname += ex |
|
334 |
|
335 if os.path.exists(fname): |
|
336 res = E5MessageBox.yesNo(self.__ui, |
|
337 self.trUtf8("New Form"), |
|
338 self.trUtf8("""The file already exists! Overwrite it?"""), |
|
339 icon = E5MessageBox.Warning) |
|
340 if not res: |
|
341 # user selected to not overwrite |
|
342 return |
|
343 |
|
344 try: |
|
345 f = open(fname, "w", encoding="utf-8") |
|
346 f.write(template) |
|
347 f.close() |
|
348 except IOError as e: |
|
349 E5MessageBox.critical(self, |
|
350 self.trUtf8("New Form"), |
|
351 self.trUtf8("<p>The new form file <b>{0}</b> could not be" |
|
352 " created.<br/>" |
|
353 "Problem: {1}</p>").format(fname, e)) |
|
354 return |
|
355 |
|
356 self.__e5project.appendFile(fname) |
|
357 self.__formsBrowser.sourceFile.emit(fname) |
|
358 |
|
359 ################################################################## |
|
360 ## methods below implement general functionality |
|
361 ################################################################## |
|
362 |
|
363 def projectClosed(self): |
|
364 """ |
|
365 Public method to handle the closing of a project. |
|
366 """ |
|
367 if self.__serverProc is not None: |
|
368 self.__serverProcFinished() |
|
369 self.__setCurrentProject(None) |
|
370 |
|
371 def __getVirtualEnvironment(self): |
|
372 """ |
|
373 Private method to get the path of the virtual environment. |
|
374 |
|
375 @return path of the virtual environment (string) |
|
376 """ |
|
377 language = self.__e5project.getProjectLanguage() |
|
378 if language == "Python3": |
|
379 virtEnv = self.__plugin.getPreferences("VirtualEnvironmentPy3") |
|
380 elif language == "Python2": |
|
381 virtEnv = self.__plugin.getPreferences("VirtualEnvironmentPy2") |
|
382 else: |
|
383 virtEnv = "" |
|
384 if virtEnv and not os.path.exists(virtEnv): |
|
385 virtEnv = "" |
|
386 return virtEnv |
|
387 |
|
388 def getPyramidCommand(self, cmd): |
|
389 """ |
|
390 Public method to build a Pyramid command. |
|
391 |
|
392 @param cmd command (string) |
|
393 @return full pyramid command (string) |
|
394 """ |
|
395 virtualEnv = self.__getVirtualEnvironment() |
|
396 if virtualEnv: |
|
397 if isWindowsPlatform(): |
|
398 cmd = os.path.join(virtualEnv, "Scripts", cmd) |
|
399 else: |
|
400 cmd = os.path.join(virtualEnv, "bin", cmd) |
|
401 return cmd |
|
402 |
|
403 def getPythonCommand(self): |
|
404 """ |
|
405 Public method to build the Python command. |
|
406 |
|
407 @return python command (string) |
|
408 """ |
|
409 python = "python" |
|
410 if isWindowsPlatform(): |
|
411 python += ".exe" |
|
412 virtualEnv = self.__getVirtualEnvironment() |
|
413 if virtualEnv: |
|
414 if isWindowsPlatform(): |
|
415 python = os.path.join(virtualEnv, "Scripts", python) |
|
416 else: |
|
417 python = os.path.join(virtualEnv, "bin", python) |
|
418 return python |
|
419 |
|
420 def __pyramidInfo(self): |
|
421 """ |
|
422 Private slot to show some info about Pyramid. |
|
423 """ |
|
424 url = "http://www.pylonsproject.org/projects/pyramid/about" |
|
425 msgBox = E5MessageBox.E5MessageBox(E5MessageBox.Question, |
|
426 self.trUtf8("About Pyramid"), |
|
427 self.trUtf8( |
|
428 "<p>Pyramid is a high-level Python Web framework that encourages rapid " |
|
429 "development and clean, pragmatic design.</p>" |
|
430 "<p>URL: <a href=\"{0}\">{0}</a></p>" |
|
431 ).format(url), |
|
432 modal=True, |
|
433 buttons=E5MessageBox.Ok) |
|
434 msgBox.setIconPixmap(UI.PixmapCache.getPixmap( |
|
435 os.path.join("ProjectPyramid", "icons", "pyramid64.png"))) |
|
436 msgBox.exec_() |
|
437 |
|
438 def isSpawningConsole(self, consoleCmd): |
|
439 """ |
|
440 Public method to check, if the given console is a spawning console. |
|
441 |
|
442 @param consoleCmd console command (string) |
|
443 @return tuple of two entries giving an indication, if the console |
|
444 is spawning (boolean) and the (possibly) cleaned console command |
|
445 (string) |
|
446 """ |
|
447 if consoleCmd and consoleCmd[0] == '@': |
|
448 return (True, consoleCmd[1:]) |
|
449 else: |
|
450 return (False, consoleCmd) |
|
451 |
|
452 ################################################################## |
|
453 ## slots below implement creation functions |
|
454 ################################################################## |
|
455 |
|
456 def __createProject(self): |
|
457 """ |
|
458 Private slot to create a new Pyramid project. |
|
459 """ |
|
460 dlg = CreateParametersDialog(self) |
|
461 if dlg.exec_() == QDialog.Accepted: |
|
462 scaffold, project, overwrite, simulate = dlg.getData() |
|
463 |
|
464 cmd = self.getPyramidCommand("pcreate") |
|
465 args = [] |
|
466 if overwrite: |
|
467 args.append("--overwrite") |
|
468 else: |
|
469 args.append("--interactive") |
|
470 if simulate: |
|
471 args.append("--simulate") |
|
472 args.append("--scaffold={0}".format(scaffold)) |
|
473 args.append(project) |
|
474 dlg = PyramidDialog(self.trUtf8("Create Pyramid Project"), |
|
475 linewrap=False, parent=self.__ui) |
|
476 if dlg.startProcess(cmd, args, self.__e5project.getProjectPath()): |
|
477 dlg.exec_() |
|
478 if dlg.normalExit() and not simulate: |
|
479 # search for files created by pcreate and add them to the project |
|
480 projectPath = os.path.join(self.__e5project.getProjectPath(), project) |
|
481 for entry in os.walk(projectPath): |
|
482 for fileName in entry[2]: |
|
483 fullName = os.path.join(entry[0], fileName) |
|
484 self.__e5project.appendFile(fullName) |
|
485 |
|
486 # create the base directory for translations |
|
487 i18nPath = os.path.join(projectPath, project.lower(), "i18n") |
|
488 if not os.path.exists(i18nPath): |
|
489 os.makedirs(i18nPath) |
|
490 self.__e5project.setDirty(True) |
|
491 |
|
492 self.__setCurrentProject(project) |
|
493 |
|
494 ################################################################## |
|
495 ## methods below implement site related functions |
|
496 ################################################################## |
|
497 |
|
498 def __findProjects(self): |
|
499 """ |
|
500 Private method to determine the relative path of all Pyramid |
|
501 projects (= top level dirs). |
|
502 |
|
503 @return list of projects (list of string) |
|
504 """ |
|
505 projects = [] |
|
506 ppath = self.__e5project.getProjectPath() |
|
507 for entry in os.listdir(ppath): |
|
508 if entry[0] not in "._" and \ |
|
509 os.path.isdir(os.path.join(ppath, entry)): |
|
510 projects.append(entry) |
|
511 return projects |
|
512 |
|
513 def __selectProject(self): |
|
514 """ |
|
515 Private method to select a Pyramid project to work with. |
|
516 |
|
517 @return selected project (string) |
|
518 """ |
|
519 projects = self.__findProjects() |
|
520 if len(projects) == 0: |
|
521 project = None |
|
522 elif len(projects) == 1: |
|
523 project = projects[0] |
|
524 else: |
|
525 if self.__currentProject is not None: |
|
526 try: |
|
527 cur = projects.index(self.__currentProject) |
|
528 except ValueError: |
|
529 cur = 0 |
|
530 else: |
|
531 cur = 0 |
|
532 project, ok = QInputDialog.getItem( |
|
533 self.__ui, |
|
534 self.trUtf8("Select Pyramid Project"), |
|
535 self.trUtf8("Select the Pyramid project to work with."), |
|
536 projects, |
|
537 cur, False) |
|
538 if not ok: |
|
539 projects = None |
|
540 self.__setCurrentProject(project) |
|
541 |
|
542 def __projectPath(self): |
|
543 """ |
|
544 Private method to calculate the full path of the Pyramid project. |
|
545 |
|
546 @exception PyramidNoProjectSelectedException raised, if no project is selected |
|
547 @return path of the project (string) |
|
548 """ |
|
549 if self.__currentProject is None: |
|
550 self.__selectProject() |
|
551 |
|
552 if self.__currentProject is None: |
|
553 raise PyramidNoProjectSelectedException |
|
554 else: |
|
555 return os.path.join(self.__e5project.getProjectPath(), |
|
556 self.__currentProject) |
|
557 |
|
558 def __setCurrentProject(self, project): |
|
559 """ |
|
560 Private slot to set the current project. |
|
561 |
|
562 @param project name of the project (string) |
|
563 """ |
|
564 if project is not None and len(project) == 0: |
|
565 self.__currentProject = None |
|
566 else: |
|
567 self.__currentProject = project |
|
568 |
|
569 if self.__currentProject is None: |
|
570 curProject = self.trUtf8("None") |
|
571 else: |
|
572 curProject = self.__currentProject |
|
573 self.selectProjectAct.setText( |
|
574 self.trUtf8('&Current Pyramid Project ({0})').format(curProject)) |
|
575 |
|
576 if self.__currentProject is None: |
|
577 self.__e5project.pdata["TRANSLATIONPATTERN"] = [] |
|
578 else: |
|
579 # TODO: adjust this to the Pyramid docu |
|
580 self.__e5project.pdata["TRANSLATIONPATTERN"] = [ |
|
581 os.path.join(project, project.lower(), "i18n", "%language%", |
|
582 "LC_MESSAGES", "%s.po" % project.lower()) |
|
583 ] |
|
584 |
|
585 def __project(self): |
|
586 """ |
|
587 Private method to get the name of the current Pyramid project. |
|
588 |
|
589 @exception PyramidNoProjectSelectedException raised, if no project is selected |
|
590 @return name of the project (string) |
|
591 """ |
|
592 if self.__currentProject is None: |
|
593 self.__selectProject() |
|
594 |
|
595 if self.__currentProject is None: |
|
596 raise PyramidNoProjectSelectedException |
|
597 else: |
|
598 return self.__currentProject |
|
599 |
|
600 ################################################################## |
|
601 ## slots below implement run functions |
|
602 ################################################################## |
|
603 |
|
604 def __runServer(self, logging = False): |
|
605 """ |
|
606 Private slot to start the Pyramid Web server. |
|
607 |
|
608 @param logging flag indicating to enable logging (boolean) |
|
609 """ |
|
610 consoleCmd = self.isSpawningConsole( |
|
611 self.__plugin.getPreferences("ConsoleCommand"))[1] |
|
612 if consoleCmd: |
|
613 try: |
|
614 projectPath = self.__projectPath() |
|
615 except PyramidNoProjectSelectedException: |
|
616 E5MessageBox.warning(self.__ui, |
|
617 self.trUtf8('Run Server'), |
|
618 self.trUtf8('No current Pyramid project selected or no Pyramid ' |
|
619 'project created yet. Aborting...')) |
|
620 return |
|
621 |
|
622 args = Utilities.parseOptionString(consoleCmd) |
|
623 args[0] = Utilities.getExecutablePath(args[0]) |
|
624 args.append(self.getPyramidCommand("pserve")) |
|
625 if logging: |
|
626 args.append("--log-file=server.log") |
|
627 args.append("--reload") |
|
628 args.append(os.path.join(projectPath, "development.ini")) |
|
629 |
|
630 if isWindowsPlatform(): |
|
631 serverProcStarted, pid = \ |
|
632 QProcess.startDetached(args[0], args[1:], projectPath) |
|
633 else: |
|
634 if self.__serverProc is not None: |
|
635 self.__serverProcFinished() |
|
636 |
|
637 self.__serverProc = QProcess() |
|
638 self.__serverProc.finished.connect(self.__serverProcFinished) |
|
639 self.__serverProc.setWorkingDirectory(projectPath) |
|
640 self.__serverProc.start(args[0], args[1:]) |
|
641 serverProcStarted = self.__serverProc.waitForStarted() |
|
642 if not serverProcStarted: |
|
643 E5MessageBox.critical(self.__ui, |
|
644 self.trUtf8('Process Generation Error'), |
|
645 self.trUtf8('The Pyramid server could not be started.')) |
|
646 |
|
647 def __runLoggingServer(self): |
|
648 """ |
|
649 Private slot to start the Pyramid Web server with logging. |
|
650 """ |
|
651 self.__runServer(True) |
|
652 |
|
653 def __serverProcFinished(self): |
|
654 """ |
|
655 Private slot connected to the finished signal. |
|
656 """ |
|
657 if self.__serverProc is not None and \ |
|
658 self.__serverProc.state() != QProcess.NotRunning: |
|
659 self.__serverProc.terminate() |
|
660 QTimer.singleShot(2000, self.__serverProc.kill) |
|
661 self.__serverProc.waitForFinished(3000) |
|
662 self.__serverProc = None |
|
663 |
|
664 def __runBrowser(self): |
|
665 """ |
|
666 Private slot to start the default web browser with the server URL. |
|
667 """ |
|
668 try: |
|
669 projectPath = self.__projectPath() |
|
670 except PyramidNoProjectSelectedException: |
|
671 E5MessageBox.warning(self.__ui, |
|
672 self.trUtf8('Run Web-Browser'), |
|
673 self.trUtf8('No current Pyramid project selected or no Pyramid project' |
|
674 ' created yet. Aborting...')) |
|
675 return |
|
676 |
|
677 config = configparser.ConfigParser() |
|
678 config.read(os.path.join(projectPath, "development.ini")) |
|
679 port = config.get("server:main", "port", fallback="6543") |
|
680 url = QUrl("http://localhost:{0}".format(port)) |
|
681 res = QDesktopServices.openUrl(url) |
|
682 if not res: |
|
683 E5MessageBox.critical(self.__ui, |
|
684 self.trUtf8('Run Web-Browser'), |
|
685 self.trUtf8('Could not start the web-browser for the URL "{0}".')\ |
|
686 .format(url.toString())) |
|
687 |
|
688 def __runPythonShell(self): |
|
689 """ |
|
690 Private slot to start a Python console for a Pyramid project. |
|
691 """ |
|
692 consoleCmd = self.isSpawningConsole( |
|
693 self.__plugin.getPreferences("ConsoleCommand"))[1] |
|
694 if consoleCmd: |
|
695 try: |
|
696 projectPath = self.__projectPath() |
|
697 except PyramidNoProjectSelectedException: |
|
698 E5MessageBox.warning(self.__ui, |
|
699 self.trUtf8('Start Pyramid Python Console'), |
|
700 self.trUtf8('No current Pyramid project selected or no Pyramid ' |
|
701 'project created yet. Aborting...')) |
|
702 return |
|
703 |
|
704 args = Utilities.parseOptionString(consoleCmd) |
|
705 args[0] = Utilities.getExecutablePath(args[0]) |
|
706 args.append(self.getPyramidCommand("pshell")) |
|
707 language = self.__e5project.getProjectLanguage() |
|
708 if language == "Python2": |
|
709 consoleType = self.__plugin.getPreferences("Python2ConsoleType") |
|
710 else: |
|
711 consoleType = self.__plugin.getPreferences("Python3ConsoleType") |
|
712 args.append("--python-shell={0}".format(consoleType)) |
|
713 args.append(os.path.join(projectPath, "development.ini")) |
|
714 |
|
715 started, pid = QProcess.startDetached(args[0], args[1:], projectPath) |
|
716 if not started: |
|
717 E5MessageBox.critical(self.__ui, |
|
718 self.trUtf8('Process Generation Error'), |
|
719 self.trUtf8('The Pyramid Shell process could not be started.')) |
|
720 |
|
721 ################################################################## |
|
722 ## slots below implement setup functions |
|
723 ################################################################## |
|
724 |
|
725 def __setupDevelop(self): |
|
726 """ |
|
727 Private slot to set up the development environment for the current project. |
|
728 """ |
|
729 title = self.trUtf8("Setup Development Environment") |
|
730 |
|
731 cmd = self.getPythonCommand() |
|
732 args = [] |
|
733 args.append("setup.py") |
|
734 args.append("develop") |
|
735 |
|
736 try: |
|
737 wd = self.__projectPath() |
|
738 except PyramidNoProjectSelectedException: |
|
739 E5MessageBox.warning(self.__ui, |
|
740 title, |
|
741 self.trUtf8('No current Pyramid project selected or no Pyramid project' |
|
742 ' created yet. Aborting...')) |
|
743 return |
|
744 |
|
745 dia = PyramidDialog(title, |
|
746 msgSuccess = \ |
|
747 self.trUtf8("Pyramid development environment setup successfully.")) |
|
748 res = dia.startProcess(cmd, args, wd) |
|
749 if res: |
|
750 dia.exec_() |
|
751 |
|
752 ################################################################## |
|
753 ## slots below implement distribution functions |
|
754 ################################################################## |
|
755 |
|
756 def __buildDistribution(self): |
|
757 """ |
|
758 Private slot to build a distribution file for the current Pyramid project. |
|
759 """ |
|
760 title = self.trUtf8("Build Distribution File") |
|
761 try: |
|
762 projectPath = self.__projectPath() |
|
763 except PyramidNoProjectSelectedException: |
|
764 E5MessageBox.warning(self.__ui, |
|
765 title, |
|
766 self.trUtf8('No current Pyramid project selected or no Pyramid project' |
|
767 ' created yet. Aborting...')) |
|
768 return |
|
769 |
|
770 dlg = DistributionTypeSelectionDialog(self, projectPath, self.__ui) |
|
771 if dlg.exec_() == QDialog.Accepted: |
|
772 formats = dlg.getFormats() |
|
773 cmd = self.getPythonCommand() |
|
774 args = [] |
|
775 args.append("setup.py") |
|
776 args.append("sdist") |
|
777 if formats: |
|
778 args.append("--formats={0}".format(','.join(formats))) |
|
779 |
|
780 dia = PyramidDialog(title, |
|
781 msgSuccess = \ |
|
782 self.trUtf8("Python distribution file built successfully.")) |
|
783 res = dia.startProcess(cmd, args, projectPath) |
|
784 if res: |
|
785 dia.exec_() |
|
786 |
|
787 ################################################################## |
|
788 ## slots below implement documentation functions |
|
789 ################################################################## |
|
790 |
|
791 def __showDocumentation(self): |
|
792 """ |
|
793 Private slot to show the helpviewer with the Pylons documentation. |
|
794 """ |
|
795 page = self.__plugin.getPreferences("PyramidDocUrl") |
|
796 self.__ui.launchHelpViewer(page) |