eric7/EricWidgets/EricToolBarDialog.py

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

eric ide

mercurial