E5Gui/E5ToolBarManager.py

changeset 55
b5c84934de9c
child 410
e5d1addeb90c
child 792
a13346916170
equal deleted inserted replaced
54:31463df17fd5 55:b5c84934de9c
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2008 - 2010 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing a toolbar manager class.
8 """
9
10 from PyQt4.QtCore import *
11 from PyQt4.QtGui import *
12
13 class E5ToolBarManager(QObject):
14 """
15 Class implementing a toolbar manager.
16 """
17 VersionMarker = 0xffff
18 ToolBarMarker = 0xfefe
19 CustomToolBarMarker = 0xfdfd
20
21 def __init__(self, ui = None, parent = None):
22 """
23 Constructor
24
25 @param ui reference to the user interface object (UI.UserInterface)
26 @param parent reference to the parent object (QObject)
27 """
28 QObject.__init__(self, parent)
29
30 self.__mainWindow = None
31 self.__ui = ui
32
33 self.__toolBars = {} # maps toolbar IDs to actions
34 self.__toolBarsWithSeparators = {} # maps toolbar IDs to actions incl. separators
35 self.__defaultToolBars = {} # maps default toolbar IDs to actions
36 self.__customToolBars = [] # list of custom toolbars
37 self.__allToolBars = {} # maps toolbar IDs to toolbars
38
39 self.__categoryToActions = {} # maps categories to actions
40 self.__actionToCategory = {} # maps action IDs to categories
41 self.__allActions = {} # maps action IDs to actions
42 self.__actionToToolBars = {} # maps action IDs to toolbars
43
44 self.__widgetActions = {} # maps widget action IDs to toolbars
45 self.__allWidgetActions = {} # maps widget action IDs to widget actions
46
47 ######################################################
48 ## Private methods
49 ######################################################
50
51 def __toolBarByName(self, name):
52 """
53 Private slot to get a toolbar by it's object name.
54
55 @param name object name of the toolbar (string)
56 @return reference to the toolbar (QToolBar)
57 """
58 for toolBar in list(self.__allToolBars.values()):
59 if toolBar.objectName() == name:
60 return toolBar
61 return None
62
63 def __findAction(self, name):
64 """
65 Private method to find an action by name.
66
67 @param name name of the action to search for (string)
68 @return reference to the action (QAction)
69 """
70 # check objectName() first
71 for action in list(self.__allActions.values()):
72 if action.objectName() == name:
73 return action
74
75 # check text() next
76 for action in list(self.__allActions.values()):
77 if action.text() == name:
78 return action
79
80 return None
81
82 def __findDefaultToolBar(self, name):
83 """
84 Private method to find a default toolbar by name.
85
86 @param name name of the default toolbar to search for (string)
87 @return reference to the default toolbar (QToolBar)
88 """
89 # check objectName() first
90 for tbID in self.__defaultToolBars:
91 tb = self.__allToolBars[tbID]
92 if tb.objectName() == name:
93 return tb
94
95 # check windowTitle() next
96 for tbID in self.__defaultToolBars:
97 tb = self.__allToolBars[tbID]
98 if tb.windowTitle() == name:
99 return tb
100
101 return None
102
103 ######################################################
104 ## Public methods
105 ######################################################
106
107 def setMainWindow(self, mainWindow):
108 """
109 Public method to set the reference to the main window.
110
111 @param mainWindow reference to the main window (QMainWindow)
112 """
113 self.__mainWindow = mainWindow
114
115 def mainWindow(self):
116 """
117 Public method to get the reference to the main window.
118
119 @return reference to the main window (QMainWindow)
120 """
121 return self.__mainWindow
122
123 def addToolBar(self, toolBar, category):
124 """
125 Public method to add a toolbar to be managed.
126
127 @param toolBar reference to the toolbar to be managed (QToolBar)
128 @param category category for the toolbar (string)
129 """
130 if toolBar is None:
131 return
132 if toolBar in self.__toolBars:
133 return
134
135 newActions = []
136 newActionsWithSeparators = []
137 actions = toolBar.actions()
138 for action in actions:
139 self.addAction(action, category)
140 if id(action) in self.__widgetActions:
141 self.__widgetActions[id(action)] = toolBar
142 newActionsWithSeparators.append(action)
143 if action.isSeparator():
144 action = None
145 else:
146 self.__actionToToolBars[id(action)].append(toolBar)
147 newActions.append(action)
148 tbID = id(toolBar)
149 self.__defaultToolBars[tbID] = newActions
150 self.__toolBars[tbID] = newActions
151 self.__toolBarsWithSeparators[tbID] = newActionsWithSeparators
152 self.__allToolBars[tbID] = toolBar
153
154 def removeToolBar(self, toolBar):
155 """
156 Public method to remove a toolbar added with addToolBar().
157
158 @param toolBar reference to the toolbar to be removed (QToolBar)
159 """
160 if toolBar is None:
161 return
162
163 tbID = id(toolBar)
164
165 if tbID not in self.__defaultToolBars:
166 return
167
168 defaultActions = self.__defaultToolBars[tbID][:]
169 self.setToolBar(toolBar, [])
170 for action in defaultActions:
171 self.removeAction(action)
172
173 del self.__defaultToolBars[tbID]
174 del self.__toolBars[tbID]
175 del self.__toolBarsWithSeparators[tbID]
176 del self.__allToolBars[tbID]
177
178 for action in defaultActions:
179 if action is None:
180 toolBar.addSeparator()
181 else:
182 toolBar.addAction(action)
183
184 def setToolBars(self, toolBars):
185 """
186 Public method to set the actions of several toolbars.
187
188 @param toolBars dictionary with toolbar id as key and
189 a list of actions as value
190 """
191 for key, actions in list(toolBars.items()):
192 tb = self.__allToolBars[key]
193 self.setToolBar(tb, actions)
194
195 def setToolBar(self, toolBar, actions):
196 """
197 Public method to set the actions of a toolbar.
198
199 @param toolBar reference to the toolbar to configure (QToolBar)
200 @param actions list of actions to be set (list of QAction)
201 """
202 if toolBar is None:
203 return
204
205 tbID = id(toolBar)
206 if tbID not in self.__toolBars:
207 return
208 if self.__toolBars[tbID] == actions:
209 return
210
211 # step 1: check list of actions
212 toRemove = {}
213 newActions = []
214 for action in actions:
215 if action is None or \
216 (action not in newActions and id(action) in self.__allActions):
217 newActions.append(action)
218 oldTB = self.toolBarWidgetAction(action)
219 if oldTB is not None and oldTB != toolBar:
220 if id(oldTB) not in toRemove:
221 toRemove[id(oldTB)] = []
222 toRemove[id(oldTB)].append(action)
223 self.removeWidgetActions(toRemove)
224
225 # step 2: remove all toolbar actions
226 for action in self.__toolBarsWithSeparators[tbID]:
227 if self.toolBarWidgetAction(action) == tbID:
228 self.__widgetActions[id(action)] = None
229 toolBar.removeAction(action)
230 if action.isSeparator():
231 del action
232 else:
233 self.__actionToToolBars[id(action)].remove(toolBar)
234
235 # step 3: set the actions as requested
236 newActionsWithSeparators = []
237 for action in newActions:
238 newAction = None
239 if action is None:
240 newAction = toolBar.addSeparator()
241 elif id(action) in self.__allActions:
242 toolBar.addAction(action)
243 newAction = action
244 self.__actionToToolBars[id(action)].append(toolBar)
245 if id(action) in self.__widgetActions:
246 self.__widgetActions[id(action)] = toolBar
247 else:
248 continue
249 newActionsWithSeparators.append(newAction)
250
251 if toolBar.isVisible():
252 toolBar.hide()
253 toolBar.show()
254 self.__toolBars[tbID] = newActions
255 self.__toolBarsWithSeparators[tbID] = newActionsWithSeparators
256
257 def resetToolBar(self, toolBar):
258 """
259 Public method to reset a toolbar to it's default state.
260
261 @param toolBar reference to the toolbar to configure (QToolBar)
262 """
263 if not isDefaultToolBar():
264 return
265 self.setToolBar(toolBar, self.__defaultToolBars[id(toolBar)])
266
267 def resetAllToolBars(self):
268 """
269 Public method to reset all toolbars to their default state.
270 """
271 self.setToolBars(self.__defaultToolBars)
272 for toolBar in self.__customToolBars[:]:
273 self.deleteToolBar(toolBar)
274
275 def defaultToolBars(self):
276 """
277 Public method to get all toolbars added with addToolBar().
278
279 @return list of all default toolbars (list of QToolBar)
280 """
281 return list(self.__defaultToolBars.values())
282
283 def isDefaultToolBar(self, toolBar):
284 """
285 Public method to check, if a toolbar was added with addToolBar().
286
287 @param toolBar reference to the toolbar to be checked (QToolBar)
288 """
289 return toolBar is not None and \
290 id(toolBar) in self.__defaultToolBars
291
292 def createToolBar(self, title):
293 """
294 Public method to create a custom toolbar.
295
296 @param title title to be used for the toolbar (string)
297 @return reference to the created toolbar (QToolBar)
298 """
299 if self.__mainWindow is None:
300 return None
301
302 toolBar = QToolBar(title, self.__mainWindow)
303 toolBar.setToolTip(title)
304 index = 1
305 customPrefix = "__CustomPrefix__"
306 name = "%s%d" % (customPrefix, index)
307 while self.__toolBarByName(name) is not None:
308 index += 1
309 name = "%s%d" % (customPrefix, index)
310 toolBar.setObjectName(name)
311 self.__mainWindow.addToolBar(toolBar)
312
313 tbID = id(toolBar)
314 self.__customToolBars.append(toolBar)
315 self.__allToolBars[tbID] = toolBar
316 self.__toolBars[tbID] = []
317 self.__toolBarsWithSeparators[tbID] = []
318
319 if self.__ui is not None:
320 toolBar.setIconSize(self.__ui.getToolBarIconSize())
321 self.__ui.registerToolbar(name, title, toolBar)
322
323 return toolBar
324
325 def deleteToolBar(self, toolBar):
326 """
327 Public method to remove a custom toolbar created with createToolBar().
328
329 @param toolBar reference to the toolbar to be managed (QToolBar)
330 """
331 if toolBar is None:
332 return
333
334 tbID = id(toolBar)
335 if tbID not in self.__toolBars:
336 return
337 if tbID in self.__defaultToolBars:
338 return
339
340 if self.__ui is not None:
341 self.__ui.unregisterToolbar(toolBar.objectName())
342
343 self.setToolBar(toolBar, [])
344
345 del self.__allToolBars[tbID]
346 del self.__toolBars[tbID]
347 del self.__toolBarsWithSeparators[tbID]
348 self.__customToolBars.remove(toolBar)
349 self.__mainWindow.removeToolBar(toolBar)
350 del toolBar
351
352 def renameToolBar(self, toolBar, title):
353 """
354 Public method to give a toolbar a new title.
355
356 @param toolBar reference to the toolbar to be managed (QToolBar)
357 @param title title to be used for the toolbar (string)
358 """
359 if toolBar is None:
360 return
361
362 toolBar.setWindowTitle(title)
363
364 if self.__ui is not None:
365 self.__ui.reregisterToolbar(toolBar.objectName(), title)
366
367 def toolBars(self):
368 """
369 Public method to get all toolbars.
370
371 @return list of all toolbars (list of QToolBar)
372 """
373 return list(self.__allToolBars.values())
374
375 def addAction(self, action, category):
376 """
377 Public method to add an action to be managed.
378
379 @param action reference to the action to be managed (QAction)
380 @param category category for the toolbar (string)
381 """
382 if action is None:
383 return
384 if action.isSeparator():
385 return
386 if action in self.__allActions:
387 return
388
389 if action.metaObject().className() == "QWidgetAction":
390 self.__widgetActions[id(action)] = None
391 self.__allWidgetActions[id(action)] = action
392 self.__allActions[id(action)] = action
393 if category not in self.__categoryToActions:
394 self.__categoryToActions[category] = []
395 self.__categoryToActions[category].append(action)
396 self.__actionToCategory[id(action)] = category
397 self.__actionToToolBars[id(action)] = []
398
399 def removeAction(self, action):
400 """
401 Public method to remove an action from the manager.
402
403 @param action reference to the action to be removed (QAction)
404 """
405 aID = id(action)
406
407 if aID not in self.__allActions:
408 return
409
410 toolBars = self.__actionToToolBars[aID]
411 for toolBar in toolBars:
412 tbID = id(toolBar)
413 self.__toolBars[tbID].remove(action)
414 self.__toolBarsWithSeparators[tbID].remove(action)
415 toolBar.removeAction(action)
416 if toolBar.isVisible():
417 toolBar.hide()
418 toolBar.show()
419
420 for tbID in self.__defaultToolBars:
421 if action in self.__defaultToolBars[tbID]:
422 self.__defaultToolBars[tbID].remove(action)
423
424 del self.__allActions[aID]
425 if aID in self.__widgetActions:
426 del self.__widgetActions[aID]
427 del self.__allWidgetActions[aID]
428 del self.__actionToCategory[aID]
429 del self.__actionToToolBars[aID]
430
431 for category in self.__categoryToActions:
432 if action in self.__categoryToActions[category]:
433 self.__categoryToActions[category].remove(action)
434
435 def saveState(self, version = 0):
436 """
437 Public method to save the state of the toolbar manager.
438
439 @param version version number stored with the data (integer)
440 @return saved state as a byte array (QByteArray)
441 """
442 data = QByteArray()
443 stream = QDataStream(data, QIODevice.WriteOnly)
444 stream.writeUInt16(E5ToolBarManager.VersionMarker)
445 stream.writeUInt16(version)
446
447 # save default toolbars
448 stream.writeUInt16(E5ToolBarManager.ToolBarMarker)
449 stream.writeUInt16(len(self.__defaultToolBars))
450 for tbID in self.__defaultToolBars:
451 tb = self.__allToolBars[tbID]
452 if tb.objectName():
453 stream.writeString(tb.objectName().encode())
454 else:
455 stream.writeString(tb.windowTitle().encode())
456 stream.writeUInt16(len(self.__toolBars[tbID]))
457 for action in self.__toolBars[tbID]:
458 if action is not None:
459 if action.objectName():
460 stream.writeString(action.objectName().encode())
461 else:
462 stream.writeString(action.text().encode())
463 else:
464 stream.writeString("".encode())
465
466 # save the custom toolbars
467 stream.writeUInt16(E5ToolBarManager.CustomToolBarMarker)
468 stream.writeUInt16(len(self.__toolBars) - len(self.__defaultToolBars))
469 for tbID in self.__toolBars:
470 if tbID not in self.__defaultToolBars:
471 tb = self.__allToolBars[tbID]
472 stream.writeString(tb.objectName().encode())
473 stream.writeString(tb.windowTitle().encode())
474 stream.writeUInt16(len(self.__toolBars[tbID]))
475 for action in self.__toolBars[tbID]:
476 if action is not None:
477 if action.objectName():
478 stream.writeString(action.objectName().encode())
479 else:
480 stream.writeString(action.text().encode())
481 else:
482 stream.writeString("".encode())
483
484 return data
485
486 def restoreState(self, state, version = 0):
487 """
488 Public method to restore the state of the toolbar manager.
489
490 @param state byte array containing the saved state (QByteArray)
491 @param version version number stored with the data (integer)
492 @return flag indicating success (boolean)
493 """
494 if state.isEmpty():
495 return False
496
497 data = QByteArray(state)
498 stream = QDataStream(data, QIODevice.ReadOnly)
499 marker = stream.readUInt16()
500 vers = stream.readUInt16()
501 if marker != E5ToolBarManager.VersionMarker or vers != version:
502 return False
503
504 tmarker = stream.readUInt16()
505 if tmarker != E5ToolBarManager.ToolBarMarker:
506 return False
507
508 toolBarCount = stream.readUInt16()
509 for i in range(toolBarCount):
510 objectName = stream.readString().decode()
511 actionCount = stream.readUInt16()
512 actions = []
513 for j in range(actionCount):
514 actionName = stream.readString().decode()
515 if actionName:
516 action = self.__findAction(actionName)
517 if action is not None:
518 actions.append(action)
519 else:
520 actions.append(None)
521 toolBar = self.__findDefaultToolBar(objectName)
522 if toolBar is not None:
523 self.setToolBar(toolBar, actions)
524
525 cmarker = stream.readUInt16()
526 if cmarker != E5ToolBarManager.CustomToolBarMarker:
527 return False
528
529 oldCustomToolBars = self.__customToolBars[:]
530
531 toolBarCount = stream.readUInt16()
532 for i in range(toolBarCount):
533 objectName = stream.readString().decode()
534 toolBarTitle = stream.readString().decode()
535 actionCount = stream.readUInt16()
536 actions = []
537 for j in range(actionCount):
538 actionName = stream.readString().decode()
539 if actionName:
540 action = self.__findAction(actionName)
541 if action is not None:
542 actions.append(action)
543 else:
544 actions.append(None)
545 toolBar = self.__toolBarByName(objectName)
546 if toolBar is not None:
547 toolBar.setWindowTitle(toolBarTitle)
548 oldCustomToolBars.remove(toolBar)
549 else:
550 toolBar = self.createToolBar(toolBarTitle)
551 if toolBar is not None:
552 toolBar.setObjectName(objectName)
553 self.setToolBar(toolBar, actions)
554
555 for tb in oldCustomToolBars:
556 self.deleteToolBar(tb)
557
558 return True
559
560 def toolBarWidgetAction(self, action):
561 """
562 Public method to get the toolbar for a widget action.
563
564 @param action widget action to check for (QAction)
565 @return reference to the toolbar containing action (QToolBar)
566 """
567 aID = id(action)
568 if aID in self.__widgetActions:
569 return self.__widgetActions[aID]
570 return None
571
572 def removeWidgetActions(self, actions):
573 """
574 Public method to remove widget actions.
575
576 @param actions dictionary with toolbar id as key and
577 a list of widget actions as value
578 """
579 for tbID in list(actions.keys())[:]:
580 toolBar = self.__allToolBars[tbID]
581 newActions = self.__toolBars[tbID][:]
582 newActionsWithSeparators = self.__toolBarsWithSeparators[tbID][:]
583
584 removedActions = []
585 for action in actions[tbID]:
586 if action in newActions and self.toolBarWidgetAction(action) == toolBar:
587 newActions.remove(action)
588 newActionsWithSeparators.remove(action)
589 removedActions.append(action)
590
591 self.__toolBars[tbID] = newActions
592 self.__toolBarsWithSeparators[tbID] = newActionsWithSeparators
593
594 for action in removedActions:
595 self.__widgetActions[id(action)] = None
596 self.__actionToToolBars[id(action)].remove(toolBar)
597 toolBar.removeAction(action)
598
599 def isWidgetAction(self, action):
600 """
601 Public method to check, if action is a widget action.
602
603 @param action reference to the action to be checked (QAction)
604 @return flag indicating a widget action (boolean)
605 """
606 return id(action) in self.__allWidgetActions
607
608 def categories(self):
609 """
610 Public method to get the list of categories.
611
612 @return list of categories (list of string)
613 """
614 return list(self.__categoryToActions.keys())
615
616 def categoryActions(self, category):
617 """
618 Public method to get the actions belonging to a category.
619
620 @param category category for the toolbar (string)
621 @return list of actions (list of QAction)
622 """
623 if category not in self.__categoryToActions:
624 return []
625
626 return self.__categoryToActions[category][:]
627
628 def actionById(self, aID):
629 """
630 Public method to get an action given it's id.
631
632 @param aID id of the action object (integer)
633 @return reference to the action (QAction)
634 """
635 if aID not in self.__allActions:
636 return None
637 return self.__allActions[aID]
638
639 def toolBarById(self, tbID):
640 """
641 Public method to get a toolbar given it's id.
642
643 @param tbID id of the toolbar object (integer)
644 @return reference to the toolbar (QToolBar)
645 """
646 if tbID not in self.__allToolBars:
647 return None
648 return self.__allToolBars[tbID]
649
650 def toolBarActions(self, tbID):
651 """
652 Public method to get a toolbar's actions given it's id.
653
654 @param tbID id of the toolbar object (integer)
655 @return list of actions (list of QAction)
656 """
657 if tbID not in self.__toolBars:
658 return []
659 return self.__toolBars[tbID][:]
660
661 def toolBarsActions(self):
662 """
663 Public method to get all toolbars and their actions.
664
665 @return reference to dictionary of toolbar IDs as key and list
666 of actions as values
667 """
668 return self.__toolBars
669
670 def defaultToolBarActions(self, tbID):
671 """
672 Public method to get a default toolbar's actions given it's id.
673
674 @param tbID id of the default toolbar object (integer)
675 @return list of actions (list of QAction)
676 """
677 if tbID not in self.__defaultToolBars:
678 return []
679 return self.__defaultToolBars[tbID][:]

eric ide

mercurial