|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2014 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 """ |
|
7 Module implementing the 'Color String' tool plug-in. |
|
8 """ |
|
9 |
|
10 from __future__ import unicode_literals |
|
11 |
|
12 import os |
|
13 |
|
14 from PyQt4.QtCore import QObject, QTranslator |
|
15 from PyQt4.QtGui import QColor, QColorDialog, QMenu, QDialog |
|
16 |
|
17 from E5Gui.E5Application import e5App |
|
18 from E5Gui import E5MessageBox |
|
19 |
|
20 # Start-Of-Header |
|
21 name = "Color String Plug-in" |
|
22 author = "Detlev Offenbach <detlev@die-offenbachs.de>" |
|
23 autoactivate = True |
|
24 deactivateable = True |
|
25 version = "0.1.0" |
|
26 className = "ColorStringPlugin" |
|
27 packageName = "ColorString" |
|
28 shortDescription = "Insert color as string" |
|
29 longDescription = \ |
|
30 """This plug-in implements a tool to select a color via a""" \ |
|
31 """ color selection dialog and insert it as a hex string at the""" \ |
|
32 """ current cursor position. Selected text is used to initialize""" \ |
|
33 """ the dialog and is replaced with the new color.""" |
|
34 needsRestart = False |
|
35 pyqtApi = 2 |
|
36 # End-Of-Header |
|
37 |
|
38 error = "" |
|
39 |
|
40 |
|
41 class ColorStringPlugin(QObject): |
|
42 """ |
|
43 Class implementing the 'Color String' tool plug-in. |
|
44 """ |
|
45 def __init__(self, ui): |
|
46 """ |
|
47 Constructor |
|
48 |
|
49 @param ui reference to the user interface object (UI.UserInterface) |
|
50 """ |
|
51 QObject.__init__(self, ui) |
|
52 self.__ui = ui |
|
53 |
|
54 self.__translator = None |
|
55 self.__loadTranslator() |
|
56 |
|
57 self.__initMenu() |
|
58 |
|
59 self.__editors = {} |
|
60 |
|
61 def activate(self): |
|
62 """ |
|
63 Public method to activate this plugin. |
|
64 |
|
65 @return tuple of None and activation status (boolean) |
|
66 """ |
|
67 global error |
|
68 error = "" # clear previous error |
|
69 |
|
70 self.__ui.showMenu.connect(self.__populateMenu) |
|
71 |
|
72 e5App().getObject("ViewManager").editorOpenedEd.connect( |
|
73 self.__editorOpened) |
|
74 e5App().getObject("ViewManager").editorClosedEd.connect( |
|
75 self.__editorClosed) |
|
76 |
|
77 for editor in e5App().getObject("ViewManager").getOpenEditors(): |
|
78 self.__editorOpened(editor) |
|
79 |
|
80 return None, True |
|
81 |
|
82 def deactivate(self): |
|
83 """ |
|
84 Public method to deactivate this plugin. |
|
85 """ |
|
86 self.__ui.showMenu.disconnect(self.__populateMenu) |
|
87 |
|
88 e5App().getObject("ViewManager").editorOpenedEd.disconnect( |
|
89 self.__editorOpened) |
|
90 e5App().getObject("ViewManager").editorClosedEd.disconnect( |
|
91 self.__editorClosed) |
|
92 |
|
93 for editor, acts in self.__editors.items(): |
|
94 menu = editor.getMenu("Tools") |
|
95 if menu is not None: |
|
96 for act in acts: |
|
97 menu.removeAction(act) |
|
98 self.__editors = {} |
|
99 |
|
100 def __loadTranslator(self): |
|
101 """ |
|
102 Private method to load the translation file. |
|
103 """ |
|
104 if self.__ui is not None: |
|
105 loc = self.__ui.getLocale() |
|
106 if loc and loc != "C": |
|
107 locale_dir = os.path.join( |
|
108 os.path.dirname(__file__), "ColorString", "i18n") |
|
109 translation = "colorstring_{0}".format(loc) |
|
110 translator = QTranslator(None) |
|
111 loaded = translator.load(translation, locale_dir) |
|
112 if loaded: |
|
113 self.__translator = translator |
|
114 e5App().installTranslator(self.__translator) |
|
115 else: |
|
116 print("Warning: translation file '{0}' could not be" |
|
117 " loaded.".format(translation)) |
|
118 print("Using default.") |
|
119 |
|
120 def __initMenu(self): |
|
121 """ |
|
122 Private method to initialize the menu. |
|
123 """ |
|
124 self.__menu = QMenu("Color String") |
|
125 self.__menu.addAction("Hex Color", self.__selectHexColor) |
|
126 self.__menu.addAction("Color Name", self.__selectColorName) |
|
127 self.__menu.setEnabled(False) |
|
128 |
|
129 def __populateMenu(self, name, menu): |
|
130 """ |
|
131 Private slot to populate the tools menu with our entry. |
|
132 |
|
133 @param name name of the menu (string) |
|
134 @param menu reference to the menu to be populated (QMenu) |
|
135 """ |
|
136 if name != "Tools": |
|
137 return |
|
138 |
|
139 if not menu.isEmpty(): |
|
140 menu.addSeparator() |
|
141 menu.addMenu(self.__menu) |
|
142 |
|
143 def __editorOpened(self, editor): |
|
144 """ |
|
145 Private slot called, when a new editor was opened. |
|
146 |
|
147 @param editor reference to the new editor (QScintilla.Editor) |
|
148 """ |
|
149 menu = editor.getMenu("Tools") |
|
150 if menu is not None: |
|
151 self.__editors[editor] = [] |
|
152 if not menu.isEmpty(): |
|
153 act = menu.addSeparator() |
|
154 self.__editors[editor].append(act) |
|
155 act = menu.addMenu(self.__menu) |
|
156 self.__menu.setEnabled(True) |
|
157 self.__editors[editor].append(act) |
|
158 |
|
159 def __editorClosed(self, editor): |
|
160 """ |
|
161 Private slot called, when an editor was closed. |
|
162 |
|
163 @param editor reference to the editor (QScintilla.Editor) |
|
164 """ |
|
165 try: |
|
166 del self.__editors[editor] |
|
167 if not self.__editors: |
|
168 self.__menu.setEnabled(False) |
|
169 except KeyError: |
|
170 pass |
|
171 |
|
172 def __isHexString(self, text): |
|
173 """ |
|
174 Private method to check, if a given text is a hex string. |
|
175 |
|
176 @param text text to check (string) |
|
177 @return flag indicating a hex string (boolean) |
|
178 """ |
|
179 isHex = True |
|
180 for c in text: |
|
181 isHex = isHex and c in "0123456789abcdefABCDEF" |
|
182 return isHex |
|
183 |
|
184 def __isValidColor(self, name): |
|
185 """ |
|
186 Private method to check for a valid color name. |
|
187 |
|
188 @param name color name to check (string) |
|
189 @return flag indicating a valid color name (boolean) |
|
190 """ |
|
191 try: |
|
192 if self.__isHexString(name) and len(name) in [3, 6, 9, 12]: |
|
193 return True |
|
194 return QColor.isValidColor(name) |
|
195 except AttributeError: |
|
196 if name.startswith("#"): |
|
197 if len(name) not in [4, 7, 10, 13]: |
|
198 return False |
|
199 hexCheckStr = name[1:] |
|
200 return self.__isHexString(hexCheckStr) |
|
201 else: |
|
202 if self.__isHexString(name) and len(name) in [3, 6, 9, 12]: |
|
203 return True |
|
204 return name in QColor.colorNames() |
|
205 |
|
206 def __selectHexColor(self): |
|
207 """ |
|
208 Private slot implementing the hex color string selection. |
|
209 """ |
|
210 editor = e5App().getObject("ViewManager").activeWindow() |
|
211 if editor is None: |
|
212 return |
|
213 |
|
214 if editor.hasSelectedText(): |
|
215 currColor = editor.selectedText() |
|
216 if not self.__isValidColor(currColor): |
|
217 E5MessageBox.critical( |
|
218 self.__ui, |
|
219 self.trUtf8("Color String"), |
|
220 self.trUtf8( |
|
221 """<p>The selected string <b>{0}</b> is not a""" \ |
|
222 """ valid color string. Aborting!</p>""") |
|
223 .format(currColor)) |
|
224 return |
|
225 |
|
226 if currColor.startswith("#"): |
|
227 withHash = True |
|
228 elif self.__isHexString(currColor): |
|
229 withHash = False |
|
230 currColor = "#" + currColor |
|
231 else: |
|
232 withHash = True |
|
233 initColor = QColor(currColor) |
|
234 else: |
|
235 withHash = True |
|
236 currColor = "" |
|
237 initColor = QColor() |
|
238 |
|
239 color = QColorDialog.getColor( |
|
240 initColor, self.__ui, self.tr("Color String")) |
|
241 if color.isValid(): |
|
242 colorStr = color.name() |
|
243 if not withHash: |
|
244 colorStr = colorStr[1:] |
|
245 editor.beginUndoAction() |
|
246 if editor.hasSelectedText(): |
|
247 editor.replaceSelectedText(colorStr) |
|
248 else: |
|
249 line, index = editor.getCursorPosition() |
|
250 editor.insert(colorStr) |
|
251 editor.setCursorPosition(line, index + len(colorStr)) |
|
252 editor.endUndoAction() |
|
253 |
|
254 def __selectColorName(self): |
|
255 """ |
|
256 Private slot implementing the named color string selection. |
|
257 """ |
|
258 editor = e5App().getObject("ViewManager").activeWindow() |
|
259 if editor is None: |
|
260 return |
|
261 |
|
262 if editor.hasSelectedText(): |
|
263 currColor = editor.selectedText() |
|
264 if currColor not in QColor.colorNames(): |
|
265 E5MessageBox.critical( |
|
266 self.__ui, |
|
267 self.trUtf8("Color String"), |
|
268 self.trUtf8( |
|
269 """<p>The selected string <b>{0}</b> is not a""" \ |
|
270 """ valid color name. Aborting!</p>""") |
|
271 .format(currColor)) |
|
272 return |
|
273 else: |
|
274 currColor = "" |
|
275 |
|
276 from ColorString.ColorSelectionDialog import ColorSelectionDialog |
|
277 dlg = ColorSelectionDialog(currColor, self.__ui) |
|
278 if dlg.exec_() == QDialog.Accepted: |
|
279 colorStr = dlg.getColor() |
|
280 editor.beginUndoAction() |
|
281 if editor.hasSelectedText(): |
|
282 editor.replaceSelectedText(colorStr) |
|
283 else: |
|
284 line, index = editor.getCursorPosition() |
|
285 editor.insert(colorStr) |
|
286 editor.setCursorPosition(line, index + len(colorStr)) |
|
287 editor.endUndoAction() |