|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2014 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 """ |
|
7 Module implementing the Selection Encloser plug-in. |
|
8 """ |
|
9 |
|
10 from __future__ import unicode_literals # __IGNORE_WARNING__ |
|
11 |
|
12 import os |
|
13 import json |
|
14 |
|
15 from PyQt4.QtCore import QObject, QTranslator, QCoreApplication |
|
16 from PyQt4.QtGui import QAction, QMenu |
|
17 |
|
18 from E5Gui.E5Application import e5App |
|
19 |
|
20 import Preferences |
|
21 |
|
22 # Start-Of-Header |
|
23 name = "Selection Encloser Plug-in" |
|
24 author = "Detlev Offenbach <detlev@die-offenbachs.de>" |
|
25 autoactivate = True |
|
26 deactivateable = True |
|
27 version = "0.1.0" |
|
28 className = "SelectionEncloserPlugin" |
|
29 packageName = "SelectionEncloser" |
|
30 shortDescription = "Enclose the selection with a string." |
|
31 longDescription = \ |
|
32 """This plug-in implements a tool to enclose the selection of""" \ |
|
33 """ the current editor with a string. The enclosing string is""" \ |
|
34 """ selectable via a configurable menu hierarchy.""" |
|
35 needsRestart = False |
|
36 pyqtApi = 2 |
|
37 python2Compatible = True |
|
38 # End-Of-Header |
|
39 |
|
40 error = "" |
|
41 |
|
42 selectionEncloserPluginObject = None |
|
43 |
|
44 |
|
45 def createSelectionEncloserPage(configDlg): |
|
46 """ |
|
47 Module function to create the Selection Encloser configuration page. |
|
48 |
|
49 @param configDlg reference to the configuration dialog |
|
50 @return reference to the configuration page |
|
51 """ |
|
52 global selectionEncloserPluginObject |
|
53 from SelectionEncloser.ConfigurationPage.SelectionEncloserPage import \ |
|
54 SelectionEncloserPage |
|
55 page = SelectionEncloserPage(selectionEncloserPluginObject) |
|
56 return page |
|
57 |
|
58 |
|
59 def getConfigData(): |
|
60 """ |
|
61 Module function returning data as required by the configuration dialog. |
|
62 |
|
63 @return dictionary containing the relevant data |
|
64 """ |
|
65 if e5App().getObject("UserInterface").versionIsNewer('5.2.99', '20121012'): |
|
66 return { |
|
67 "selectionEncloserPage": [ |
|
68 QCoreApplication.translate("SelectionEncloserPlugin", |
|
69 "Selection Encloser"), |
|
70 os.path.join("SelectionEncloser", "icons", |
|
71 "selectionEncloser.png"), |
|
72 createSelectionEncloserPage, None, None], |
|
73 } |
|
74 else: |
|
75 return {} |
|
76 |
|
77 |
|
78 def prepareUninstall(): |
|
79 """ |
|
80 Module function to prepare for an uninstallation. |
|
81 """ |
|
82 Preferences.Prefs.settings.remove(SelectionEncloserPlugin.PreferencesKey) |
|
83 |
|
84 |
|
85 class SelectionEncloserPlugin(QObject): |
|
86 """ |
|
87 Class implementing the Selection Encloser plugin. |
|
88 """ |
|
89 PreferencesKey = "SelectionEncloser" |
|
90 |
|
91 def __init__(self, ui): |
|
92 """ |
|
93 Constructor |
|
94 |
|
95 @param ui reference to the user interface object (UI.UserInterface) |
|
96 """ |
|
97 QObject.__init__(self, ui) |
|
98 self.__ui = ui |
|
99 |
|
100 # menu is a list of lists; each list consists of a string for the |
|
101 # submenu title and a list of submenu entries. The title of the submenu |
|
102 # entry is the enclosing string. |
|
103 defaultMenu = [ |
|
104 [self.tr("Quotes"), ['"', "'", '"""', "'''"]], |
|
105 ] |
|
106 self.__defaults = { |
|
107 "MenuHierarchy": json.dumps(defaultMenu), |
|
108 } |
|
109 |
|
110 self.__translator = None |
|
111 self.__loadTranslator() |
|
112 |
|
113 self.__initMenu() |
|
114 |
|
115 self.__editors = {} |
|
116 |
|
117 def activate(self): |
|
118 """ |
|
119 Public method to activate this plugin. |
|
120 |
|
121 @return tuple of None and activation status (boolean) |
|
122 """ |
|
123 global error |
|
124 error = "" # clear previous error |
|
125 |
|
126 global selectionEncloserPluginObject |
|
127 selectionEncloserPluginObject = self |
|
128 |
|
129 self.__ui.showMenu.connect(self.__populateMenu) |
|
130 |
|
131 e5App().getObject("ViewManager").editorOpenedEd.connect( |
|
132 self.__editorOpened) |
|
133 e5App().getObject("ViewManager").editorClosedEd.connect( |
|
134 self.__editorClosed) |
|
135 |
|
136 for editor in e5App().getObject("ViewManager").getOpenEditors(): |
|
137 self.__editorOpened(editor) |
|
138 |
|
139 return None, True |
|
140 |
|
141 def deactivate(self): |
|
142 """ |
|
143 Public method to deactivate this plugin. |
|
144 """ |
|
145 self.__ui.showMenu.disconnect(self.__populateMenu) |
|
146 |
|
147 e5App().getObject("ViewManager").editorOpenedEd.disconnect( |
|
148 self.__editorOpened) |
|
149 e5App().getObject("ViewManager").editorClosedEd.disconnect( |
|
150 self.__editorClosed) |
|
151 |
|
152 for editor, acts in self.__editors.items(): |
|
153 menu = editor.getMenu("Tools") |
|
154 if menu is not None: |
|
155 for act in acts: |
|
156 menu.removeAction(act) |
|
157 self.__editors = {} |
|
158 |
|
159 def __loadTranslator(self): |
|
160 """ |
|
161 Private method to load the translation file. |
|
162 """ |
|
163 if self.__ui is not None: |
|
164 loc = self.__ui.getLocale() |
|
165 if loc and loc != "C": |
|
166 locale_dir = os.path.join( |
|
167 os.path.dirname(__file__), "SelectionEncloser", "i18n") |
|
168 translation = "selectionencloser_{0}".format(loc) |
|
169 translator = QTranslator(None) |
|
170 loaded = translator.load(translation, locale_dir) |
|
171 if loaded: |
|
172 self.__translator = translator |
|
173 e5App().installTranslator(self.__translator) |
|
174 else: |
|
175 print("Warning: translation file '{0}' could not be" |
|
176 " loaded.".format(translation)) |
|
177 print("Using default.") |
|
178 |
|
179 def getPreferences(self, key): |
|
180 """ |
|
181 Public method to retrieve the various settings. |
|
182 |
|
183 @param key the key of the value to get (string) |
|
184 @return the requested setting |
|
185 """ |
|
186 if key in ["MenuHierarchy"]: |
|
187 return json.loads( |
|
188 Preferences.Prefs.settings.value( |
|
189 self.PreferencesKey + "/" + key, self.__defaults[key])) |
|
190 else: |
|
191 return Preferences.Prefs.settings.value( |
|
192 self.PreferencesKey + "/" + key, self.__defaults[key]) |
|
193 |
|
194 def setPreferences(self, key, value): |
|
195 """ |
|
196 Public method to store the various settings. |
|
197 |
|
198 @param key the key of the setting to be set (string) |
|
199 @param value the value to be set |
|
200 """ |
|
201 if key in ["MenuHierarchy"]: |
|
202 Preferences.Prefs.settings.setValue( |
|
203 self.PreferencesKey + "/" + key, json.dumps(value)) |
|
204 else: |
|
205 Preferences.Prefs.settings.setValue( |
|
206 self.PreferencesKey + "/" + key, value) |
|
207 |
|
208 def __initMenu(self): |
|
209 """ |
|
210 Private method to initialize the menu. |
|
211 """ |
|
212 self.__menu = QMenu("Enclose Selection") |
|
213 self.__menu.setEnabled(False) |
|
214 self.__menu.aboutToShow.connect(self.__showMenu) |
|
215 |
|
216 def __populateMenu(self, name, menu): |
|
217 """ |
|
218 Private slot to populate the tools menu with our entry. |
|
219 |
|
220 @param name name of the menu (string) |
|
221 @param menu reference to the menu to be populated (QMenu) |
|
222 """ |
|
223 if name != "Tools": |
|
224 return |
|
225 |
|
226 editor = e5App().getObject("ViewManager").activeWindow() |
|
227 |
|
228 if not menu.isEmpty(): |
|
229 menu.addSeparator() |
|
230 |
|
231 act = menu.addMenu(self.__menu) |
|
232 act.setEnabled(editor is not None and editor.hasSelectedText()) |
|
233 |
|
234 def __editorOpened(self, editor): |
|
235 """ |
|
236 Private slot called, when a new editor was opened. |
|
237 |
|
238 @param editor reference to the new editor (QScintilla.Editor) |
|
239 """ |
|
240 menu = editor.getMenu("Tools") |
|
241 if menu is not None: |
|
242 self.__editors[editor] = [] |
|
243 if not menu.isEmpty(): |
|
244 act = menu.addSeparator() |
|
245 self.__editors[editor].append(act) |
|
246 act = menu.addMenu(self.__menu) |
|
247 self.__menu.setEnabled(True) |
|
248 self.__editors[editor].append(act) |
|
249 editor.showMenu.connect(self.__editorShowMenu) |
|
250 |
|
251 def __editorClosed(self, editor): |
|
252 """ |
|
253 Private slot called, when an editor was closed. |
|
254 |
|
255 @param editor reference to the editor (QScintilla.Editor) |
|
256 """ |
|
257 try: |
|
258 del self.__editors[editor] |
|
259 if not self.__editors: |
|
260 self.__menu.setEnabled(False) |
|
261 except KeyError: |
|
262 pass |
|
263 |
|
264 def __editorShowMenu(self, menuName, menu, editor): |
|
265 """ |
|
266 Private slot called, when the the editor context menu or a submenu is |
|
267 about to be shown. |
|
268 |
|
269 @param menuName name of the menu to be shown (string) |
|
270 @param menu reference to the menu (QMenu) |
|
271 @param editor reference to the editor |
|
272 """ |
|
273 if menuName == "Tools": |
|
274 for act in self.__editors[editor]: |
|
275 if not act.isSeparator(): |
|
276 act.setEnabled(editor.hasSelectedText()) |
|
277 |
|
278 def __showMenu(self): |
|
279 """ |
|
280 Private slot to build the menu hierarchy. |
|
281 """ |
|
282 self.__menu.clear() |
|
283 hierarchy = self.getPreferences("MenuHierarchy") |
|
284 for menuTitle, entries in hierarchy: |
|
285 submenu = QMenu(menuTitle, self.__menu) |
|
286 for entry in entries: |
|
287 act = submenu.addAction(entry, self.__encloseSelection) |
|
288 act.setData(entry) |
|
289 self.__menu.addMenu(submenu) |
|
290 |
|
291 def __encloseSelection(self): |
|
292 """ |
|
293 Private slot to enclose the selection with the selected string. |
|
294 """ |
|
295 act = self.sender() |
|
296 if act is None or not isinstance(act, QAction): |
|
297 return |
|
298 |
|
299 editor = e5App().getObject("ViewManager").activeWindow() |
|
300 if editor is None: |
|
301 return |
|
302 |
|
303 if not editor.hasSelectedText(): |
|
304 return |
|
305 |
|
306 string = act.data() |
|
307 if not string: |
|
308 return |
|
309 |
|
310 newText = string + editor.selectedText() + string |
|
311 editor.beginUndoAction() |
|
312 editor.replaceSelectedText(newText) |
|
313 editor.endUndoAction() |