|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2013 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 """ |
|
7 Module implementing the Django project plugin. |
|
8 """ |
|
9 |
|
10 import os |
|
11 import glob |
|
12 import fnmatch |
|
13 |
|
14 from PyQt4.QtCore import QCoreApplication, QObject, QTranslator |
|
15 |
|
16 from E5Gui.E5Application import e5App |
|
17 |
|
18 import Preferences |
|
19 |
|
20 from Globals import isWindowsPlatform, isMacPlatform |
|
21 |
|
22 from ProjectDjango.Project import Project |
|
23 |
|
24 # Start-of-Header |
|
25 name = "Django Project Plugin" |
|
26 author = "Detlev Offenbach <detlev@die-offenbachs.de>" |
|
27 autoactivate = True |
|
28 deactivateable = True |
|
29 version = "3.0.0" |
|
30 className = "ProjectDjangoPlugin" |
|
31 packageName = "ProjectDjango" |
|
32 shortDescription = "Project support for Django projects." |
|
33 longDescription = """This plugin implements project support for Django projects.""" |
|
34 needsRestart = False |
|
35 pyqtApi = 2 |
|
36 # End-of-Header |
|
37 |
|
38 error = "" |
|
39 |
|
40 djangoPluginObject = None |
|
41 |
|
42 |
|
43 def apiFiles(language): |
|
44 """ |
|
45 Module function to return the API files made available by this plugin. |
|
46 |
|
47 @return list of API filenames (list of string) |
|
48 """ |
|
49 if language in ["Python3", "Python2"]: |
|
50 apisDir = \ |
|
51 os.path.join(os.path.dirname(__file__), "ProjectDjango", "APIs") |
|
52 apis = glob.glob(os.path.join(apisDir, '*.api')) |
|
53 else: |
|
54 apis = [] |
|
55 return apis |
|
56 |
|
57 |
|
58 def createDjangoPage(configDlg): |
|
59 """ |
|
60 Module function to create the Django configuration page. |
|
61 |
|
62 @return reference to the configuration page |
|
63 """ |
|
64 global djangoPluginObject |
|
65 from ProjectDjango.ConfigurationPage.DjangoPage import DjangoPage |
|
66 page = DjangoPage(djangoPluginObject) |
|
67 return page |
|
68 |
|
69 |
|
70 def getConfigData(): |
|
71 """ |
|
72 Module function returning data as required by the configuration dialog. |
|
73 |
|
74 @return dictionary containing the relevant data |
|
75 """ |
|
76 if e5App().getObject("UserInterface").versionIsNewer('5.0.99', '20120101'): |
|
77 return { |
|
78 "djangoPage": \ |
|
79 [QCoreApplication.translate("ProjectDjangoPlugin", "Django"), |
|
80 os.path.join("ProjectDjango", "icons", |
|
81 "django.png"), |
|
82 createDjangoPage, None, None], |
|
83 } |
|
84 else: |
|
85 return {} |
|
86 |
|
87 |
|
88 def prepareUninstall(): |
|
89 """ |
|
90 Module function to prepare for an uninstallation. |
|
91 """ |
|
92 Preferences.removeProjectBrowserFlags(ProjectDjangoPlugin.PreferencesKey) |
|
93 Preferences.Prefs.settings.remove(ProjectDjangoPlugin.PreferencesKey) |
|
94 Preferences.Prefs.rsettings.remove(ProjectDjangoPlugin.PreferencesKey) |
|
95 |
|
96 |
|
97 class ProjectDjangoPlugin(QObject): |
|
98 """ |
|
99 Class implementing the Pyramid project plugin. |
|
100 """ |
|
101 PreferencesKey = "Django" |
|
102 |
|
103 lexerAssociations = { |
|
104 "*.html" : "Pygments|HTML+Django/Jinja", |
|
105 "*.htm" : "Pygments|HTML+Django/Jinja", |
|
106 } |
|
107 |
|
108 def __init__(self, ui): |
|
109 """ |
|
110 Constructor |
|
111 |
|
112 @param ui reference to the user interface object (UI.UserInterface) |
|
113 """ |
|
114 QObject.__init__(self, ui) |
|
115 self.__ui = ui |
|
116 self.__initialize() |
|
117 |
|
118 self.__defaults = { |
|
119 "ServerAddress" : "", |
|
120 |
|
121 "RecentNumberApps" : 10, |
|
122 "UsePlainPython" : False, |
|
123 } |
|
124 if isWindowsPlatform(): |
|
125 self.__defaults["ConsoleCommandNoClose"] = "cmd.exe /k" |
|
126 self.__defaults["ConsoleCommand"] = "cmd.exe /c" |
|
127 elif isMacPlatform(): |
|
128 self.__defaults["ConsoleCommandNoClose"] = "xterm -hold -e" |
|
129 self.__defaults["ConsoleCommand"] = "xterm -e" |
|
130 else: |
|
131 self.__defaults["ConsoleCommandNoClose"] = "konsole --noclose -e" |
|
132 self.__defaults["ConsoleCommand"] = "konsole -e" |
|
133 |
|
134 self.__translator = None |
|
135 self.__loadTranslator() |
|
136 |
|
137 def __initialize(self): |
|
138 """ |
|
139 Private slot to (re)initialize the plugin. |
|
140 """ |
|
141 self.__object = None |
|
142 |
|
143 self.__mainAct = None |
|
144 self.__mainMenu = None |
|
145 |
|
146 self.__e5project = e5App().getObject("Project") |
|
147 |
|
148 def __checkVersions(self): |
|
149 """ |
|
150 Private function to check that the eric5 version is ok. |
|
151 |
|
152 @return flag indicating version is ok (boolean) |
|
153 """ |
|
154 global error |
|
155 |
|
156 if self.__ui.versionIsNewer('5.0.99', '20120101'): |
|
157 error = "" |
|
158 else: |
|
159 error = self.trUtf8("eric5 version is too old, {0}, {1} or newer needed.")\ |
|
160 .format("5.1.0", "20120101") |
|
161 return False |
|
162 |
|
163 return True |
|
164 |
|
165 def activate(self): |
|
166 """ |
|
167 Public method to activate this plugin. |
|
168 |
|
169 @return tuple of None and activation status (boolean) |
|
170 """ |
|
171 if not self.__checkVersions(): |
|
172 return None, False |
|
173 |
|
174 global djangoPluginObject |
|
175 djangoPluginObject = self |
|
176 |
|
177 self.__object = Project(self, self.__ui) |
|
178 self.__object.initActions() |
|
179 e5App().registerPluginObject("ProjectDjango", self.__object) |
|
180 |
|
181 self.__mainMenu = self.__object.initMenu() |
|
182 |
|
183 try: |
|
184 self.__e5project.registerProjectType("Django", self.trUtf8("Django"), |
|
185 self.fileTypesCallback, |
|
186 lexerAssociationCallback=self.lexerAssociationCallback, |
|
187 binaryTranslationsCallback=self.binaryTranslationsCallback, |
|
188 progLanguages=["Python2", "Python3"]) |
|
189 except TypeError: |
|
190 # for backward compatibility |
|
191 self.__e5project.registerProjectType("Django", self.trUtf8("Django"), |
|
192 self.fileTypesCallback, |
|
193 lexerAssociationCallback=self.lexerAssociationCallback, |
|
194 binaryTranslationsCallback=self.binaryTranslationsCallback) |
|
195 |
|
196 from Project.ProjectBrowser import SourcesBrowserFlag, FormsBrowserFlag, \ |
|
197 TranslationsBrowserFlag, OthersBrowserFlag |
|
198 Preferences.setProjectBrowserFlagsDefault("Pyramid", |
|
199 SourcesBrowserFlag | \ |
|
200 FormsBrowserFlag | \ |
|
201 TranslationsBrowserFlag | \ |
|
202 OthersBrowserFlag, |
|
203 ) |
|
204 |
|
205 if self.__e5project.isOpen(): |
|
206 self.__projectOpened() |
|
207 self.__object.projectOpenedHooks() |
|
208 |
|
209 e5App().getObject("Project").projectOpened.connect(self.__projectOpened) |
|
210 e5App().getObject("Project").projectClosed.connect(self.__projectClosed) |
|
211 e5App().getObject("Project").newProject.connect(self.__projectOpened) |
|
212 |
|
213 e5App().getObject("Project").projectOpenedHooks.connect( |
|
214 self.__object.projectOpenedHooks) |
|
215 e5App().getObject("Project").projectClosedHooks.connect( |
|
216 self.__object.projectClosedHooks) |
|
217 e5App().getObject("Project").newProjectHooks.connect( |
|
218 self.__object.projectOpenedHooks) |
|
219 |
|
220 return None, True |
|
221 |
|
222 def deactivate(self): |
|
223 """ |
|
224 Public method to deactivate this plugin. |
|
225 """ |
|
226 e5App().unregisterPluginObject("ProjectDjango") |
|
227 |
|
228 e5App().getObject("Project").projectOpened.disconnect(self.__projectOpened) |
|
229 e5App().getObject("Project").projectClosed.disconnect(self.__projectClosed) |
|
230 e5App().getObject("Project").newProject.disconnect(self.__projectOpened) |
|
231 |
|
232 e5App().getObject("Project").projectOpenedHooks.disconnect( |
|
233 self.__object.projectOpenedHooks) |
|
234 e5App().getObject("Project").projectClosedHooks.disconnect( |
|
235 self.__object.projectClosedHooks) |
|
236 e5App().getObject("Project").newProjectHooks.disconnect( |
|
237 self.__object.projectOpenedHooks) |
|
238 |
|
239 self.__e5project.unregisterProjectType("Django") |
|
240 |
|
241 self.__object.projectClosedHooks() |
|
242 self.__projectClosed() |
|
243 |
|
244 self.__initialize() |
|
245 |
|
246 def __loadTranslator(self): |
|
247 """ |
|
248 Private method to load the translation file. |
|
249 """ |
|
250 if self.__ui is not None: |
|
251 loc = self.__ui.getLocale() |
|
252 if loc and loc != "C": |
|
253 locale_dir = \ |
|
254 os.path.join(os.path.dirname(__file__), "ProjectDjango", "i18n") |
|
255 translation = "django_%s" % loc |
|
256 translator = QTranslator(None) |
|
257 loaded = translator.load(translation, locale_dir) |
|
258 if loaded: |
|
259 self.__translator = translator |
|
260 e5App().installTranslator(self.__translator) |
|
261 else: |
|
262 print("Warning: translation file '{0}' could not be loaded.".format( |
|
263 translation)) |
|
264 print("Using default.") |
|
265 |
|
266 def __projectOpened(self): |
|
267 """ |
|
268 Private slot to handle the projectOpened signal. |
|
269 """ |
|
270 if self.__e5project.getProjectType() == "Django": |
|
271 projectAct = self.__ui.getMenuBarAction("project") |
|
272 actions = self.__ui.menuBar().actions() |
|
273 insertAct = actions[actions.index(projectAct) + 1] |
|
274 self.__mainAct = self.__ui.menuBar().insertMenu(insertAct, self.__mainMenu) |
|
275 |
|
276 def __projectClosed(self): |
|
277 """ |
|
278 Private slot to handle the projectClosed signal. |
|
279 """ |
|
280 if self.__mainAct is not None: |
|
281 self.__ui.menuBar().removeAction(self.__mainAct) |
|
282 self.__mainAct = None |
|
283 self.__object.projectClosed() |
|
284 |
|
285 def fileTypesCallback(self): |
|
286 """ |
|
287 Public method get the filetype associations of the Django project type. |
|
288 |
|
289 @return dictionary with file type associations |
|
290 """ |
|
291 if self.__e5project.getProjectType() == "Django": |
|
292 fileTypes = { |
|
293 "*.html" : "FORMS", |
|
294 "*.htm" : "FORMS", |
|
295 "*.js": "SOURCES", |
|
296 "*.pot": "TRANSLATIONS", |
|
297 "*.po": "TRANSLATIONS", |
|
298 "*.mo": "TRANSLATIONS", |
|
299 } |
|
300 else: |
|
301 fileTypes = {} |
|
302 return fileTypes |
|
303 |
|
304 def lexerAssociationCallback(self, filename): |
|
305 """ |
|
306 Public method to get the lexer association of the Django project type for |
|
307 a file. |
|
308 |
|
309 @param filename name of the file (string) |
|
310 @return name of the lexer (string) (Pygments lexers are prefixed with 'Pygments|') |
|
311 """ |
|
312 for pattern, language in self.lexerAssociations.items(): |
|
313 if fnmatch.fnmatch(filename, pattern): |
|
314 return language |
|
315 |
|
316 return "" |
|
317 |
|
318 def binaryTranslationsCallback(self, filename): |
|
319 """ |
|
320 Public method to determine the filename of a compiled translation file |
|
321 given the translation source file. |
|
322 |
|
323 @param filename name of the translation source file (string) |
|
324 @return name of the binary translation file (string) |
|
325 """ |
|
326 if filename.endswith(".po"): |
|
327 filename = filename.replace(".po", ".mo") |
|
328 return filename |
|
329 |
|
330 def getPreferences(self, key): |
|
331 """ |
|
332 Public method to retrieve the various settings. |
|
333 |
|
334 @param key the key of the value to get |
|
335 @param prefClass preferences class used as the storage area |
|
336 @return the requested setting |
|
337 """ |
|
338 if key in ["RecentNumberApps"]: |
|
339 return int(Preferences.Prefs.settings.value(self.PreferencesKey + "/" + key, |
|
340 self.__defaults[key])) |
|
341 elif key in ["UsePlainPython"]: |
|
342 return Preferences.toBool(Preferences.Prefs.settings.value( |
|
343 self.PreferencesKey + "/" + key, self.__defaults[key])) |
|
344 else: |
|
345 return Preferences.Prefs.settings.value(self.PreferencesKey + "/" + key, |
|
346 self.__defaults[key]) |
|
347 |
|
348 def setPreferences(self, key, value): |
|
349 """ |
|
350 Public method to store the various settings. |
|
351 |
|
352 @param key the key of the setting to be set (string) |
|
353 @param value the value to be set |
|
354 @param prefClass preferences class used as the storage area |
|
355 """ |
|
356 Preferences.Prefs.settings.setValue(self.PreferencesKey + "/" + key, value) |