src/eric7/EricWidgets/EricToolBarDialog.py

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

eric ide

mercurial