|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2008 - 2010 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 """ |
|
7 Module implementing a toolbar configuration dialog. |
|
8 """ |
|
9 |
|
10 from PyQt4.QtGui import * |
|
11 from PyQt4.QtCore import * |
|
12 |
|
13 from .Ui_E5ToolBarDialog import Ui_E5ToolBarDialog |
|
14 |
|
15 import UI.PixmapCache |
|
16 |
|
17 class E5ToolBarItem(object): |
|
18 """ |
|
19 Class storing data belonging to a toolbar entry of the toolbar dialog. |
|
20 """ |
|
21 def __init__(self, toolBarId, actionIDs, default): |
|
22 """ |
|
23 Constructor |
|
24 |
|
25 @param toolBarId id of the toolbar object (integer) |
|
26 @param actionIDs list of action IDs belonging to the toolbar (list of integer) |
|
27 @param default flag indicating a default toolbar (boolean) |
|
28 """ |
|
29 self.toolBarId = toolBarId |
|
30 self.actionIDs = actionIDs[:] |
|
31 self.isDefault = default |
|
32 self.title = "" |
|
33 self.isChanged = False |
|
34 |
|
35 class E5ToolBarDialog(QDialog, Ui_E5ToolBarDialog): |
|
36 """ |
|
37 Class implementing a toolbar configuration dialog. |
|
38 """ |
|
39 ActionIdRole = Qt.UserRole |
|
40 WidgetActionRole = Qt.UserRole + 1 |
|
41 |
|
42 def __init__(self, toolBarManager, parent = None): |
|
43 """ |
|
44 Constructor |
|
45 |
|
46 @param toolBarManager reference to a toolbar manager object (E5ToolBarManager) |
|
47 @param parent reference to the parent widget (QWidget) |
|
48 """ |
|
49 QDialog.__init__(self, parent) |
|
50 self.setupUi(self) |
|
51 |
|
52 self.__manager = toolBarManager |
|
53 self.__toolbarItems = {} # maps toolbar item IDs to toolbar items |
|
54 self.__currentToolBarItem = None |
|
55 self.__removedToolBarIDs = [] # remember custom toolbars to be deleted |
|
56 |
|
57 self.__widgetActionToToolBarItemID = {} # maps widget action IDs to toolbar item IDs |
|
58 self.__toolBarItemToWidgetActionID = {} # maps toolbar item IDs to widget action IDs |
|
59 |
|
60 self.upButton.setIcon(UI.PixmapCache.getIcon("1uparrow.png")) |
|
61 self.downButton.setIcon(UI.PixmapCache.getIcon("1downarrow.png")) |
|
62 self.leftButton.setIcon(UI.PixmapCache.getIcon("1leftarrow.png")) |
|
63 self.rightButton.setIcon(UI.PixmapCache.getIcon("1rightarrow.png")) |
|
64 |
|
65 self.__restoreDefaultsButton = \ |
|
66 self.buttonBox.button(QDialogButtonBox.RestoreDefaults) |
|
67 self.__resetButton = self.buttonBox.button(QDialogButtonBox.Reset) |
|
68 |
|
69 self.actionsTree.header().hide() |
|
70 self.__separatorText = self.trUtf8("--Separator--") |
|
71 itm = QTreeWidgetItem(self.actionsTree, [self.__separatorText]) |
|
72 self.actionsTree.setCurrentItem(itm) |
|
73 |
|
74 for category in sorted(self.__manager.categories()): |
|
75 categoryItem = QTreeWidgetItem(self.actionsTree, [category]) |
|
76 for action in self.__manager.categoryActions(category): |
|
77 item = QTreeWidgetItem(categoryItem) |
|
78 item.setText(0, action.text()) |
|
79 item.setIcon(0, action.icon()) |
|
80 item.setTextAlignment(0, Qt.AlignLeft | Qt.AlignVCenter) |
|
81 item.setData(0, E5ToolBarDialog.ActionIdRole, int(id(action))) |
|
82 item.setData(0, E5ToolBarDialog.WidgetActionRole, False) |
|
83 if self.__manager.isWidgetAction(action): |
|
84 item.setData(0, E5ToolBarDialog.WidgetActionRole, True) |
|
85 item.setData(0, Qt.TextColorRole, QColor(Qt.blue)) |
|
86 self.__widgetActionToToolBarItemID[id(action)] = None |
|
87 categoryItem.setExpanded(True) |
|
88 |
|
89 for tbID, actions in list(self.__manager.toolBarsActions().items()): |
|
90 tb = self.__manager.toolBarById(tbID) |
|
91 default = self.__manager.isDefaultToolBar(tb) |
|
92 tbItem = E5ToolBarItem(tbID, [], default) |
|
93 self.__toolbarItems[id(tbItem)] = tbItem |
|
94 self.__toolBarItemToWidgetActionID[id(tbItem)] = [] |
|
95 actionIDs = [] |
|
96 for action in actions: |
|
97 if action is None: |
|
98 actionIDs.append(None) |
|
99 else: |
|
100 aID = id(action) |
|
101 actionIDs.append(aID) |
|
102 if aID in self.__widgetActionToToolBarItemID: |
|
103 self.__widgetActionToToolBarItemID[aID] = id(tbItem) |
|
104 self.__toolBarItemToWidgetActionID[id(tbItem)].append(aID) |
|
105 tbItem.actionIDs = actionIDs |
|
106 self.toolbarComboBox.addItem(tb.windowTitle(), int(id(tbItem))) |
|
107 if default: |
|
108 self.toolbarComboBox.setItemData(self.toolbarComboBox.count() - 1, |
|
109 QColor(Qt.darkGreen), Qt.ForegroundRole) |
|
110 self.toolbarComboBox.model().sort(0) |
|
111 |
|
112 self.connect(self.toolbarComboBox, SIGNAL("currentIndexChanged(int)"), |
|
113 self.__toolbarComboBox_currentIndexChanged) |
|
114 self.toolbarComboBox.setCurrentIndex(0) |
|
115 |
|
116 @pyqtSlot() |
|
117 def on_newButton_clicked(self): |
|
118 """ |
|
119 Private slot to create a new toolbar. |
|
120 """ |
|
121 name, ok = QInputDialog.getText(\ |
|
122 self, |
|
123 self.trUtf8("New Toolbar"), |
|
124 self.trUtf8("Toolbar Name:"), |
|
125 QLineEdit.Normal) |
|
126 if ok and name: |
|
127 if self.toolbarComboBox.findText(name) != -1: |
|
128 # toolbar with this name already exists |
|
129 QMessageBox.critical(self, |
|
130 self.trUtf8("New Toolbar"), |
|
131 self.trUtf8("""A toolbar with the name <b>{0}</b> already exists.""")\ |
|
132 .format(name), |
|
133 QMessageBox.StandardButtons(\ |
|
134 QMessageBox.Abort)) |
|
135 return |
|
136 |
|
137 tbItem = E5ToolBarItem(None, [], False) |
|
138 tbItem.title = name |
|
139 tbItem.isChanged = True |
|
140 self.__toolbarItems[id(tbItem)] = tbItem |
|
141 self.__toolBarItemToWidgetActionID[id(tbItem)] = [] |
|
142 self.toolbarComboBox.addItem(name, int(id(tbItem))) |
|
143 self.toolbarComboBox.model().sort(0) |
|
144 self.toolbarComboBox.setCurrentIndex(self.toolbarComboBox.findText(name)) |
|
145 |
|
146 @pyqtSlot() |
|
147 def on_removeButton_clicked(self): |
|
148 """ |
|
149 Private slot to remove a custom toolbar |
|
150 """ |
|
151 name = self.toolbarComboBox.currentText() |
|
152 res = QMessageBox.question(self, |
|
153 self.trUtf8("Remove Toolbar"), |
|
154 self.trUtf8("""Should the toolbar <b>{0}</b> really be removed?""")\ |
|
155 .format(name), |
|
156 QMessageBox.StandardButtons(\ |
|
157 QMessageBox.No | \ |
|
158 QMessageBox.Yes), |
|
159 QMessageBox.No) |
|
160 if res == QMessageBox.Yes: |
|
161 index = self.toolbarComboBox.currentIndex() |
|
162 tbItemID = self.toolbarComboBox.itemData(index) |
|
163 tbItem = self.__toolbarItems[tbItemID] |
|
164 if tbItem.toolBarId is not None and \ |
|
165 tbItem.toolBarId not in self.__removedToolBarIDs: |
|
166 self.__removedToolBarIDs.append(tbItem.toolBarId) |
|
167 del self.__toolbarItems[tbItemID] |
|
168 for widgetActionID in self.__toolBarItemToWidgetActionID[tbItemID]: |
|
169 self.__widgetActionToToolBarItemID[widgetActionID] = None |
|
170 del self.__toolBarItemToWidgetActionID[tbItemID] |
|
171 self.toolbarComboBox.removeItem(index) |
|
172 |
|
173 @pyqtSlot() |
|
174 def on_renameButton_clicked(self): |
|
175 """ |
|
176 Private slot to rename a custom toolbar. |
|
177 """ |
|
178 oldName = self.toolbarComboBox.currentText() |
|
179 newName, ok = QInputDialog.getText(\ |
|
180 self, |
|
181 self.trUtf8("Rename Toolbar"), |
|
182 self.trUtf8("New Toolbar Name:"), |
|
183 QLineEdit.Normal, |
|
184 oldName) |
|
185 if ok and newName: |
|
186 if oldName == newName: |
|
187 return |
|
188 if self.toolbarComboBox.findText(newName) != -1: |
|
189 # toolbar with this name already exists |
|
190 QMessageBox.critical(self, |
|
191 self.trUtf8("Rename Toolbar"), |
|
192 self.trUtf8("""A toolbar with the name <b>{0}</b> already exists.""")\ |
|
193 .format(newName), |
|
194 QMessageBox.StandardButtons(\ |
|
195 QMessageBox.Abort)) |
|
196 return |
|
197 index = self.toolbarComboBox.currentIndex() |
|
198 self.toolbarComboBox.setItemText(index, newName) |
|
199 tbItem = \ |
|
200 self.__toolbarItems[self.toolbarComboBox.itemData(index)] |
|
201 tbItem.title = newName |
|
202 tbItem.isChanged = True |
|
203 |
|
204 def __setupButtons(self): |
|
205 """ |
|
206 Private slot to set the buttons state. |
|
207 """ |
|
208 index = self.toolbarComboBox.currentIndex() |
|
209 if index > -1: |
|
210 itemID = self.toolbarComboBox.itemData(index) |
|
211 self.__currentToolBarItem = self.__toolbarItems[itemID] |
|
212 self.renameButton.setEnabled(not self.__currentToolBarItem.isDefault) |
|
213 self.removeButton.setEnabled(not self.__currentToolBarItem.isDefault) |
|
214 self.__restoreDefaultsButton.setEnabled(self.__currentToolBarItem.isDefault) |
|
215 self.__resetButton.setEnabled(self.__currentToolBarItem.toolBarId is not None) |
|
216 |
|
217 row = self.toolbarActionsList.currentRow() |
|
218 self.upButton.setEnabled(row > 0) |
|
219 self.downButton.setEnabled(row < self.toolbarActionsList.count() - 1) |
|
220 self.leftButton.setEnabled(self.toolbarActionsList.count() > 0) |
|
221 rightEnable = self.actionsTree.currentItem().parent() is not None or \ |
|
222 self.actionsTree.currentItem().text(0) == self.__separatorText |
|
223 self.rightButton.setEnabled(rightEnable) |
|
224 |
|
225 @pyqtSlot(int) |
|
226 def __toolbarComboBox_currentIndexChanged(self, index): |
|
227 """ |
|
228 Private slot called upon a selection of the current toolbar. |
|
229 |
|
230 @param index index of the new current toolbar (integer) |
|
231 """ |
|
232 itemID = self.toolbarComboBox.itemData(index) |
|
233 self.__currentToolBarItem = self.__toolbarItems[itemID] |
|
234 self.toolbarActionsList.clear() |
|
235 for actionID in self.__currentToolBarItem.actionIDs: |
|
236 item = QListWidgetItem(self.toolbarActionsList) |
|
237 if actionID is None: |
|
238 item.setText(self.__separatorText) |
|
239 else: |
|
240 action = self.__manager.actionById(actionID) |
|
241 item.setText(action.text()) |
|
242 item.setIcon(action.icon()) |
|
243 item.setTextAlignment(Qt.AlignLeft | Qt.AlignVCenter) |
|
244 item.setData(E5ToolBarDialog.ActionIdRole, int(id(action))) |
|
245 item.setData(E5ToolBarDialog.WidgetActionRole, False) |
|
246 if self.__manager.isWidgetAction(action): |
|
247 item.setData(E5ToolBarDialog.WidgetActionRole, True) |
|
248 item.setData(Qt.TextColorRole, QColor(Qt.blue)) |
|
249 self.toolbarActionsList.setCurrentRow(0) |
|
250 |
|
251 self.__setupButtons() |
|
252 |
|
253 @pyqtSlot(QTreeWidgetItem, QTreeWidgetItem) |
|
254 def on_actionsTree_currentItemChanged(self, current, previous): |
|
255 """ |
|
256 Private slot called, when the currently selected action changes. |
|
257 """ |
|
258 self.__setupButtons() |
|
259 |
|
260 @pyqtSlot(QListWidgetItem, QListWidgetItem) |
|
261 def on_toolbarActionsList_currentItemChanged(self, current, previous): |
|
262 """ |
|
263 Slot documentation goes here. |
|
264 """ |
|
265 self.__setupButtons() |
|
266 |
|
267 @pyqtSlot() |
|
268 def on_upButton_clicked(self): |
|
269 """ |
|
270 Private slot used to move an action up in the list. |
|
271 """ |
|
272 row = self.toolbarActionsList.currentRow() |
|
273 if row == 0: |
|
274 # we're already at the top |
|
275 return |
|
276 |
|
277 actionID = self.__currentToolBarItem.actionIDs.pop(row) |
|
278 self.__currentToolBarItem.actionIDs.insert(row - 1, actionID) |
|
279 self.__currentToolBarItem.isChanged = True |
|
280 itm = self.toolbarActionsList.takeItem(row) |
|
281 self.toolbarActionsList.insertItem(row - 1, itm) |
|
282 self.toolbarActionsList.setCurrentItem(itm) |
|
283 self.__setupButtons() |
|
284 |
|
285 @pyqtSlot() |
|
286 def on_downButton_clicked(self): |
|
287 """ |
|
288 Private slot used to move an action down in the list. |
|
289 """ |
|
290 row = self.toolbarActionsList.currentRow() |
|
291 if row == self.toolbarActionsList.count() - 1: |
|
292 # we're already at the end |
|
293 return |
|
294 |
|
295 actionID = self.__currentToolBarItem.actionIDs.pop(row) |
|
296 self.__currentToolBarItem.actionIDs.insert(row + 1, actionID) |
|
297 self.__currentToolBarItem.isChanged = True |
|
298 itm = self.toolbarActionsList.takeItem(row) |
|
299 self.toolbarActionsList.insertItem(row + 1, itm) |
|
300 self.toolbarActionsList.setCurrentItem(itm) |
|
301 self.__setupButtons() |
|
302 |
|
303 @pyqtSlot() |
|
304 def on_leftButton_clicked(self): |
|
305 """ |
|
306 Private slot to delete an action from the list. |
|
307 """ |
|
308 row = self.toolbarActionsList.currentRow() |
|
309 actionID = self.__currentToolBarItem.actionIDs.pop(row) |
|
310 self.__currentToolBarItem.isChanged = True |
|
311 if actionID in self.__widgetActionToToolBarItemID: |
|
312 self.__widgetActionToToolBarItemID[actionID] = None |
|
313 self.__toolBarItemToWidgetActionID[id(self.__currentToolBarItem)]\ |
|
314 .remove(actionID) |
|
315 itm = self.toolbarActionsList.takeItem(row) |
|
316 del itm |
|
317 self.toolbarActionsList.setCurrentRow(row) |
|
318 self.__setupButtons() |
|
319 |
|
320 @pyqtSlot() |
|
321 def on_rightButton_clicked(self): |
|
322 """ |
|
323 Private slot to add an action to the list. |
|
324 """ |
|
325 row = self.toolbarActionsList.currentRow() + 1 |
|
326 |
|
327 item = QListWidgetItem() |
|
328 if self.actionsTree.currentItem().text(0) == self.__separatorText: |
|
329 item.setText(self.__separatorText) |
|
330 actionID = None |
|
331 else: |
|
332 actionID = self.actionsTree.currentItem()\ |
|
333 .data(0, E5ToolBarDialog.ActionIdRole) |
|
334 action = self.__manager.actionById(actionID) |
|
335 item.setText(action.text()) |
|
336 item.setIcon(action.icon()) |
|
337 item.setTextAlignment(Qt.AlignLeft | Qt.AlignVCenter) |
|
338 item.setData(E5ToolBarDialog.ActionIdRole, int(id(action))) |
|
339 item.setData(E5ToolBarDialog.WidgetActionRole, False) |
|
340 if self.__manager.isWidgetAction(action): |
|
341 item.setData(E5ToolBarDialog.WidgetActionRole, True) |
|
342 item.setData(Qt.TextColorRole, QColor(Qt.blue)) |
|
343 oldTbItemID = self.__widgetActionToToolBarItemID[actionID] |
|
344 if oldTbItemID is not None: |
|
345 self.__toolbarItems[oldTbItemID].actionIDs.remove(actionID) |
|
346 self.__toolbarItems[oldTbItemID].isChanged = True |
|
347 self.__toolBarItemToWidgetActionID[oldTbItemID].remove(actionID) |
|
348 self.__widgetActionToToolBarItemID[actionID] = \ |
|
349 id(self.__currentToolBarItem) |
|
350 self.__toolBarItemToWidgetActionID[id(self.__currentToolBarItem)]\ |
|
351 .append(actionID) |
|
352 self.toolbarActionsList.insertItem(row, item) |
|
353 self.__currentToolBarItem.actionIDs.insert(row, actionID) |
|
354 self.__currentToolBarItem.isChanged = True |
|
355 self.toolbarActionsList.setCurrentRow(row) |
|
356 self.__setupButtons() |
|
357 |
|
358 @pyqtSlot(QAbstractButton) |
|
359 def on_buttonBox_clicked(self, button): |
|
360 """ |
|
361 Private slot called, when a button of the button box was clicked. |
|
362 """ |
|
363 if button == self.buttonBox.button(QDialogButtonBox.Cancel): |
|
364 self.reject() |
|
365 elif button == self.buttonBox.button(QDialogButtonBox.Apply): |
|
366 self.__saveToolBars() |
|
367 self.__setupButtons() |
|
368 elif button == self.buttonBox.button(QDialogButtonBox.Ok): |
|
369 self.__saveToolBars() |
|
370 self.accept() |
|
371 elif button == self.buttonBox.button(QDialogButtonBox.Reset): |
|
372 self.__resetCurrentToolbar() |
|
373 self.__setupButtons() |
|
374 elif button == self.buttonBox.button(QDialogButtonBox.RestoreDefaults): |
|
375 self.__restoreCurrentToolbarToDefault() |
|
376 self.__setupButtons() |
|
377 |
|
378 def __saveToolBars(self): |
|
379 """ |
|
380 Private method to save the configured toolbars. |
|
381 """ |
|
382 # step 1: remove toolbars marked for deletion |
|
383 for tbID in self.__removedToolBarIDs: |
|
384 tb = self.__manager.toolBarById(tbID) |
|
385 self.__manager.deleteToolBar(tb) |
|
386 self.__removedToolBarIDs = [] |
|
387 |
|
388 # step 2: save configured toolbars |
|
389 for tbItem in list(self.__toolbarItems.values()): |
|
390 if not tbItem.isChanged: |
|
391 continue |
|
392 |
|
393 if tbItem.toolBarId is None: |
|
394 # new custom toolbar |
|
395 tb = self.__manager.createToolBar(tbItem.title) |
|
396 tbItem.toolBarId = id(tb) |
|
397 else: |
|
398 tb = self.__manager.toolBarById(tbItem.toolBarId) |
|
399 if not tbItem.isDefault and tbItem.title: |
|
400 self.__manager.renameToolBar(tb, tbItem.title) |
|
401 |
|
402 actions = [] |
|
403 for actionID in tbItem.actionIDs: |
|
404 if actionID is None: |
|
405 actions.append(None) |
|
406 else: |
|
407 action = self.__manager.actionById(actionID) |
|
408 if action is None: |
|
409 raise RuntimeError("No such action, id: 0x%x" % actionID) |
|
410 actions.append(action) |
|
411 self.__manager.setToolBar(tb, actions) |
|
412 tbItem.isChanged = False |
|
413 |
|
414 def __restoreCurrentToolbar(self, actions): |
|
415 """ |
|
416 Private methdo to restore the current toolbar to the given list of actions. |
|
417 |
|
418 @param actions list of actions to set for the current toolbar (list of QAction) |
|
419 """ |
|
420 tbItemID = id(self.__currentToolBarItem) |
|
421 for widgetActionID in self.__toolBarItemToWidgetActionID[tbItemID]: |
|
422 self.__widgetActionToToolBarItemID[widgetActionID] = None |
|
423 self.__toolBarItemToWidgetActionID[tbItemID] = [] |
|
424 self.__currentToolBarItem.actionIDs = [] |
|
425 |
|
426 for action in actions: |
|
427 if action is None: |
|
428 self.__currentToolBarItem.actionIDs.append(None) |
|
429 else: |
|
430 actionID = id(action) |
|
431 self.__currentToolBarItem.actionIDs.append(actionID) |
|
432 if actionID in self.__widgetActionToToolBarItemID: |
|
433 oldTbItemID = self.__widgetActionToToolBarItemID[actionID] |
|
434 if oldTbItemID is not None: |
|
435 self.__toolbarItems[oldTbItemID].actionIDs.remove(actionID) |
|
436 self.__toolbarItems[oldTbItemID].isChanged = True |
|
437 self.__toolBarItemToWidgetActionID[oldTbItemID].remove(actionID) |
|
438 self.__widgetActionToToolBarItemID[actionID] = tbItemID |
|
439 self.__toolBarItemToWidgetActionID[tbItemID].append(actionID) |
|
440 self.__toolbarComboBox_currentIndexChanged(self.toolbarComboBox.currentIndex()) |
|
441 |
|
442 def __resetCurrentToolbar(self): |
|
443 """ |
|
444 Private method to revert all changes made to the current toolbar. |
|
445 """ |
|
446 tbID = self.__currentToolBarItem.toolBarId |
|
447 actions = self.__manager.toolBarActions(tbID) |
|
448 self.__restoreCurrentToolbar(actions) |
|
449 self.__currentToolBarItem.isChanged = False |
|
450 |
|
451 def __restoreCurrentToolbarToDefault(self): |
|
452 """ |
|
453 Private method to set the current toolbar to it's default configuration. |
|
454 """ |
|
455 if not self.__currentToolBarItem.isDefault: |
|
456 return |
|
457 |
|
458 tbID = self.__currentToolBarItem.toolBarId |
|
459 actions = self.__manager.defaultToolBarActions(tbID) |
|
460 self.__restoreCurrentToolbar(actions) |
|
461 self.__currentToolBarItem.isChanged = True |