41 needsRestart = False |
42 needsRestart = False |
42 pyqtApi = 2 |
43 pyqtApi = 2 |
43 # End-Of-Header |
44 # End-Of-Header |
44 |
45 |
45 error = "" |
46 error = "" |
46 |
47 |
47 |
48 |
48 class ProjectWebPlugin(QObject): |
49 class ProjectWebPlugin(QObject): |
49 """ |
50 """ |
50 Class implementing the Web project plugin. |
51 Class implementing the Web project plugin. |
51 """ |
52 """ |
|
53 |
52 def __init__(self, ui): |
54 def __init__(self, ui): |
53 """ |
55 """ |
54 Constructor |
56 Constructor |
55 |
57 |
56 @param ui reference to the user interface object |
58 @param ui reference to the user interface object |
57 @type UserInterface |
59 @type UserInterface |
58 """ |
60 """ |
59 super().__init__(ui) |
61 super().__init__(ui) |
60 self.__ui = ui |
62 self.__ui = ui |
61 self.__initialize() |
63 self.__initialize() |
62 |
64 |
63 self.__translator = None |
65 self.__translator = None |
64 self.__loadTranslator() |
66 self.__loadTranslator() |
65 |
67 |
66 self.__initMenu() |
68 self.__initMenu() |
67 |
69 |
68 def __initialize(self): |
70 def __initialize(self): |
69 """ |
71 """ |
70 Private slot to (re)initialize the plugin. |
72 Private slot to (re)initialize the plugin. |
71 """ |
73 """ |
72 self.__ericProject = ericApp().getObject("Project") |
74 self.__ericProject = ericApp().getObject("Project") |
73 |
75 |
74 self.__editors = {} |
76 self.__editors = {} |
75 self.__mainActions = [] |
77 self.__mainActions = [] |
76 |
78 |
77 def activate(self): |
79 def activate(self): |
78 """ |
80 """ |
79 Public method to activate this plugin. |
81 Public method to activate this plugin. |
80 |
82 |
81 @return tuple of None and activation status |
83 @return tuple of None and activation status |
82 @rtype tuple of (None, bool) |
84 @rtype tuple of (None, bool) |
83 """ |
85 """ |
84 global error |
86 global error |
85 error = "" # clear previous error |
87 error = "" # clear previous error |
86 |
88 |
87 # it is not registered for a specific programming language |
89 # it is not registered for a specific programming language |
88 self.__ericProject.registerProjectType( |
90 self.__ericProject.registerProjectType( |
89 "Web", self.tr("Web"), |
91 "Web", self.tr("Web"), self.fileTypesCallback |
90 self.fileTypesCallback) |
92 ) |
91 |
93 |
92 from Project.ProjectBrowser import ( |
94 from Project.ProjectBrowser import ( |
93 SourcesBrowserFlag, FormsBrowserFlag, OthersBrowserFlag |
95 SourcesBrowserFlag, |
94 ) |
96 FormsBrowserFlag, |
|
97 OthersBrowserFlag, |
|
98 ) |
|
99 |
95 Preferences.setProjectBrowserFlagsDefault( |
100 Preferences.setProjectBrowserFlagsDefault( |
96 "Web", |
101 "Web", |
97 SourcesBrowserFlag | FormsBrowserFlag | OthersBrowserFlag, |
102 SourcesBrowserFlag | FormsBrowserFlag | OthersBrowserFlag, |
98 ) |
103 ) |
99 |
104 |
100 self.__ui.showMenu.connect(self.__populateMenu) |
105 self.__ui.showMenu.connect(self.__populateMenu) |
101 |
106 |
102 menu = self.__ui.getMenu("plugin_tools") |
107 menu = self.__ui.getMenu("plugin_tools") |
103 if menu is not None: |
108 if menu is not None: |
104 if not menu.isEmpty(): |
109 if not menu.isEmpty(): |
105 act = menu.addSeparator() |
110 act = menu.addSeparator() |
106 self.__mainActions.append(act) |
111 self.__mainActions.append(act) |
107 act = menu.addMenu(self.__menu) |
112 act = menu.addMenu(self.__menu) |
108 self.__mainActions.append(act) |
113 self.__mainActions.append(act) |
109 |
114 |
110 ericApp().getObject("ViewManager").editorOpenedEd.connect( |
115 ericApp().getObject("ViewManager").editorOpenedEd.connect(self.__editorOpened) |
111 self.__editorOpened) |
116 ericApp().getObject("ViewManager").editorClosedEd.connect(self.__editorClosed) |
112 ericApp().getObject("ViewManager").editorClosedEd.connect( |
117 |
113 self.__editorClosed) |
|
114 |
|
115 for editor in ericApp().getObject("ViewManager").getOpenEditors(): |
118 for editor in ericApp().getObject("ViewManager").getOpenEditors(): |
116 self.__editorOpened(editor) |
119 self.__editorOpened(editor) |
117 |
120 |
118 return None, True |
121 return None, True |
119 |
122 |
120 def deactivate(self): |
123 def deactivate(self): |
121 """ |
124 """ |
122 Public method to deactivate this plugin. |
125 Public method to deactivate this plugin. |
123 """ |
126 """ |
124 self.__ericProject.unregisterProjectType("Web") |
127 self.__ericProject.unregisterProjectType("Web") |
125 |
128 |
126 self.__ui.showMenu.disconnect(self.__populateMenu) |
129 self.__ui.showMenu.disconnect(self.__populateMenu) |
127 |
130 |
128 menu = self.__ui.getMenu("plugin_tools") |
131 menu = self.__ui.getMenu("plugin_tools") |
129 if menu is not None: |
132 if menu is not None: |
130 for act in self.__mainActions: |
133 for act in self.__mainActions: |
131 menu.removeAction(act) |
134 menu.removeAction(act) |
132 self.__mainActions = [] |
135 self.__mainActions = [] |
133 |
136 |
134 ericApp().getObject("ViewManager").editorOpenedEd.disconnect( |
137 ericApp().getObject("ViewManager").editorOpenedEd.disconnect( |
135 self.__editorOpened) |
138 self.__editorOpened |
|
139 ) |
136 ericApp().getObject("ViewManager").editorClosedEd.disconnect( |
140 ericApp().getObject("ViewManager").editorClosedEd.disconnect( |
137 self.__editorClosed) |
141 self.__editorClosed |
138 |
142 ) |
|
143 |
139 for editor, acts in self.__editors.items(): |
144 for editor, acts in self.__editors.items(): |
140 editor.showMenu.disconnect(self.__editorShowMenu) |
145 editor.showMenu.disconnect(self.__editorShowMenu) |
141 menu = editor.getMenu("Tools") |
146 menu = editor.getMenu("Tools") |
142 if menu is not None: |
147 if menu is not None: |
143 for act in acts: |
148 for act in acts: |
144 menu.removeAction(act) |
149 menu.removeAction(act) |
145 |
150 |
146 self.__initialize() |
151 self.__initialize() |
147 |
152 |
148 def __loadTranslator(self): |
153 def __loadTranslator(self): |
149 """ |
154 """ |
150 Private method to load the translation file. |
155 Private method to load the translation file. |
151 """ |
156 """ |
152 if self.__ui is not None: |
157 if self.__ui is not None: |
153 loc = self.__ui.getLocale() |
158 loc = self.__ui.getLocale() |
154 if loc and loc != "C": |
159 if loc and loc != "C": |
155 locale_dir = os.path.join( |
160 locale_dir = os.path.join( |
156 os.path.dirname(__file__), "ProjectWeb", "i18n") |
161 os.path.dirname(__file__), "ProjectWeb", "i18n" |
|
162 ) |
157 translation = "web_{0}".format(loc) |
163 translation = "web_{0}".format(loc) |
158 translator = QTranslator(None) |
164 translator = QTranslator(None) |
159 loaded = translator.load(translation, locale_dir) |
165 loaded = translator.load(translation, locale_dir) |
160 if loaded: |
166 if loaded: |
161 self.__translator = translator |
167 self.__translator = translator |
162 ericApp().installTranslator(self.__translator) |
168 ericApp().installTranslator(self.__translator) |
163 else: |
169 else: |
164 print("Warning: translation file '{0}' could not be" |
170 print( |
165 " loaded.".format(translation)) |
171 "Warning: translation file '{0}' could not be" |
|
172 " loaded.".format(translation) |
|
173 ) |
166 print("Using default.") |
174 print("Using default.") |
167 |
175 |
168 def fileTypesCallback(self): |
176 def fileTypesCallback(self): |
169 """ |
177 """ |
170 Public method to get the filetype associations of the Web project type. |
178 Public method to get the filetype associations of the Web project type. |
171 |
179 |
172 @return dictionary with file type associations |
180 @return dictionary with file type associations |
173 @rtype dict |
181 @rtype dict |
174 """ |
182 """ |
175 if self.__ericProject.getProjectType() == "Web": |
183 if self.__ericProject.getProjectType() == "Web": |
176 return { |
184 return { |
178 "*.htm": "FORMS", |
186 "*.htm": "FORMS", |
179 "*.js": "SOURCES", |
187 "*.js": "SOURCES", |
180 } |
188 } |
181 else: |
189 else: |
182 return {} |
190 return {} |
183 |
191 |
184 def __initMenu(self): |
192 def __initMenu(self): |
185 """ |
193 """ |
186 Private method to initialize the web tools menu. |
194 Private method to initialize the web tools menu. |
187 """ |
195 """ |
188 self.__menu = QMenu(self.tr("Web")) |
196 self.__menu = QMenu(self.tr("Web")) |
189 |
197 |
190 self.__html5ToCss3Act = self.__menu.addAction(self.tr( |
198 self.__html5ToCss3Act = self.__menu.addAction( |
191 "HTML5 to CSS3"), self.__html5ToCss3) |
199 self.tr("HTML5 to CSS3"), self.__html5ToCss3 |
192 self.__html5ToJsAct = self.__menu.addAction(self.tr( |
200 ) |
193 "HTML5 to JavaScript"), self.__html5ToJs) |
201 self.__html5ToJsAct = self.__menu.addAction( |
|
202 self.tr("HTML5 to JavaScript"), self.__html5ToJs |
|
203 ) |
194 self.__menu.addSeparator() |
204 self.__menu.addSeparator() |
195 self.__html5PrettifyAct = self.__menu.addAction(self.tr( |
205 self.__html5PrettifyAct = self.__menu.addAction( |
196 "Prettify HTML"), self.__html5Prettify) |
206 self.tr("Prettify HTML"), self.__html5Prettify |
197 |
207 ) |
|
208 |
198 self.__menu.aboutToShow.connect(self.__menuAboutToShow) |
209 self.__menu.aboutToShow.connect(self.__menuAboutToShow) |
199 |
210 |
200 def __menuAboutToShow(self): |
211 def __menuAboutToShow(self): |
201 """ |
212 """ |
202 Private slot to prepare the menu before it is shown. |
213 Private slot to prepare the menu before it is shown. |
203 """ |
214 """ |
204 editor = ericApp().getObject("ViewManager").activeWindow() |
215 editor = ericApp().getObject("ViewManager").activeWindow() |
205 selectionAvailable = bool(editor and editor.selectedText() != "") |
216 selectionAvailable = bool(editor and editor.selectedText() != "") |
206 isHtml = bool(editor and |
217 isHtml = bool(editor and editor.getLanguage().lower().startswith("html")) |
207 editor.getLanguage().lower().startswith("html")) |
218 |
208 |
|
209 self.__html5ToCss3Act.setEnabled( |
219 self.__html5ToCss3Act.setEnabled( |
210 selectionAvailable and BeautifulSoupAvailable and isHtml) |
220 selectionAvailable and BeautifulSoupAvailable and isHtml |
|
221 ) |
211 self.__html5ToJsAct.setEnabled( |
222 self.__html5ToJsAct.setEnabled( |
212 selectionAvailable and BeautifulSoupAvailable and isHtml) |
223 selectionAvailable and BeautifulSoupAvailable and isHtml |
213 self.__html5PrettifyAct.setEnabled( |
224 ) |
214 BeautifulSoupAvailable and isHtml) |
225 self.__html5PrettifyAct.setEnabled(BeautifulSoupAvailable and isHtml) |
215 |
226 |
216 def __populateMenu(self, name, menu): |
227 def __populateMenu(self, name, menu): |
217 """ |
228 """ |
218 Private slot to populate the tools menu with our entries. |
229 Private slot to populate the tools menu with our entries. |
219 |
230 |
220 @param name name of the menu |
231 @param name name of the menu |
221 @type str |
232 @type str |
222 @param menu reference to the menu to be populated |
233 @param menu reference to the menu to be populated |
223 @type QMenu |
234 @type QMenu |
224 """ |
235 """ |
225 if name not in ["Tools", "PluginTools"]: |
236 if name not in ["Tools", "PluginTools"]: |
226 return |
237 return |
227 |
238 |
228 if name == "Tools": |
239 if name == "Tools": |
229 if not menu.isEmpty(): |
240 if not menu.isEmpty(): |
230 menu.addSeparator() |
241 menu.addSeparator() |
231 menu.addMenu(self.__menu) |
242 menu.addMenu(self.__menu) |
232 |
243 |
233 def __editorOpened(self, editor): |
244 def __editorOpened(self, editor): |
234 """ |
245 """ |
235 Private slot called, when a new editor was opened. |
246 Private slot called, when a new editor was opened. |
236 |
247 |
237 @param editor reference to the new editor |
248 @param editor reference to the new editor |
238 @type Editor |
249 @type Editor |
239 """ |
250 """ |
240 menu = editor.getMenu("Tools") |
251 menu = editor.getMenu("Tools") |
241 if menu is not None: |
252 if menu is not None: |
244 act = menu.addSeparator() |
255 act = menu.addSeparator() |
245 self.__editors[editor].append(act) |
256 self.__editors[editor].append(act) |
246 act = menu.addMenu(self.__menu) |
257 act = menu.addMenu(self.__menu) |
247 self.__editors[editor].append(act) |
258 self.__editors[editor].append(act) |
248 editor.showMenu.connect(self.__editorShowMenu) |
259 editor.showMenu.connect(self.__editorShowMenu) |
249 |
260 |
250 def __editorClosed(self, editor): |
261 def __editorClosed(self, editor): |
251 """ |
262 """ |
252 Private slot called, when an editor was closed. |
263 Private slot called, when an editor was closed. |
253 |
264 |
254 @param editor reference to the editor |
265 @param editor reference to the editor |
255 @type Editor |
266 @type Editor |
256 """ |
267 """ |
257 with contextlib.suppress(KeyError): |
268 with contextlib.suppress(KeyError): |
258 del self.__editors[editor] |
269 del self.__editors[editor] |
259 |
270 |
260 def __editorShowMenu(self, menuName, menu, editor): |
271 def __editorShowMenu(self, menuName, menu, editor): |
261 """ |
272 """ |
262 Private slot called, when the the editor context menu or a submenu is |
273 Private slot called, when the the editor context menu or a submenu is |
263 about to be shown. |
274 about to be shown. |
264 |
275 |
265 @param menuName name of the menu to be shown |
276 @param menuName name of the menu to be shown |
266 @type str |
277 @type str |
267 @param menu reference to the menu |
278 @param menu reference to the menu |
268 @type QMenu |
279 @type QMenu |
269 @param editor reference to the editor |
280 @param editor reference to the editor |
270 @type Editor |
281 @type Editor |
271 """ |
282 """ |
272 if ( |
283 if menuName == "Tools" and self.__menu.menuAction() not in menu.actions(): |
273 menuName == "Tools" and |
|
274 self.__menu.menuAction() not in menu.actions() |
|
275 ): |
|
276 # Re-add our menu |
284 # Re-add our menu |
277 self.__editors[editor] = [] |
285 self.__editors[editor] = [] |
278 if not menu.isEmpty(): |
286 if not menu.isEmpty(): |
279 act = menu.addSeparator() |
287 act = menu.addSeparator() |
280 self.__editors[editor].append(act) |
288 self.__editors[editor].append(act) |
281 act = menu.addMenu(self.__menu) |
289 act = menu.addMenu(self.__menu) |
282 self.__editors[editor].append(act) |
290 self.__editors[editor].append(act) |
283 |
291 |
284 def __html5ToCss3(self): |
292 def __html5ToCss3(self): |
285 """ |
293 """ |
286 Private slot handling the HTML5 to CSS3 conversion. |
294 Private slot handling the HTML5 to CSS3 conversion. |
287 """ |
295 """ |
288 from ProjectWeb.Html5ToCss3Converter import Html5ToCss3Converter |
296 from ProjectWeb.Html5ToCss3Converter import Html5ToCss3Converter |
|
297 |
289 vm = ericApp().getObject("ViewManager") |
298 vm = ericApp().getObject("ViewManager") |
290 editor = vm.activeWindow() |
299 editor = vm.activeWindow() |
291 html = editor.selectedText() |
300 html = editor.selectedText() |
292 |
301 |
293 converter = Html5ToCss3Converter(html) |
302 converter = Html5ToCss3Converter(html) |
294 css3 = converter.getCss3() |
303 css3 = converter.getCss3() |
295 |
304 |
296 if css3: |
305 if css3: |
297 vm.newEditor() |
306 vm.newEditor() |
298 newEditor = vm.activeWindow() |
307 newEditor = vm.activeWindow() |
299 newEditor.setText(css3) |
308 newEditor.setText(css3) |
300 newEditor.setLanguage("dummy.css") |
309 newEditor.setLanguage("dummy.css") |
301 |
310 |
302 def __html5ToJs(self): |
311 def __html5ToJs(self): |
303 """ |
312 """ |
304 Private slot handling the HTML5 to JavaScript conversion. |
313 Private slot handling the HTML5 to JavaScript conversion. |
305 """ |
314 """ |
306 from ProjectWeb.Html5ToJsConverter import Html5ToJsConverter |
315 from ProjectWeb.Html5ToJsConverter import Html5ToJsConverter |
|
316 |
307 vm = ericApp().getObject("ViewManager") |
317 vm = ericApp().getObject("ViewManager") |
308 editor = vm.activeWindow() |
318 editor = vm.activeWindow() |
309 html = editor.selectedText() |
319 html = editor.selectedText() |
310 |
320 |
311 converter = Html5ToJsConverter(html) |
321 converter = Html5ToJsConverter(html) |
312 js = converter.getJavaScript() |
322 js = converter.getJavaScript() |
313 |
323 |
314 if js: |
324 if js: |
315 vm.newEditor() |
325 vm.newEditor() |
316 newEditor = vm.activeWindow() |
326 newEditor = vm.activeWindow() |
317 newEditor.setText(js) |
327 newEditor.setText(js) |
318 newEditor.setLanguage("dummy.js") |
328 newEditor.setLanguage("dummy.js") |
319 |
329 |
320 def __html5Prettify(self): |
330 def __html5Prettify(self): |
321 """ |
331 """ |
322 Private slot handling the Prettify HTML action. |
332 Private slot handling the Prettify HTML action. |
323 """ |
333 """ |
324 from ProjectWeb.Html5Prettifier import Html5Prettifier |
334 from ProjectWeb.Html5Prettifier import Html5Prettifier |
|
335 |
325 editor = ericApp().getObject("ViewManager").activeWindow() |
336 editor = ericApp().getObject("ViewManager").activeWindow() |
326 html = editor.text() |
337 html = editor.text() |
327 |
338 |
328 prettifier = Html5Prettifier(html) |
339 prettifier = Html5Prettifier(html) |
329 newHtml = prettifier.getPrettifiedHtml() |
340 newHtml = prettifier.getPrettifiedHtml() |
330 |
341 |
331 if newHtml and newHtml != html: |
342 if newHtml and newHtml != html: |
332 cursorLine, cursorIndex = editor.getCursorPosition() |
343 cursorLine, cursorIndex = editor.getCursorPosition() |
333 |
344 |
334 editor.beginUndoAction() |
345 editor.beginUndoAction() |
335 editor.selectAll() |
346 editor.selectAll() |
336 editor.replaceSelectedText(newHtml) |
347 editor.replaceSelectedText(newHtml) |
337 editor.endUndoAction() |
348 editor.endUndoAction() |
338 |
349 |
339 editor.setCursorPosition(cursorLine, cursorIndex) |
350 editor.setCursorPosition(cursorLine, cursorIndex) |
340 |
351 |
341 |
352 |
342 def installDependencies(pipInstall): |
353 def installDependencies(pipInstall): |
343 """ |
354 """ |
344 Function to install dependencies of this plug-in. |
355 Function to install dependencies of this plug-in. |
345 |
356 |
346 @param pipInstall function to be called with a list of package names. |
357 @param pipInstall function to be called with a list of package names. |
347 @type function |
358 @type function |
348 """ |
359 """ |
349 try: |
360 try: |
350 import bs4 # __IGNORE_WARNING__ |
361 import bs4 # __IGNORE_WARNING__ |
351 except ImportError: |
362 except ImportError: |
352 pipInstall(["beautifulsoup4"]) |
363 pipInstall(["beautifulsoup4"]) |
353 |
364 |
|
365 |
354 # |
366 # |
355 # eflag: noqa = M801 |
367 # eflag: noqa = M801 |