PluginColorString.py

branch
eric7
changeset 57
b633598e2e67
parent 55
43b616631f94
child 58
80dfe684353a
equal deleted inserted replaced
56:69d0e91cf0fb 57:b633598e2e67
41 41
42 class ColorStringPlugin(QObject): 42 class ColorStringPlugin(QObject):
43 """ 43 """
44 Class implementing the 'Color String' tool plug-in. 44 Class implementing the 'Color String' tool plug-in.
45 """ 45 """
46
46 def __init__(self, ui): 47 def __init__(self, ui):
47 """ 48 """
48 Constructor 49 Constructor
49 50
50 @param ui reference to the user interface object 51 @param ui reference to the user interface object
51 @type UserInterface 52 @type UserInterface
52 """ 53 """
53 super().__init__(ui) 54 super().__init__(ui)
54 self.__ui = ui 55 self.__ui = ui
55 56
56 self.__translator = None 57 self.__translator = None
57 self.__loadTranslator() 58 self.__loadTranslator()
58 59
59 self.__initMenu() 60 self.__initMenu()
60 61
61 self.__editors = {} 62 self.__editors = {}
62 self.__mainActions = [] 63 self.__mainActions = []
63 64
64 def activate(self): 65 def activate(self):
65 """ 66 """
66 Public method to activate this plugin. 67 Public method to activate this plugin.
67 68
68 @return tuple of None and activation status 69 @return tuple of None and activation status
69 @rtype tuple of (None, bool) 70 @rtype tuple of (None, bool)
70 """ 71 """
71 global error 72 global error
72 error = "" # clear previous error 73 error = "" # clear previous error
73 74
74 self.__ui.showMenu.connect(self.__populateMenu) 75 self.__ui.showMenu.connect(self.__populateMenu)
75 76
76 menu = self.__ui.getMenu("plugin_tools") 77 menu = self.__ui.getMenu("plugin_tools")
77 if menu is not None: 78 if menu is not None:
78 if not menu.isEmpty(): 79 if not menu.isEmpty():
79 act = menu.addSeparator() 80 act = menu.addSeparator()
80 self.__mainActions.append(act) 81 self.__mainActions.append(act)
81 act = menu.addMenu(self.__menu) 82 act = menu.addMenu(self.__menu)
82 self.__mainActions.append(act) 83 self.__mainActions.append(act)
83 84
84 ericApp().getObject("ViewManager").editorOpenedEd.connect( 85 ericApp().getObject("ViewManager").editorOpenedEd.connect(self.__editorOpened)
85 self.__editorOpened) 86 ericApp().getObject("ViewManager").editorClosedEd.connect(self.__editorClosed)
86 ericApp().getObject("ViewManager").editorClosedEd.connect( 87
87 self.__editorClosed)
88
89 for editor in ericApp().getObject("ViewManager").getOpenEditors(): 88 for editor in ericApp().getObject("ViewManager").getOpenEditors():
90 self.__editorOpened(editor) 89 self.__editorOpened(editor)
91 90
92 return None, True 91 return None, True
93 92
94 def deactivate(self): 93 def deactivate(self):
95 """ 94 """
96 Public method to deactivate this plugin. 95 Public method to deactivate this plugin.
97 """ 96 """
98 self.__ui.showMenu.disconnect(self.__populateMenu) 97 self.__ui.showMenu.disconnect(self.__populateMenu)
99 98
100 menu = self.__ui.getMenu("plugin_tools") 99 menu = self.__ui.getMenu("plugin_tools")
101 if menu is not None: 100 if menu is not None:
102 for act in self.__mainActions: 101 for act in self.__mainActions:
103 menu.removeAction(act) 102 menu.removeAction(act)
104 self.__mainActions = [] 103 self.__mainActions = []
105 104
106 ericApp().getObject("ViewManager").editorOpenedEd.disconnect( 105 ericApp().getObject("ViewManager").editorOpenedEd.disconnect(
107 self.__editorOpened) 106 self.__editorOpened
107 )
108 ericApp().getObject("ViewManager").editorClosedEd.disconnect( 108 ericApp().getObject("ViewManager").editorClosedEd.disconnect(
109 self.__editorClosed) 109 self.__editorClosed
110 110 )
111
111 for editor, acts in self.__editors.items(): 112 for editor, acts in self.__editors.items():
112 editor.showMenu.disconnect(self.__editorShowMenu) 113 editor.showMenu.disconnect(self.__editorShowMenu)
113 menu = editor.getMenu("Tools") 114 menu = editor.getMenu("Tools")
114 if menu is not None: 115 if menu is not None:
115 for act in acts: 116 for act in acts:
116 menu.removeAction(act) 117 menu.removeAction(act)
117 self.__editors = {} 118 self.__editors = {}
118 119
119 def __loadTranslator(self): 120 def __loadTranslator(self):
120 """ 121 """
121 Private method to load the translation file. 122 Private method to load the translation file.
122 """ 123 """
123 if self.__ui is not None: 124 if self.__ui is not None:
124 loc = self.__ui.getLocale() 125 loc = self.__ui.getLocale()
125 if loc and loc != "C": 126 if loc and loc != "C":
126 locale_dir = os.path.join( 127 locale_dir = os.path.join(
127 os.path.dirname(__file__), "ColorString", "i18n") 128 os.path.dirname(__file__), "ColorString", "i18n"
129 )
128 translation = "colorstring_{0}".format(loc) 130 translation = "colorstring_{0}".format(loc)
129 translator = QTranslator(None) 131 translator = QTranslator(None)
130 loaded = translator.load(translation, locale_dir) 132 loaded = translator.load(translation, locale_dir)
131 if loaded: 133 if loaded:
132 self.__translator = translator 134 self.__translator = translator
133 ericApp().installTranslator(self.__translator) 135 ericApp().installTranslator(self.__translator)
134 else: 136 else:
135 print("Warning: translation file '{0}' could not be" 137 print(
136 " loaded.".format(translation)) 138 "Warning: translation file '{0}' could not be"
139 " loaded.".format(translation)
140 )
137 print("Using default.") 141 print("Using default.")
138 142
139 def __initMenu(self): 143 def __initMenu(self):
140 """ 144 """
141 Private method to initialize the menu. 145 Private method to initialize the menu.
142 """ 146 """
143 self.__menu = QMenu(self.tr("Color String")) 147 self.__menu = QMenu(self.tr("Color String"))
144 self.__menu.addAction(self.tr("Hex Color"), self.__selectHexColor) 148 self.__menu.addAction(self.tr("Hex Color"), self.__selectHexColor)
145 self.__menu.addAction(self.tr("Color Name"), self.__selectColorName) 149 self.__menu.addAction(self.tr("Color Name"), self.__selectColorName)
146 self.__menu.addAction(self.tr("RGBA Color"), self.__selectRgbaColor) 150 self.__menu.addAction(self.tr("RGBA Color"), self.__selectRgbaColor)
147 self.__menu.setEnabled(False) 151 self.__menu.setEnabled(False)
148 152
149 def __populateMenu(self, name, menu): 153 def __populateMenu(self, name, menu):
150 """ 154 """
151 Private slot to populate the tools menu with our entry. 155 Private slot to populate the tools menu with our entry.
152 156
153 @param name name of the menu 157 @param name name of the menu
154 @type str 158 @type str
155 @param menu reference to the menu to be populated 159 @param menu reference to the menu to be populated
156 @type QMenu 160 @type QMenu
157 """ 161 """
158 if name not in ["Tools", "PluginTools"]: 162 if name not in ["Tools", "PluginTools"]:
159 return 163 return
160 164
161 editor = ericApp().getObject("ViewManager").activeWindow() 165 editor = ericApp().getObject("ViewManager").activeWindow()
162 166
163 if name == "Tools": 167 if name == "Tools":
164 if not menu.isEmpty(): 168 if not menu.isEmpty():
165 menu.addSeparator() 169 menu.addSeparator()
166 act = menu.addMenu(self.__menu) 170 act = menu.addMenu(self.__menu)
167 act.setEnabled(editor is not None) 171 act.setEnabled(editor is not None)
168 elif name == "PluginTools" and self.__mainActions: 172 elif name == "PluginTools" and self.__mainActions:
169 self.__mainActions[-1].setEnabled(editor is not None) 173 self.__mainActions[-1].setEnabled(editor is not None)
170 174
171 def __editorOpened(self, editor): 175 def __editorOpened(self, editor):
172 """ 176 """
173 Private slot called, when a new editor was opened. 177 Private slot called, when a new editor was opened.
174 178
175 @param editor reference to the new editor 179 @param editor reference to the new editor
176 @type Editor 180 @type Editor
177 """ 181 """
178 menu = editor.getMenu("Tools") 182 menu = editor.getMenu("Tools")
179 if menu is not None: 183 if menu is not None:
183 self.__editors[editor].append(act) 187 self.__editors[editor].append(act)
184 act = menu.addMenu(self.__menu) 188 act = menu.addMenu(self.__menu)
185 self.__menu.setEnabled(True) 189 self.__menu.setEnabled(True)
186 self.__editors[editor].append(act) 190 self.__editors[editor].append(act)
187 editor.showMenu.connect(self.__editorShowMenu) 191 editor.showMenu.connect(self.__editorShowMenu)
188 192
189 def __editorClosed(self, editor): 193 def __editorClosed(self, editor):
190 """ 194 """
191 Private slot called, when an editor was closed. 195 Private slot called, when an editor was closed.
192 196
193 @param editor reference to the editor 197 @param editor reference to the editor
194 @type Editor 198 @type Editor
195 """ 199 """
196 with contextlib.suppress(KeyError): 200 with contextlib.suppress(KeyError):
197 del self.__editors[editor] 201 del self.__editors[editor]
198 if not self.__editors: 202 if not self.__editors:
199 self.__menu.setEnabled(False) 203 self.__menu.setEnabled(False)
200 204
201 def __editorShowMenu(self, menuName, menu, editor): 205 def __editorShowMenu(self, menuName, menu, editor):
202 """ 206 """
203 Private slot called, when the the editor context menu or a submenu is 207 Private slot called, when the the editor context menu or a submenu is
204 about to be shown. 208 about to be shown.
205 209
206 @param menuName name of the menu to be shown 210 @param menuName name of the menu to be shown
207 @type str 211 @type str
208 @param menu reference to the menu 212 @param menu reference to the menu
209 @type QMenu 213 @type QMenu
210 @param editor reference to the editor 214 @param editor reference to the editor
211 @type Editor 215 @type Editor
212 """ 216 """
213 if ( 217 if menuName == "Tools" and self.__menu.menuAction() not in menu.actions():
214 menuName == "Tools" and
215 self.__menu.menuAction() not in menu.actions()
216 ):
217 # Re-add our menu 218 # Re-add our menu
218 self.__editors[editor] = [] 219 self.__editors[editor] = []
219 if not menu.isEmpty(): 220 if not menu.isEmpty():
220 act = menu.addSeparator() 221 act = menu.addSeparator()
221 self.__editors[editor].append(act) 222 self.__editors[editor].append(act)
222 act = menu.addMenu(self.__menu) 223 act = menu.addMenu(self.__menu)
223 self.__editors[editor].append(act) 224 self.__editors[editor].append(act)
224 225
225 def __isHexString(self, text): 226 def __isHexString(self, text):
226 """ 227 """
227 Private method to check, if a given text is a hex string. 228 Private method to check, if a given text is a hex string.
228 229
229 @param text text to check 230 @param text text to check
230 @type str 231 @type str
231 @return flag indicating a hex string 232 @return flag indicating a hex string
232 @rtype bool 233 @rtype bool
233 """ 234 """
234 return all(c in "0123456789abcdefABCDEF" for c in text) 235 return all(c in "0123456789abcdefABCDEF" for c in text)
235 236
236 def __isValidColor(self, name): 237 def __isValidColor(self, name):
237 """ 238 """
238 Private method to check for a valid color name. 239 Private method to check for a valid color name.
239 240
240 @param name color name to check 241 @param name color name to check
241 @type str 242 @type str
242 @return flag indicating a valid color name 243 @return flag indicating a valid color name
243 @rtype bool 244 @rtype bool
244 """ 245 """
245 if self.__isHexString(name) and len(name) in (3, 6, 8, 9, 12): 246 if self.__isHexString(name) and len(name) in (3, 6, 8, 9, 12):
246 return True 247 return True
247 return QColor.isValidColor(name) 248 return QColor.isValidColor(name)
248 249
249 def __selectHexColor(self): 250 def __selectHexColor(self):
250 """ 251 """
251 Private slot implementing the hex color string selection. 252 Private slot implementing the hex color string selection.
252 """ 253 """
253 editor = ericApp().getObject("ViewManager").activeWindow() 254 editor = ericApp().getObject("ViewManager").activeWindow()
254 if editor is None: 255 if editor is None:
255 return 256 return
256 257
257 if editor.hasSelectedText(): 258 if editor.hasSelectedText():
258 currColor = editor.selectedText() 259 currColor = editor.selectedText()
259 if not self.__isValidColor(currColor): 260 if not self.__isValidColor(currColor):
260 EricMessageBox.critical( 261 EricMessageBox.critical(
261 self.__ui, 262 self.__ui,
262 self.tr("Color String"), 263 self.tr("Color String"),
263 self.tr( 264 self.tr(
264 """<p>The selected string <b>{0}</b> is not a""" 265 """<p>The selected string <b>{0}</b> is not a"""
265 """ valid color string. Aborting!</p>""") 266 """ valid color string. Aborting!</p>"""
266 .format(currColor)) 267 ).format(currColor),
268 )
267 return 269 return
268 270
269 if currColor.startswith("#"): 271 if currColor.startswith("#"):
270 withHash = True 272 withHash = True
271 elif self.__isHexString(currColor): 273 elif self.__isHexString(currColor):
272 withHash = False 274 withHash = False
273 currColor = "#" + currColor 275 currColor = "#" + currColor
276 initColor = QColor(currColor) 278 initColor = QColor(currColor)
277 else: 279 else:
278 withHash = True 280 withHash = True
279 currColor = "" 281 currColor = ""
280 initColor = QColor() 282 initColor = QColor()
281 283
282 color = QColorDialog.getColor( 284 color = QColorDialog.getColor(
283 initColor, self.__ui, self.tr("Color String"), 285 initColor,
284 QColorDialog.ColorDialogOption.ShowAlphaChannel) 286 self.__ui,
287 self.tr("Color String"),
288 QColorDialog.ColorDialogOption.ShowAlphaChannel,
289 )
285 if color.isValid(): 290 if color.isValid():
286 if color.alpha() == 255: 291 if color.alpha() == 255:
287 nameFormat = QColor.NameFormat.HexRgb 292 nameFormat = QColor.NameFormat.HexRgb
288 else: 293 else:
289 nameFormat = QColor.NameFormat.HexArgb 294 nameFormat = QColor.NameFormat.HexArgb
296 else: 301 else:
297 line, index = editor.getCursorPosition() 302 line, index = editor.getCursorPosition()
298 editor.insert(colorStr) 303 editor.insert(colorStr)
299 editor.setCursorPosition(line, index + len(colorStr)) 304 editor.setCursorPosition(line, index + len(colorStr))
300 editor.endUndoAction() 305 editor.endUndoAction()
301 306
302 def __selectColorName(self): 307 def __selectColorName(self):
303 """ 308 """
304 Private slot implementing the named color string selection. 309 Private slot implementing the named color string selection.
305 """ 310 """
306 editor = ericApp().getObject("ViewManager").activeWindow() 311 editor = ericApp().getObject("ViewManager").activeWindow()
307 if editor is None: 312 if editor is None:
308 return 313 return
309 314
310 if editor.hasSelectedText(): 315 if editor.hasSelectedText():
311 currColor = editor.selectedText() 316 currColor = editor.selectedText()
312 if currColor not in QColor.colorNames(): 317 if currColor not in QColor.colorNames():
313 EricMessageBox.critical( 318 EricMessageBox.critical(
314 self.__ui, 319 self.__ui,
315 self.tr("Color String"), 320 self.tr("Color String"),
316 self.tr( 321 self.tr(
317 """<p>The selected string <b>{0}</b> is not a""" 322 """<p>The selected string <b>{0}</b> is not a"""
318 """ valid color name. Aborting!</p>""") 323 """ valid color name. Aborting!</p>"""
319 .format(currColor)) 324 ).format(currColor),
325 )
320 return 326 return
321 else: 327 else:
322 currColor = "" 328 currColor = ""
323 329
324 from ColorString.ColorSelectionDialog import ColorSelectionDialog 330 from ColorString.ColorSelectionDialog import ColorSelectionDialog
331
325 dlg = ColorSelectionDialog(currColor, self.__ui) 332 dlg = ColorSelectionDialog(currColor, self.__ui)
326 if dlg.exec() == QDialog.DialogCode.Accepted: 333 if dlg.exec() == QDialog.DialogCode.Accepted:
327 colorStr = dlg.getColor() 334 colorStr = dlg.getColor()
328 editor.beginUndoAction() 335 editor.beginUndoAction()
329 if editor.hasSelectedText(): 336 if editor.hasSelectedText():
331 else: 338 else:
332 line, index = editor.getCursorPosition() 339 line, index = editor.getCursorPosition()
333 editor.insert(colorStr) 340 editor.insert(colorStr)
334 editor.setCursorPosition(line, index + len(colorStr)) 341 editor.setCursorPosition(line, index + len(colorStr))
335 editor.endUndoAction() 342 editor.endUndoAction()
336 343
337 def __selectRgbaColor(self): 344 def __selectRgbaColor(self):
338 """ 345 """
339 Private slot implementing the RGBA color string selection. 346 Private slot implementing the RGBA color string selection.
340 """ 347 """
341 editor = ericApp().getObject("ViewManager").activeWindow() 348 editor = ericApp().getObject("ViewManager").activeWindow()
342 if editor is None: 349 if editor is None:
343 return 350 return
344 351
345 if editor.hasSelectedText(): 352 if editor.hasSelectedText():
346 currColor = editor.selectedText() 353 currColor = editor.selectedText()
347 valid, rgba = self.__isValidRgbaColor(currColor) 354 valid, rgba = self.__isValidRgbaColor(currColor)
348 if not valid: 355 if not valid:
349 EricMessageBox.critical( 356 EricMessageBox.critical(
350 self.__ui, 357 self.__ui,
351 self.tr("Color String"), 358 self.tr("Color String"),
352 self.tr( 359 self.tr(
353 """<p>The selected string <b>{0}</b> is not a""" 360 """<p>The selected string <b>{0}</b> is not a"""
354 """ valid RGBA color string. Aborting!</p>""") 361 """ valid RGBA color string. Aborting!</p>"""
355 .format(currColor)) 362 ).format(currColor),
363 )
356 return 364 return
357 initColor = QColor(*rgba) 365 initColor = QColor(*rgba)
358 else: 366 else:
359 initColor = QColor() 367 initColor = QColor()
360 368
361 color = QColorDialog.getColor( 369 color = QColorDialog.getColor(
362 initColor, self.__ui, self.tr("Color String"), 370 initColor,
363 QColorDialog.ColorDialogOption.ShowAlphaChannel) 371 self.__ui,
372 self.tr("Color String"),
373 QColorDialog.ColorDialogOption.ShowAlphaChannel,
374 )
364 if color.isValid(): 375 if color.isValid():
365 rgba = color.getRgb() 376 rgba = color.getRgb()
366 if rgba[-1] == 255: 377 if rgba[-1] == 255:
367 colorStr = "{0}, {1}, {2}".format(*rgba[:-1]) 378 colorStr = "{0}, {1}, {2}".format(*rgba[:-1])
368 else: 379 else:
373 else: 384 else:
374 line, index = editor.getCursorPosition() 385 line, index = editor.getCursorPosition()
375 editor.insert(colorStr) 386 editor.insert(colorStr)
376 editor.setCursorPosition(line, index + len(colorStr)) 387 editor.setCursorPosition(line, index + len(colorStr))
377 editor.endUndoAction() 388 editor.endUndoAction()
378 389
379 def __isValidRgbaColor(self, color): 390 def __isValidRgbaColor(self, color):
380 """ 391 """
381 Private method to check for a valid RGBA color. 392 Private method to check for a valid RGBA color.
382 393
383 @param color color string to check 394 @param color color string to check
384 @type str 395 @type str
385 @return flag indicating a valid RGBA color (boolean) and a list with 396 @return flag indicating a valid RGBA color (boolean) and a list with
386 the RGBA components of the color (three or four integers) 397 the RGBA components of the color (three or four integers)
387 @rtype tuple of (bool, [int, int, int]) or (bool, [int, int, int, int]) 398 @rtype tuple of (bool, [int, int, int]) or (bool, [int, int, int, int])
388 """ 399 """
389 rgba = [] 400 rgba = []
390 401
391 parts = color.split(",") 402 parts = color.split(",")
392 if len(parts) not in [3, 4]: 403 if len(parts) not in [3, 4]:
393 return False, [] 404 return False, []
394 405
395 for part in parts: 406 for part in parts:
396 try: 407 try:
397 c = int(float(part)) if "." in part else int(part) 408 c = int(float(part)) if "." in part else int(part)
398 except ValueError: 409 except ValueError:
399 return False, [] 410 return False, []
400 411
401 if c < 0 or c > 255: 412 if c < 0 or c > 255:
402 return False, [] 413 return False, []
403 414
404 rgba.append(c) 415 rgba.append(c)
405 416
406 return True, rgba 417 return True, rgba
418
407 419
408 # 420 #
409 # eflag: noqa = M801 421 # eflag: noqa = M801

eric ide

mercurial