PluginColorString.py

branch
eric7
changeset 48
e35a2acef5b8
parent 45
1ba3620cae56
child 51
c02cbedf626d
equal deleted inserted replaced
47:ea50152ee631 48:e35a2acef5b8
8 """ 8 """
9 9
10 import contextlib 10 import contextlib
11 import os 11 import os
12 12
13 from PyQt5.QtCore import QObject, QTranslator 13 from PyQt6.QtCore import QObject, QTranslator
14 from PyQt5.QtGui import QColor 14 from PyQt6.QtGui import QColor
15 from PyQt5.QtWidgets import QColorDialog, QMenu, QDialog 15 from PyQt6.QtWidgets import QColorDialog, QMenu, QDialog
16 16
17 from E5Gui.E5Application import e5App 17 from EricWidgets.EricApplication import ericApp
18 from E5Gui import E5MessageBox 18 from EricWidgets import EricMessageBox
19 19
20 # Start-Of-Header 20 # Start-Of-Header
21 name = "Color String Plug-in" 21 name = "Color String Plug-in"
22 author = "Detlev Offenbach <detlev@die-offenbachs.de>" 22 author = "Detlev Offenbach <detlev@die-offenbachs.de>"
23 autoactivate = True 23 autoactivate = True
24 deactivateable = True 24 deactivateable = True
25 version = "3.2.0" 25 version = "1.0.0"
26 className = "ColorStringPlugin" 26 className = "ColorStringPlugin"
27 packageName = "ColorString" 27 packageName = "ColorString"
28 shortDescription = "Insert color as string" 28 shortDescription = "Insert color as string"
29 longDescription = ( 29 longDescription = (
30 """This plug-in implements a tool to select a color via a""" 30 """This plug-in implements a tool to select a color via a"""
45 """ 45 """
46 def __init__(self, ui): 46 def __init__(self, ui):
47 """ 47 """
48 Constructor 48 Constructor
49 49
50 @param ui reference to the user interface object (UI.UserInterface) 50 @param ui reference to the user interface object
51 @type UserInterface
51 """ 52 """
52 super().__init__(ui) 53 super().__init__(ui)
53 self.__ui = ui 54 self.__ui = ui
54 55
55 self.__translator = None 56 self.__translator = None
62 63
63 def activate(self): 64 def activate(self):
64 """ 65 """
65 Public method to activate this plugin. 66 Public method to activate this plugin.
66 67
67 @return tuple of None and activation status (boolean) 68 @return tuple of None and activation status
69 @rtype tuple of (None, bool)
68 """ 70 """
69 global error 71 global error
70 error = "" # clear previous error 72 error = "" # clear previous error
71 73
72 self.__ui.showMenu.connect(self.__populateMenu) 74 self.__ui.showMenu.connect(self.__populateMenu)
77 act = menu.addSeparator() 79 act = menu.addSeparator()
78 self.__mainActions.append(act) 80 self.__mainActions.append(act)
79 act = menu.addMenu(self.__menu) 81 act = menu.addMenu(self.__menu)
80 self.__mainActions.append(act) 82 self.__mainActions.append(act)
81 83
82 e5App().getObject("ViewManager").editorOpenedEd.connect( 84 ericApp().getObject("ViewManager").editorOpenedEd.connect(
83 self.__editorOpened) 85 self.__editorOpened)
84 e5App().getObject("ViewManager").editorClosedEd.connect( 86 ericApp().getObject("ViewManager").editorClosedEd.connect(
85 self.__editorClosed) 87 self.__editorClosed)
86 88
87 for editor in e5App().getObject("ViewManager").getOpenEditors(): 89 for editor in ericApp().getObject("ViewManager").getOpenEditors():
88 self.__editorOpened(editor) 90 self.__editorOpened(editor)
89 91
90 return None, True 92 return None, True
91 93
92 def deactivate(self): 94 def deactivate(self):
99 if menu is not None: 101 if menu is not None:
100 for act in self.__mainActions: 102 for act in self.__mainActions:
101 menu.removeAction(act) 103 menu.removeAction(act)
102 self.__mainActions = [] 104 self.__mainActions = []
103 105
104 e5App().getObject("ViewManager").editorOpenedEd.disconnect( 106 ericApp().getObject("ViewManager").editorOpenedEd.disconnect(
105 self.__editorOpened) 107 self.__editorOpened)
106 e5App().getObject("ViewManager").editorClosedEd.disconnect( 108 ericApp().getObject("ViewManager").editorClosedEd.disconnect(
107 self.__editorClosed) 109 self.__editorClosed)
108 110
109 for editor, acts in self.__editors.items(): 111 for editor, acts in self.__editors.items():
110 editor.showMenu.disconnect(self.__editorShowMenu) 112 editor.showMenu.disconnect(self.__editorShowMenu)
111 menu = editor.getMenu("Tools") 113 menu = editor.getMenu("Tools")
126 translation = "colorstring_{0}".format(loc) 128 translation = "colorstring_{0}".format(loc)
127 translator = QTranslator(None) 129 translator = QTranslator(None)
128 loaded = translator.load(translation, locale_dir) 130 loaded = translator.load(translation, locale_dir)
129 if loaded: 131 if loaded:
130 self.__translator = translator 132 self.__translator = translator
131 e5App().installTranslator(self.__translator) 133 ericApp().installTranslator(self.__translator)
132 else: 134 else:
133 print("Warning: translation file '{0}' could not be" 135 print("Warning: translation file '{0}' could not be"
134 " loaded.".format(translation)) 136 " loaded.".format(translation))
135 print("Using default.") 137 print("Using default.")
136 138
146 148
147 def __populateMenu(self, name, menu): 149 def __populateMenu(self, name, menu):
148 """ 150 """
149 Private slot to populate the tools menu with our entry. 151 Private slot to populate the tools menu with our entry.
150 152
151 @param name name of the menu (string) 153 @param name name of the menu
152 @param menu reference to the menu to be populated (QMenu) 154 @type str
155 @param menu reference to the menu to be populated
156 @type QMenu
153 """ 157 """
154 if name not in ["Tools", "PluginTools"]: 158 if name not in ["Tools", "PluginTools"]:
155 return 159 return
156 160
157 editor = e5App().getObject("ViewManager").activeWindow() 161 editor = ericApp().getObject("ViewManager").activeWindow()
158 162
159 if name == "Tools": 163 if name == "Tools":
160 if not menu.isEmpty(): 164 if not menu.isEmpty():
161 menu.addSeparator() 165 menu.addSeparator()
162 act = menu.addMenu(self.__menu) 166 act = menu.addMenu(self.__menu)
166 170
167 def __editorOpened(self, editor): 171 def __editorOpened(self, editor):
168 """ 172 """
169 Private slot called, when a new editor was opened. 173 Private slot called, when a new editor was opened.
170 174
171 @param editor reference to the new editor (QScintilla.Editor) 175 @param editor reference to the new editor
176 @type Editor
172 """ 177 """
173 menu = editor.getMenu("Tools") 178 menu = editor.getMenu("Tools")
174 if menu is not None: 179 if menu is not None:
175 self.__editors[editor] = [] 180 self.__editors[editor] = []
176 if not menu.isEmpty(): 181 if not menu.isEmpty():
183 188
184 def __editorClosed(self, editor): 189 def __editorClosed(self, editor):
185 """ 190 """
186 Private slot called, when an editor was closed. 191 Private slot called, when an editor was closed.
187 192
188 @param editor reference to the editor (QScintilla.Editor) 193 @param editor reference to the editor
194 @type Editor
189 """ 195 """
190 with contextlib.suppress(KeyError): 196 with contextlib.suppress(KeyError):
191 del self.__editors[editor] 197 del self.__editors[editor]
192 if not self.__editors: 198 if not self.__editors:
193 self.__menu.setEnabled(False) 199 self.__menu.setEnabled(False)
195 def __editorShowMenu(self, menuName, menu, editor): 201 def __editorShowMenu(self, menuName, menu, editor):
196 """ 202 """
197 Private slot called, when the the editor context menu or a submenu is 203 Private slot called, when the the editor context menu or a submenu is
198 about to be shown. 204 about to be shown.
199 205
200 @param menuName name of the menu to be shown (string) 206 @param menuName name of the menu to be shown
201 @param menu reference to the menu (QMenu) 207 @type str
208 @param menu reference to the menu
209 @type QMenu
202 @param editor reference to the editor 210 @param editor reference to the editor
211 @type Editor
203 """ 212 """
204 if ( 213 if (
205 menuName == "Tools" and 214 menuName == "Tools" and
206 self.__menu.menuAction() not in menu.actions() 215 self.__menu.menuAction() not in menu.actions()
207 ): 216 ):
215 224
216 def __isHexString(self, text): 225 def __isHexString(self, text):
217 """ 226 """
218 Private method to check, if a given text is a hex string. 227 Private method to check, if a given text is a hex string.
219 228
220 @param text text to check (string) 229 @param text text to check
221 @return flag indicating a hex string (boolean) 230 @type str
222 """ 231 @return flag indicating a hex string
223 return all(map(lambda c: c in "0123456789abcdefABCDEF", text)) 232 @rtype bool
233 """
234 return all(c in "0123456789abcdefABCDEF" for c in text)
224 235
225 def __isValidColor(self, name): 236 def __isValidColor(self, name):
226 """ 237 """
227 Private method to check for a valid color name. 238 Private method to check for a valid color name.
228 239
229 @param name color name to check (string) 240 @param name color name to check
230 @return flag indicating a valid color name (boolean) 241 @type str
231 """ 242 @return flag indicating a valid color name
232 try: 243 @rtype bool
233 if self.__isHexString(name) and len(name) in [3, 6, 9, 12]: 244 """
234 return True 245 if self.__isHexString(name) and len(name) in (3, 6, 8, 9, 12):
235 return QColor.isValidColor(name) 246 return True
236 except AttributeError: 247 return QColor.isValidColor(name)
237 if name.startswith("#"):
238 if len(name) not in [4, 7, 10, 13]:
239 return False
240 hexCheckStr = name[1:]
241 return self.__isHexString(hexCheckStr)
242 else:
243 if self.__isHexString(name) and len(name) in [3, 6, 9, 12]:
244 return True
245 return name in QColor.colorNames()
246 248
247 def __selectHexColor(self): 249 def __selectHexColor(self):
248 """ 250 """
249 Private slot implementing the hex color string selection. 251 Private slot implementing the hex color string selection.
250 """ 252 """
251 editor = e5App().getObject("ViewManager").activeWindow() 253 editor = ericApp().getObject("ViewManager").activeWindow()
252 if editor is None: 254 if editor is None:
253 return 255 return
254 256
255 if editor.hasSelectedText(): 257 if editor.hasSelectedText():
256 currColor = editor.selectedText() 258 currColor = editor.selectedText()
257 if not self.__isValidColor(currColor): 259 if not self.__isValidColor(currColor):
258 E5MessageBox.critical( 260 EricMessageBox.critical(
259 self.__ui, 261 self.__ui,
260 self.tr("Color String"), 262 self.tr("Color String"),
261 self.tr( 263 self.tr(
262 """<p>The selected string <b>{0}</b> is not a""" 264 """<p>The selected string <b>{0}</b> is not a"""
263 """ valid color string. Aborting!</p>""") 265 """ valid color string. Aborting!</p>""")
276 withHash = True 278 withHash = True
277 currColor = "" 279 currColor = ""
278 initColor = QColor() 280 initColor = QColor()
279 281
280 color = QColorDialog.getColor( 282 color = QColorDialog.getColor(
281 initColor, self.__ui, self.tr("Color String")) 283 initColor, self.__ui, self.tr("Color String"),
284 QColorDialog.ColorDialogOption.ShowAlphaChannel)
282 if color.isValid(): 285 if color.isValid():
283 colorStr = color.name() 286 if color.alpha() == 255:
287 nameFormat = QColor.NameFormat.HexRgb
288 else:
289 nameFormat = QColor.NameFormat.HexArgb
290 colorStr = color.name(nameFormat)
284 if not withHash: 291 if not withHash:
285 colorStr = colorStr[1:] 292 colorStr = colorStr[1:]
286 editor.beginUndoAction() 293 editor.beginUndoAction()
287 if editor.hasSelectedText(): 294 if editor.hasSelectedText():
288 editor.replaceSelectedText(colorStr) 295 editor.replaceSelectedText(colorStr)
294 301
295 def __selectColorName(self): 302 def __selectColorName(self):
296 """ 303 """
297 Private slot implementing the named color string selection. 304 Private slot implementing the named color string selection.
298 """ 305 """
299 editor = e5App().getObject("ViewManager").activeWindow() 306 editor = ericApp().getObject("ViewManager").activeWindow()
300 if editor is None: 307 if editor is None:
301 return 308 return
302 309
303 if editor.hasSelectedText(): 310 if editor.hasSelectedText():
304 currColor = editor.selectedText() 311 currColor = editor.selectedText()
305 if currColor not in QColor.colorNames(): 312 if currColor not in QColor.colorNames():
306 E5MessageBox.critical( 313 EricMessageBox.critical(
307 self.__ui, 314 self.__ui,
308 self.tr("Color String"), 315 self.tr("Color String"),
309 self.tr( 316 self.tr(
310 """<p>The selected string <b>{0}</b> is not a""" 317 """<p>The selected string <b>{0}</b> is not a"""
311 """ valid color name. Aborting!</p>""") 318 """ valid color name. Aborting!</p>""")
314 else: 321 else:
315 currColor = "" 322 currColor = ""
316 323
317 from ColorString.ColorSelectionDialog import ColorSelectionDialog 324 from ColorString.ColorSelectionDialog import ColorSelectionDialog
318 dlg = ColorSelectionDialog(currColor, self.__ui) 325 dlg = ColorSelectionDialog(currColor, self.__ui)
319 if dlg.exec() == QDialog.Accepted: 326 if dlg.exec() == QDialog.DialogCode.Accepted:
320 colorStr = dlg.getColor() 327 colorStr = dlg.getColor()
321 editor.beginUndoAction() 328 editor.beginUndoAction()
322 if editor.hasSelectedText(): 329 if editor.hasSelectedText():
323 editor.replaceSelectedText(colorStr) 330 editor.replaceSelectedText(colorStr)
324 else: 331 else:
329 336
330 def __selectRgbaColor(self): 337 def __selectRgbaColor(self):
331 """ 338 """
332 Private slot implementing the RGBA color string selection. 339 Private slot implementing the RGBA color string selection.
333 """ 340 """
334 editor = e5App().getObject("ViewManager").activeWindow() 341 editor = ericApp().getObject("ViewManager").activeWindow()
335 if editor is None: 342 if editor is None:
336 return 343 return
337 344
338 if editor.hasSelectedText(): 345 if editor.hasSelectedText():
339 currColor = editor.selectedText() 346 currColor = editor.selectedText()
340 valid, rgba = self.__isValidRgbaColor(currColor) 347 valid, rgba = self.__isValidRgbaColor(currColor)
341 if not valid: 348 if not valid:
342 E5MessageBox.critical( 349 EricMessageBox.critical(
343 self.__ui, 350 self.__ui,
344 self.tr("Color String"), 351 self.tr("Color String"),
345 self.tr( 352 self.tr(
346 """<p>The selected string <b>{0}</b> is not a""" 353 """<p>The selected string <b>{0}</b> is not a"""
347 """ valid color string. Aborting!</p>""") 354 """ valid RGBA color string. Aborting!</p>""")
348 .format(currColor)) 355 .format(currColor))
349 return 356 return
350 initColor = QColor(*rgba) 357 initColor = QColor(*rgba)
351 else: 358 else:
352 initColor = QColor() 359 initColor = QColor()
353 360
354 color = QColorDialog.getColor( 361 color = QColorDialog.getColor(
355 initColor, self.__ui, self.tr("Color String"), 362 initColor, self.__ui, self.tr("Color String"),
356 QColorDialog.ShowAlphaChannel) 363 QColorDialog.ColorDialogOption.ShowAlphaChannel)
357 if color.isValid(): 364 if color.isValid():
358 rgba = color.getRgb() 365 rgba = color.getRgb()
359 if rgba[-1] == 255: 366 if rgba[-1] == 255:
360 colorStr = "{0}, {1}, {2}".format(*rgba[:-1]) 367 colorStr = "{0}, {1}, {2}".format(*rgba[:-1])
361 else: 368 else:
371 378
372 def __isValidRgbaColor(self, color): 379 def __isValidRgbaColor(self, color):
373 """ 380 """
374 Private method to check for a valid RGBA color. 381 Private method to check for a valid RGBA color.
375 382
376 @param color color string to check (string) 383 @param color color string to check
384 @type str
377 @return flag indicating a valid RGBA color (boolean) and a list with 385 @return flag indicating a valid RGBA color (boolean) and a list with
378 the RGBA components of the color (three or four integers) 386 the RGBA components of the color (three or four integers)
387 @rtype tuple of (bool, [int, int, int]) or (bool, [int, int, int, int])
379 """ 388 """
380 rgba = [] 389 rgba = []
381 390
382 parts = color.split(",") 391 parts = color.split(",")
383 if len(parts) not in [3, 4]: 392 if len(parts) not in [3, 4]:

eric ide

mercurial