1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qttoolbardialog.h"
5#include "ui_qttoolbardialog.h"
6
7#include <QtCore/QMap>
8#include <QtCore/QHash>
9#include <QtCore/QSet>
10#include <QtGui/QAction>
11#include <QtGui/QtEvents>
12#include <QtWidgets/QMainWindow>
13#include <QtWidgets/QPushButton>
14#include <QtWidgets/QToolBar>
15
16#include <algorithm>
17
18QT_BEGIN_NAMESPACE
19
20using namespace Qt::StringLiterals;
21
22class QtFullToolBarManagerPrivate;
23
24class QtFullToolBarManager : public QObject
25{
26 Q_OBJECT
27public:
28 QtFullToolBarManager(QObject *parent);
29 ~QtFullToolBarManager();
30
31 void setMainWindow(QMainWindow *mainWindow);
32 QMainWindow *mainWindow() const;
33
34 void addCategory(const QString &category);
35 bool hasCategory(const QString &category) const;
36 QStringList categories() const;
37 QList<QAction *> categoryActions(const QString &category) const;
38 QString actionCategory(QAction *action) const;
39
40 // only non-separator
41 void addAction(QAction *action, const QString &category);
42
43 void removeAction(QAction *action);
44
45 QSet<QAction *> actions() const;
46 bool isWidgetAction(QAction *action) const;
47
48 /*
49 Adds (registers) toolBar. Adds (registers) actions that already exists in toolBar.
50 Remembers toolbar and its actions as a default.
51 */
52 void addDefaultToolBar(QToolBar *toolBar, const QString &category);
53
54 void removeDefaultToolBar(QToolBar *toolBar);
55 // NULL on action list means separator.
56 QHash<QToolBar *, QList<QAction *>> defaultToolBars() const;
57 bool isDefaultToolBar(QToolBar *toolBar) const;
58
59 QToolBar *createToolBar(const QString &toolBarName);
60 void deleteToolBar(QToolBar *toolBar); // only those which were created, not added
61
62 QList<QAction *> actions(QToolBar *toolBar) const;
63
64 void setToolBars(const QHash<QToolBar *, QList<QAction *>> &actions);
65 void setToolBar(QToolBar *toolBar, const QList<QAction *> &actions);
66
67 QHash<QToolBar *, QList<QAction *>> toolBarsActions() const;
68 QByteArray saveState(int version = 0) const;
69 bool restoreState(const QByteArray &state, int version = 0);
70
71public slots:
72
73 void resetToolBar(QToolBar *toolBar);
74 void resetAllToolBars();
75
76signals:
77 void toolBarCreated(QToolBar *toolBar);
78 void toolBarRemoved(QToolBar *toolBar);
79
80 /*
81 If QToolBarWidgetAction was in another tool bar and is inserted into
82 this toolBar, toolBarChanged is first emitted for other toolbar - without
83 that action. (Another approach may be that user first must call setToolBar
84 without that action for old tool bar)
85 */
86 void toolBarChanged(QToolBar *toolBar, const QList<QAction *> &actions);
87
88private:
89 QScopedPointer<QtFullToolBarManagerPrivate> d_ptr;
90 Q_DECLARE_PRIVATE(QtFullToolBarManager)
91 Q_DISABLE_COPY_MOVE(QtFullToolBarManager)
92};
93
94class QtFullToolBarManagerPrivate
95{
96 class QtFullToolBarManager *q_ptr;
97 Q_DECLARE_PUBLIC(QtFullToolBarManager)
98
99public:
100
101 QToolBar *toolBarWidgetAction(QAction *action) const;
102 void removeWidgetActions(const QHash<QToolBar *, QList<QAction *>> &actions);
103
104 enum {
105 VersionMarker = 0xff,
106 ToolBarMarker = 0xfe,
107 CustomToolBarMarker = 0xfd,
108 };
109
110 void saveState(QDataStream &stream) const;
111 bool restoreState(QDataStream &stream) const;
112 QToolBar *findDefaultToolBar(const QString &objectName) const;
113 QAction *findAction(const QString &actionName) const;
114
115 QToolBar *toolBarByName(const QString &toolBarName) const;
116
117 QHash<QString, QList<QAction *>> categoryToActions;
118 QHash<QAction *, QString> actionToCategory;
119
120 QSet<QAction *> allActions;
121 QHash<QAction *, QToolBar *> widgetActions;
122 QSet<QAction *> regularActions;
123 QHash<QAction *, QList<QToolBar *>> actionToToolBars;
124
125 QHash<QToolBar *, QList<QAction *>> toolBars;
126 QHash<QToolBar *, QList<QAction *>> toolBarsWithSeparators;
127 QHash<QToolBar *, QList<QAction *>> defaultToolBars;
128 QList<QToolBar *> customToolBars;
129
130 QMainWindow *theMainWindow{nullptr};
131};
132
133QToolBar *QtFullToolBarManagerPrivate::toolBarWidgetAction(QAction *action) const
134{
135 if (widgetActions.contains(key: action))
136 return widgetActions.value(key: action);
137 return 0;
138}
139
140void QtFullToolBarManagerPrivate::removeWidgetActions(const QHash<QToolBar *, QList<QAction *>>
141 &actions)
142{
143 auto itToolBar = actions.constBegin();
144 while (itToolBar != actions.constEnd()) {
145 QToolBar *toolBar = itToolBar.key();
146 auto newActions = toolBars.value(key: toolBar);
147 auto newActionsWithSeparators = toolBarsWithSeparators.value(key: toolBar);
148
149 QList<QAction *> removedActions;
150 const auto actionList = itToolBar.value();
151 for (QAction *action : actionList) {
152 if (newActions.contains(t: action) && toolBarWidgetAction(action) == toolBar) {
153 newActions.removeAll(t: action);
154 newActionsWithSeparators.removeAll(t: action);
155 removedActions.append(t: action);
156 }
157 }
158
159 //emit q_ptr->toolBarChanged(toolBar, newActions);
160
161 toolBars.insert(key: toolBar, value: newActions);
162 toolBarsWithSeparators.insert(key: toolBar, value: newActionsWithSeparators);
163 for (QAction *oldAction : std::as_const(t&: removedActions)) {
164 widgetActions.insert(key: oldAction, value: 0);
165 actionToToolBars[oldAction].removeAll(t: toolBar);
166 }
167
168 ++itToolBar;
169 }
170}
171
172void QtFullToolBarManagerPrivate::saveState(QDataStream &stream) const
173{
174 stream << (uchar) ToolBarMarker;
175 stream << defaultToolBars.size();
176 auto itToolBar = defaultToolBars.constBegin();
177 while (itToolBar != defaultToolBars.constEnd()) {
178 QToolBar *tb = itToolBar.key();
179 if (tb->objectName().isEmpty()) {
180 qWarning(msg: "QtToolBarManager::saveState(): 'objectName' not set for QToolBar "
181 "%p '%s', using 'windowTitle' instead",
182 tb, tb->windowTitle().toLocal8Bit().constData());
183 stream << tb->windowTitle();
184 } else {
185 stream << tb->objectName();
186 }
187
188 const auto actions = toolBars.value(key: tb);
189 stream << actions.size();
190 for (QAction *action : actions) {
191 if (action) {
192 if (action->objectName().isEmpty()) {
193 qWarning(msg: "QtToolBarManager::saveState(): 'objectName' not set for QAction "
194 "%p '%s', using 'text' instead",
195 action, action->text().toLocal8Bit().constData());
196 stream << action->text();
197 } else {
198 stream << action->objectName();
199 }
200 } else {
201 stream << QString();
202 }
203 }
204 ++itToolBar;
205 }
206
207
208 stream << (uchar) CustomToolBarMarker;
209 stream << toolBars.size() - defaultToolBars.size();
210 itToolBar = toolBars.constBegin();
211 while (itToolBar != toolBars.constEnd()) {
212 QToolBar *tb = itToolBar.key();
213 if (!defaultToolBars.contains(key: tb)) {
214 stream << tb->objectName();
215 stream << tb->windowTitle();
216
217 stream << toolBars[tb].size();
218
219 const auto actions = toolBars.value(key: tb);
220 for (QAction *action : actions) {
221 if (action) {
222 if (action->objectName().isEmpty()) {
223 qWarning(msg: "QtToolBarManager::saveState(): 'objectName' not set for QAction "
224 "%p '%s', using 'text' instead",
225 action, action->text().toLocal8Bit().constData());
226 stream << action->text();
227 } else {
228 stream << action->objectName();
229 }
230 } else {
231 stream << QString();
232 }
233 }
234 }
235 ++itToolBar;
236 }
237}
238
239bool QtFullToolBarManagerPrivate::restoreState(QDataStream &stream) const
240{
241 uchar tmarker;
242 stream >> tmarker;
243 if (tmarker != ToolBarMarker)
244 return false;
245
246 int toolBars;
247 stream >> toolBars;
248 for (int i = 0; i < toolBars; i++) {
249 QString objectName;
250 stream >> objectName;
251 int actionCount;
252 stream >> actionCount;
253 QList<QAction *> actions;
254 for (int j = 0; j < actionCount; j++) {
255 QString actionName;
256 stream >> actionName;
257
258 if (actionName.isEmpty())
259 actions.append(t: 0);
260 else {
261 QAction *action = findAction(actionName);
262 if (action)
263 actions.append(t: action);
264 }
265 }
266
267 QToolBar *toolBar = findDefaultToolBar(objectName);
268 if (toolBar)
269 q_ptr->setToolBar(toolBar, actions);
270 }
271
272
273
274 uchar ctmarker;
275 stream >> ctmarker;
276 if (ctmarker != CustomToolBarMarker)
277 return false;
278
279 auto oldCustomToolBars = customToolBars;
280
281 stream >> toolBars;
282 for (int i = 0; i < toolBars; i++) {
283 QString objectName;
284 QString toolBarName;
285 int actionCount;
286 stream >> objectName;
287 stream >> toolBarName;
288 stream >> actionCount;
289 QList<QAction *> actions;
290 for (int j = 0; j < actionCount; j++) {
291 QString actionName;
292 stream >> actionName;
293
294 if (actionName.isEmpty())
295 actions.append(t: 0);
296 else {
297 QAction *action = findAction(actionName);
298 if (action)
299 actions.append(t: action);
300 }
301 }
302
303 QToolBar *toolBar = toolBarByName(toolBarName: objectName);
304 if (toolBar) {
305 toolBar->setWindowTitle(toolBarName);
306 oldCustomToolBars.removeAll(t: toolBar);
307 }
308 else
309 toolBar = q_ptr->createToolBar(toolBarName);
310 if (toolBar) {
311 toolBar->setObjectName(objectName);
312 q_ptr->setToolBar(toolBar, actions);
313 }
314 }
315 for (QToolBar *toolBar : std::as_const(t&: oldCustomToolBars))
316 q_ptr->deleteToolBar(toolBar);
317 return true;
318}
319
320QToolBar *QtFullToolBarManagerPrivate::findDefaultToolBar(const QString &objectName) const
321{
322 auto itToolBar = defaultToolBars.constBegin();
323 while (itToolBar != defaultToolBars.constEnd()) {
324 QToolBar *tb = itToolBar.key();
325 if (tb->objectName() == objectName)
326 return tb;
327
328 ++itToolBar;
329 }
330
331 qWarning(msg: "QtToolBarManager::restoreState(): cannot find a QToolBar named "
332 "'%s', trying to match using 'windowTitle' instead.",
333 objectName.toLocal8Bit().constData());
334
335 itToolBar = defaultToolBars.constBegin();
336 while (itToolBar != defaultToolBars.constEnd()) {
337 QToolBar *tb = itToolBar.key();
338 if (tb->windowTitle() == objectName)
339 return tb;
340
341 ++itToolBar;
342 }
343 qWarning(msg: "QtToolBarManager::restoreState(): cannot find a QToolBar with "
344 "matching 'windowTitle' (looking for '%s').",
345 objectName.toLocal8Bit().constData());
346
347 return 0;
348}
349
350QAction *QtFullToolBarManagerPrivate::findAction(const QString &actionName) const
351{
352 auto it =
353 std::find_if(first: allActions.cbegin(), last: allActions.cend(),
354 pred: [&actionName] (const QAction *a) { return a->objectName() == actionName; });
355 if (it != allActions.cend())
356 return *it;
357 qWarning(msg: "QtToolBarManager::restoreState(): cannot find a QAction named "
358 "'%s', trying to match using 'text' instead.",
359 actionName.toLocal8Bit().constData());
360
361 it = std::find_if(first: allActions.cbegin(), last: allActions.cend(),
362 pred: [&actionName] (const QAction *a) { return a->text() == actionName; });
363 if (it != allActions.cend())
364 return *it;
365 qWarning(msg: "QtToolBarManager::restoreState(): cannot find a QAction with "
366 "matching 'text' (looking for '%s').",
367 actionName.toLocal8Bit().constData());
368
369 return 0;
370}
371
372QToolBar *QtFullToolBarManagerPrivate::toolBarByName(const QString &toolBarName) const
373{
374 auto itToolBar = toolBars.constBegin();
375 while (itToolBar != toolBars.constEnd()) {
376 QToolBar *toolBar = itToolBar.key();
377 if (toolBar->objectName() == toolBarName)
378 return toolBar;
379
380 ++itToolBar;
381 }
382 return 0;
383}
384
385//////////////////////////////
386
387QtFullToolBarManager::QtFullToolBarManager(QObject *parent)
388 : QObject(parent), d_ptr(new QtFullToolBarManagerPrivate)
389{
390 d_ptr->q_ptr = this;
391}
392
393QtFullToolBarManager::~QtFullToolBarManager()
394{
395}
396
397void QtFullToolBarManager::setMainWindow(QMainWindow *mainWindow)
398{
399 d_ptr->theMainWindow = mainWindow;
400}
401
402QMainWindow *QtFullToolBarManager::mainWindow() const
403{
404 return d_ptr->theMainWindow;
405}
406
407void QtFullToolBarManager::addCategory(const QString &category)
408{
409 d_ptr->categoryToActions[category] = QList<QAction *>();
410}
411
412bool QtFullToolBarManager::hasCategory(const QString &category) const
413{
414 return d_ptr->categoryToActions.contains(key: category);
415}
416
417QStringList QtFullToolBarManager::categories() const
418{
419 return d_ptr->categoryToActions.keys();
420}
421
422QList<QAction *> QtFullToolBarManager::categoryActions(const QString &category) const
423{
424 const auto it = d_ptr->categoryToActions.constFind(key: category);
425 if (it != d_ptr->categoryToActions.constEnd())
426 return it.value();
427 return {};
428}
429
430QString QtFullToolBarManager::actionCategory(QAction *action) const
431{
432 return d_ptr->actionToCategory.value(key: action, defaultValue: {});
433}
434
435void QtFullToolBarManager::addAction(QAction *action, const QString &category)
436{
437 if (!action)
438 return;
439 if (action->isSeparator())
440 return;
441 if (d_ptr->allActions.contains(value: action))
442 return;
443 if (qstrcmp(str1: action->metaObject()->className(), str2: "QToolBarWidgetAction") == 0)
444 d_ptr->widgetActions.insert(key: action, value: 0);
445 else
446 d_ptr->regularActions.insert(value: action);
447 d_ptr->allActions.insert(value: action);
448 d_ptr->categoryToActions[category].append(t: action);
449 d_ptr->actionToCategory[action] = category;
450}
451
452void QtFullToolBarManager::removeAction(QAction *action)
453{
454 if (!d_ptr->allActions.contains(value: action))
455 return;
456
457 const auto toolBars = d_ptr->actionToToolBars[action];
458 for (QToolBar *toolBar : toolBars) {
459 d_ptr->toolBars[toolBar].removeAll(t: action);
460 d_ptr->toolBarsWithSeparators[toolBar].removeAll(t: action);
461
462 toolBar->removeAction(action);
463 }
464
465 auto itDefault = d_ptr->defaultToolBars.constBegin();
466 while (itDefault != d_ptr->defaultToolBars.constEnd()) {
467 if (itDefault.value().contains(t: action))
468 d_ptr->defaultToolBars[itDefault.key()].removeAll(t: action);
469
470 itDefault++;
471 }
472
473 d_ptr->allActions.remove(value: action);
474 d_ptr->widgetActions.remove(key: action);
475 d_ptr->regularActions.remove(value: action);
476 d_ptr->actionToToolBars.remove(key: action);
477
478 QString category = d_ptr->actionToCategory.value(key: action);
479 d_ptr->actionToCategory.remove(key: action);
480 d_ptr->categoryToActions[category].removeAll(t: action);
481
482 if (d_ptr->categoryToActions[category].isEmpty())
483 d_ptr->categoryToActions.remove(key: category);
484}
485
486QSet<QAction *> QtFullToolBarManager::actions() const
487{
488 return d_ptr->allActions;
489}
490
491bool QtFullToolBarManager::isWidgetAction(QAction *action) const
492{
493 if (d_ptr->widgetActions.contains(key: action))
494 return true;
495 return false;
496}
497
498void QtFullToolBarManager::addDefaultToolBar(QToolBar *toolBar, const QString &category)
499{
500 if (!toolBar)
501 return;
502 if (d_ptr->toolBars.contains(key: toolBar))
503 return;
504 // could be also checked if toolBar belongs to mainwindow
505
506 QList<QAction *> newActionsWithSeparators;
507 QList<QAction *> newActions;
508 const auto actions = toolBar->actions();
509 for (QAction *action : actions) {
510 addAction(action, category);
511 if (d_ptr->widgetActions.contains(key: action))
512 d_ptr->widgetActions.insert(key: action, value: toolBar);
513 newActionsWithSeparators.append(t: action);
514 if (action->isSeparator())
515 action = 0;
516 else
517 d_ptr->actionToToolBars[action].append(t: toolBar);
518 newActions.append(t: action);
519 }
520 d_ptr->defaultToolBars.insert(key: toolBar, value: newActions);
521 //Below could be done by call setToolBar() if we want signal emission here.
522 d_ptr->toolBars.insert(key: toolBar, value: newActions);
523 d_ptr->toolBarsWithSeparators.insert(key: toolBar, value: newActionsWithSeparators);
524}
525
526void QtFullToolBarManager::removeDefaultToolBar(QToolBar *toolBar)
527{
528 if (!d_ptr->defaultToolBars.contains(key: toolBar))
529 return;
530
531 const auto defaultActions = d_ptr->defaultToolBars[toolBar];
532 setToolBar(toolBar, actions: QList<QAction *>());
533 for (QAction *action : defaultActions)
534 removeAction(action);
535
536 d_ptr->toolBars.remove(key: toolBar);
537 d_ptr->toolBarsWithSeparators.remove(key: toolBar);
538 d_ptr->defaultToolBars.remove(key: toolBar);
539
540 for (QAction *action : defaultActions) {
541 if (action)
542 toolBar->insertAction(before: 0, action);
543 else
544 toolBar->insertSeparator(before: 0);
545 }
546}
547
548QHash<QToolBar *, QList<QAction *>> QtFullToolBarManager::defaultToolBars() const
549{
550 return d_ptr->defaultToolBars;
551}
552
553bool QtFullToolBarManager::isDefaultToolBar(QToolBar *toolBar) const
554{
555 if (d_ptr->defaultToolBars.contains(key: toolBar))
556 return true;
557 return false;
558}
559
560QToolBar *QtFullToolBarManager::createToolBar(const QString &toolBarName)
561{
562 if (!mainWindow())
563 return 0;
564 QToolBar *toolBar = new QToolBar(toolBarName, mainWindow());
565 int i = 1;
566 const QString prefix = "_Custom_Toolbar_%1"_L1;
567 QString name = prefix.arg(a: i);
568 while (d_ptr->toolBarByName(toolBarName: name))
569 name = prefix.arg(a: ++i);
570 toolBar->setObjectName(name);
571 mainWindow()->addToolBar(toolbar: toolBar);
572 d_ptr->customToolBars.append(t: toolBar);
573 d_ptr->toolBars.insert(key: toolBar, value: QList<QAction *>());
574 d_ptr->toolBarsWithSeparators.insert(key: toolBar, value: QList<QAction *>());
575 return toolBar;
576}
577
578void QtFullToolBarManager::deleteToolBar(QToolBar *toolBar)
579{
580 if (!d_ptr->toolBars.contains(key: toolBar))
581 return;
582 if (d_ptr->defaultToolBars.contains(key: toolBar))
583 return;
584 setToolBar(toolBar, actions: QList<QAction *>());
585 d_ptr->customToolBars.removeAll(t: toolBar);
586 d_ptr->toolBars.remove(key: toolBar);
587 d_ptr->toolBarsWithSeparators.remove(key: toolBar);
588 delete toolBar;
589}
590
591QList<QAction *> QtFullToolBarManager::actions(QToolBar *toolBar) const
592{
593 if (d_ptr->toolBars.contains(key: toolBar))
594 return d_ptr->toolBars.value(key: toolBar);
595 return QList<QAction *>();
596}
597
598void QtFullToolBarManager::setToolBars(const QHash<QToolBar *, QList<QAction *>> &actions)
599{
600 auto it = actions.constBegin();
601 while (it != actions.constEnd()) {
602 setToolBar(toolBar: it.key(), actions: it.value());
603 ++it;
604 }
605}
606
607void QtFullToolBarManager::setToolBar(QToolBar *toolBar, const QList<QAction *> &actions)
608{
609 if (!toolBar)
610 return;
611 if (!d_ptr->toolBars.contains(key: toolBar))
612 return;
613
614 if (actions == d_ptr->toolBars[toolBar])
615 return;
616
617 QHash<QToolBar *, QList<QAction *>> toRemove;
618
619 QList<QAction *> newActions;
620 for (QAction *action : actions) {
621 if (!action || (!newActions.contains(t: action) && d_ptr->allActions.contains(value: action)))
622 newActions.append(t: action);
623
624 QToolBar *oldToolBar = d_ptr->toolBarWidgetAction(action);
625 if (oldToolBar && oldToolBar != toolBar)
626 toRemove[oldToolBar].append(t: action);
627 }
628
629 d_ptr->removeWidgetActions(actions: toRemove);
630
631 const auto oldActions = d_ptr->toolBarsWithSeparators.value(key: toolBar);
632 for (QAction *action : oldActions) {
633 /*
634 When addDefaultToolBar() separator actions could be checked if they are
635 inserted in other toolbars - if yes then create new one.
636 */
637 if (d_ptr->toolBarWidgetAction(action) == toolBar)
638 d_ptr->widgetActions.insert(key: action, value: 0);
639 toolBar->removeAction(action);
640 if (action->isSeparator())
641 delete action;
642 else
643 d_ptr->actionToToolBars[action].removeAll(t: toolBar);
644 }
645
646 QList<QAction *> newActionsWithSeparators;
647 for (QAction *action : std::as_const(t&: newActions)) {
648 QAction *newAction = nullptr;
649 if (!action)
650 newAction = toolBar->insertSeparator(before: 0);
651 if (d_ptr->allActions.contains(value: action)) {
652 toolBar->insertAction(before: 0, action);
653 newAction = action;
654 d_ptr->actionToToolBars[action].append(t: toolBar);
655 }
656 newActionsWithSeparators.append(t: newAction);
657 }
658 d_ptr->toolBars.insert(key: toolBar, value: newActions);
659 d_ptr->toolBarsWithSeparators.insert(key: toolBar, value: newActionsWithSeparators);
660}
661
662QHash<QToolBar *, QList<QAction *>> QtFullToolBarManager::toolBarsActions() const
663{
664 return d_ptr->toolBars;
665}
666
667void QtFullToolBarManager::resetToolBar(QToolBar *toolBar)
668{
669 if (!isDefaultToolBar(toolBar))
670 return;
671 setToolBar(toolBar, actions: defaultToolBars().value(key: toolBar));
672}
673
674void QtFullToolBarManager::resetAllToolBars()
675{
676 setToolBars(defaultToolBars());
677 const auto oldCustomToolBars = d_ptr->customToolBars;
678 for (QToolBar *tb : oldCustomToolBars)
679 deleteToolBar(toolBar: tb);
680}
681
682QByteArray QtFullToolBarManager::saveState(int version) const
683{
684 QByteArray data;
685 QDataStream stream(&data, QIODevice::WriteOnly);
686 stream << int(QtFullToolBarManagerPrivate::VersionMarker);
687 stream << version;
688 d_ptr->saveState(stream);
689 return data;
690}
691
692bool QtFullToolBarManager::restoreState(const QByteArray &state, int version)
693{
694 QByteArray sd = state;
695 QDataStream stream(&sd, QIODevice::ReadOnly);
696 int marker, v;
697 stream >> marker;
698 stream >> v;
699 if (marker != QtFullToolBarManagerPrivate::VersionMarker || v != version)
700 return false;
701 return d_ptr->restoreState(stream);
702}
703
704
705class QtToolBarManagerPrivate
706{
707 class QtToolBarManager *q_ptr;
708 Q_DECLARE_PUBLIC(QtToolBarManager)
709public:
710 QtFullToolBarManager *manager;
711};
712
713//////////////////////////////////////
714
715/*! \class QtToolBarManager
716 \internal
717 \inmodule QtDesigner
718 \since 4.4
719
720 \brief The QtToolBarManager class provides toolbar management for
721 main windows.
722
723 The QtToolBarManager is typically used with a QtToolBarDialog
724 which allows the user to customize the toolbars for a given main
725 window. The QtToolBarDialog class's functionality is controlled by
726 an instance of the QtToolBarManager class, and the main window is
727 specified using the QtToolBarManager class's setMainWindow()
728 function.
729
730 The currently specified main window can be retrieved using the
731 mainWindow() function.
732
733 The toolbar manager holds lists of the given main window's actions
734 and toolbars, and can add actions and toolbars to these
735 lists using the addAction() and addToolBar() functions
736 respectively. The actions can in addition be categorized
737 acccording to the user's preferences. The toolbar manager can also
738 remove custom actions and toolbars using the removeAction() and
739 removeToolBar() functions.
740
741 Finally, the QtToolBarManager is able to save the customized state
742 of its toolbars using the saveState() function as well as restore
743 the toolbars' saved state using restoreState() function.
744
745 \sa QtToolBarDialog
746*/
747
748/*!
749 Creates a toolbar manager with the given \a parent.
750*/
751QtToolBarManager::QtToolBarManager(QObject *parent)
752 : QObject(parent), d_ptr(new QtToolBarManagerPrivate)
753{
754 d_ptr->q_ptr = this;
755
756 d_ptr->manager = new QtFullToolBarManager(this);
757}
758
759/*!
760 Destroys the toolbar manager.
761*/
762QtToolBarManager::~QtToolBarManager()
763{
764}
765
766/*!
767 Sets the main window upon which the toolbar manager operates, to
768 be the given \a mainWindow.
769*/
770void QtToolBarManager::setMainWindow(QMainWindow *mainWindow)
771{
772 d_ptr->manager->setMainWindow(mainWindow);
773}
774
775/*!
776 Returns the main window associated this toolbar manager.
777*/
778QMainWindow *QtToolBarManager::mainWindow() const
779{
780 return d_ptr->manager->mainWindow();
781}
782
783/*!
784 Adds the given \a action to the given \a category in the manager's
785 list of actions. If the \a category doesn't exist it is created.
786 Only non separator actions can be added. If the action is already
787 added to the list, the function doesn't do anything.
788
789 \sa removeAction()
790*/
791void QtToolBarManager::addAction(QAction *action, const QString &category)
792{
793 d_ptr->manager->addAction(action, category);
794}
795
796/*!
797 Removes the specified \a action from the manager's list of
798 actions. The action is also removed from all the registered
799 toolbars. If the specified \a action is the only action in its
800 category, that category is removed as well.
801
802 \sa addAction()
803*/
804void QtToolBarManager::removeAction(QAction *action)
805{
806 d_ptr->manager->removeAction(action);
807}
808
809/*!
810 Adds the given \a toolBar to the manager's toolbar list.
811
812 All the \a toolBar's actions are automatically added to the given
813 \a category in the manager's list of actions if they're not
814 already there. The manager remembers which toolbar the actions
815 belonged to, so, when the \a toolBar is removed, its actions will
816 be removed as well.
817
818 Custom toolbars are created with the main window returned by
819 the mainWindow() function, as its parent.
820
821 \sa removeToolBar()
822*/
823void QtToolBarManager::addToolBar(QToolBar *toolBar, const QString &category)
824{
825 d_ptr->manager->addDefaultToolBar(toolBar, category);
826}
827
828/*!
829 Removes the specified \a toolBar from the manager's list. All the
830 actions that existed in the specified \a toolBar when it was
831 added are removed as well.
832
833 \sa addToolBar()
834*/
835void QtToolBarManager::removeToolBar(QToolBar *toolBar)
836{
837 d_ptr->manager->removeDefaultToolBar(toolBar);
838}
839
840/*!
841 Returns the manager's toolbar list.
842*/
843QList<QToolBar *> QtToolBarManager::toolBars() const
844{
845 return d_ptr->manager->toolBarsActions().keys();
846}
847
848/*
849void QtToolBarManager::resetToolBar(QToolBar *toolBar)
850{
851 d_ptr->manager->resetToolBar(toolBar);
852}
853
854void QtToolBarManager::resetAllToolBars()
855{
856 d_ptr->manager->resetAllToolBars();
857}
858*/
859
860/*!
861 Saves the state of the toolbar manager's toolbars. The \a version
862 number is stored as part of the data.
863
864 Identifies all the QToolBar and QAction objects by their object
865 name property. Ensure that this property is unique for each
866 QToolBar and QAction that you add using the QtToolBarManager.
867
868 Returns an identifier for the state which can be passed along with
869 the version number to the restoreState() function to restore the
870 saved state.
871
872 \sa restoreState()
873*/
874QByteArray QtToolBarManager::saveState(int version) const
875{
876 return d_ptr->manager->saveState(version);
877}
878
879/*!
880 Restores the saved state of the toolbar manager's toolbars. The
881 \a version number is compared with the version number of the
882 stored \a state.
883
884 Returns true if the version numbers are matching and the toolbar
885 manager's state is restored; otherwise the toolbar manager's state
886 is left unchanged and the function returns false.
887
888 Note that the state of the toolbar manager's toolbars should be
889 restored before restoring the state of the main window's toolbars
890 and dockwidgets using the QMainWindow::restoreState() function. In
891 that way the restoreState() function can create the custom
892 toolbars before the QMainWindow::restoreState() function restores
893 the custom toolbars' positions.
894
895 \sa saveState()
896*/
897bool QtToolBarManager::restoreState(const QByteArray &state, int version)
898{
899 return d_ptr->manager->restoreState(state, version);
900}
901
902//////////////////////
903
904class ToolBarItem {
905public:
906 ToolBarItem() : tb(0) {}
907 ToolBarItem(QToolBar *toolBar) : tb(toolBar) {}
908 ToolBarItem(QToolBar *toolBar, const QString &toolBarName)
909 : tb(toolBar), tbName(toolBarName) {}
910 ToolBarItem(const QString &toolBarName) : tb(0), tbName(toolBarName) {}
911 QToolBar *toolBar() const
912 { return tb; }
913 void setToolBar(QToolBar *toolBar)
914 { tb = toolBar; }
915 QString toolBarName() const
916 { return tbName; }
917 void setToolBarName(const QString &toolBarName)
918 { tbName = toolBarName; }
919private:
920 QToolBar *tb;
921 QString tbName;
922};
923
924class QtToolBarDialogPrivate {
925 QtToolBarDialog *q_ptr;
926 Q_DECLARE_PUBLIC(QtToolBarDialog)
927public:
928 QtToolBarDialogPrivate()
929 : toolBarManager(0),
930 currentAction(0),
931 currentToolBar(0)
932 { }
933
934 ToolBarItem *createItem(QToolBar *toolBar);
935 ToolBarItem *createItem(const QString &toolBarName);
936 void deleteItem(ToolBarItem *item);
937
938 void newClicked();
939 void removeClicked();
940 void defaultClicked();
941 void okClicked();
942 void applyClicked();
943 void cancelClicked();
944 void upClicked();
945 void downClicked();
946 void leftClicked();
947 void rightClicked();
948 void renameClicked();
949 void toolBarRenamed(QListWidgetItem *item);
950 void currentActionChanged(QTreeWidgetItem *current);
951 void currentToolBarChanged(QListWidgetItem *current);
952 void currentToolBarActionChanged(QListWidgetItem *current);
953
954 void removeToolBar(ToolBarItem *item);
955 bool isDefaultToolBar(ToolBarItem *item) const;
956 void setButtons();
957 void clearOld();
958 void fillNew();
959 QtFullToolBarManager *toolBarManager;
960 QHash<ToolBarItem *, QList<QAction *>> currentState;
961 QHash<QToolBar *, ToolBarItem *> toolBarItems;
962 QSet<ToolBarItem *> createdItems;
963 QSet<ToolBarItem *> removedItems;
964
965 QSet<ToolBarItem *> allToolBarItems;
966
967 // static
968 QTreeWidgetItem *currentAction;
969 QHash<QAction *, QTreeWidgetItem *> actionToItem;
970 QHash<QTreeWidgetItem *, QAction *> itemToAction;
971
972 // dynamic
973 ToolBarItem *currentToolBar;
974 QHash<ToolBarItem *, QListWidgetItem *> toolBarToItem;
975 QHash<QListWidgetItem *, ToolBarItem *> itemToToolBar;
976
977 // dynamic
978 QHash<QAction *, QListWidgetItem *> actionToCurrentItem;
979 QHash<QListWidgetItem *, QAction *> currentItemToAction;
980
981 QHash<QAction *, ToolBarItem *> widgetActionToToolBar;
982 QHash<ToolBarItem *, QSet<QAction *>> toolBarToWidgetActions;
983
984 QString separatorText;
985 Ui::QtToolBarDialog ui;
986};
987
988ToolBarItem *QtToolBarDialogPrivate::createItem(QToolBar *toolBar)
989{
990 if (!toolBar)
991 return 0;
992 ToolBarItem *item = new ToolBarItem(toolBar, toolBar->windowTitle());
993 allToolBarItems.insert(value: item);
994 return item;
995}
996
997ToolBarItem *QtToolBarDialogPrivate::createItem(const QString &toolBarName)
998{
999 ToolBarItem *item = new ToolBarItem(toolBarName);
1000 allToolBarItems.insert(value: item);
1001 return item;
1002}
1003
1004void QtToolBarDialogPrivate::deleteItem(ToolBarItem *item)
1005{
1006 if (!allToolBarItems.contains(value: item))
1007 return;
1008 allToolBarItems.remove(value: item);
1009 delete item;
1010}
1011
1012void QtToolBarDialogPrivate::clearOld()
1013{
1014 ui.actionTree->clear();
1015 ui.toolBarList->clear();
1016 ui.currentToolBarList->clear();
1017 ui.removeButton->setEnabled(false);
1018 ui.newButton->setEnabled(false);
1019 ui.upButton->setEnabled(false);
1020 ui.downButton->setEnabled(false);
1021 ui.leftButton->setEnabled(false);
1022 ui.rightButton->setEnabled(false);
1023
1024 actionToItem.clear();
1025 itemToAction.clear();
1026 toolBarToItem.clear();
1027 itemToToolBar.clear();
1028 actionToCurrentItem.clear();
1029 currentItemToAction.clear();
1030 widgetActionToToolBar.clear();
1031 toolBarToWidgetActions.clear();
1032
1033 toolBarItems.clear();
1034 currentState.clear();
1035 createdItems.clear();
1036 removedItems.clear();
1037 qDeleteAll(c: allToolBarItems);
1038 allToolBarItems.clear();
1039
1040 currentToolBar = nullptr;
1041 currentAction = nullptr;
1042}
1043
1044void QtToolBarDialogPrivate::fillNew()
1045{
1046 if (!toolBarManager)
1047 return;
1048
1049 QTreeWidgetItem *item = new QTreeWidgetItem(ui.actionTree);
1050 item->setText(0, separatorText);
1051 ui.actionTree->setCurrentItem(item);
1052 currentAction = item;
1053 actionToItem.insert(0, item);
1054 itemToAction.insert(item, 0);
1055 const QStringList categories = toolBarManager->categories();
1056 for (const QString &category : categories) {
1057 QTreeWidgetItem *categoryItem = new QTreeWidgetItem(ui.actionTree);
1058 categoryItem->setText(0, category);
1059 const auto actions = toolBarManager->categoryActions(category);
1060 for (QAction *action : actions) {
1061 item = new QTreeWidgetItem(categoryItem);
1062 item->setText(0, action->text());
1063 item->setIcon(0, action->icon());
1064 item->setTextAlignment(0, Qt::Alignment(Qt::AlignLeft | Qt::AlignVCenter | Qt::TextShowMnemonic));
1065 actionToItem.insert(action, item);
1066 itemToAction.insert(item, action);
1067 if (toolBarManager->isWidgetAction(action)) {
1068 item->setData(0, Qt::ForegroundRole, QColor(Qt::blue));
1069 widgetActionToToolBar.insert(key: action, value: 0);
1070 }
1071 item->setFlags(item->flags() | Qt::ItemIsDragEnabled);
1072 }
1073 categoryItem->setExpanded(true);
1074 }
1075 //ui.actionTree->sortItems(0, Qt::AscendingOrder);
1076
1077 const auto toolBars = toolBarManager->toolBarsActions();
1078 auto it = toolBars.constBegin();
1079 while (it != toolBars.constEnd()) {
1080 QToolBar *toolBar = it.key();
1081 ToolBarItem *tbItem = createItem(toolBar);
1082 toolBarItems.insert(key: toolBar, value: tbItem);
1083 QListWidgetItem *item = new QListWidgetItem(toolBar->windowTitle(),
1084 ui.toolBarList);
1085 toolBarToItem.insert(tbItem, item);
1086 itemToToolBar.insert(item, tbItem);
1087 const auto actions = it.value();
1088 for (QAction *action : actions) {
1089 if (toolBarManager->isWidgetAction(action)) {
1090 widgetActionToToolBar.insert(key: action, value: tbItem);
1091 toolBarToWidgetActions[tbItem].insert(value: action);
1092 }
1093 }
1094 currentState.insert(key: tbItem, value: actions);
1095 if (it == toolBars.constBegin())
1096 ui.toolBarList->setCurrentItem(item);
1097 if (isDefaultToolBar(item: tbItem))
1098 item->setData(Qt::ForegroundRole, QColor(Qt::darkGreen));
1099 else
1100 item->setFlags(item->flags() | Qt::ItemIsEditable);
1101
1102 ++it;
1103 }
1104 ui.toolBarList->sortItems();
1105 setButtons();
1106}
1107
1108bool QtToolBarDialogPrivate::isDefaultToolBar(ToolBarItem *item) const
1109{
1110 if (!item)
1111 return false;
1112 if (!item->toolBar())
1113 return false;
1114 return toolBarManager->isDefaultToolBar(toolBar: item->toolBar());
1115}
1116
1117void QtToolBarDialogPrivate::setButtons()
1118{
1119 bool newEnabled = false;
1120 bool removeEnabled = false;
1121 bool renameEnabled = false;
1122 bool upEnabled = false;
1123 bool downEnabled = false;
1124 bool leftEnabled = false;
1125 bool rightEnabled = false;
1126
1127 if (toolBarManager) {
1128 newEnabled = true;
1129 removeEnabled = !isDefaultToolBar(item: currentToolBar);
1130 renameEnabled = removeEnabled;
1131 QListWidgetItem *currentToolBarAction = ui.currentToolBarList->currentItem();
1132 if (currentToolBarAction) {
1133 int row = ui.currentToolBarList->row(currentToolBarAction);
1134 upEnabled = row > 0;
1135 downEnabled = row < ui.currentToolBarList->count() - 1;
1136 leftEnabled = true;
1137 }
1138 if (currentAction && currentToolBar)
1139 rightEnabled = true;
1140 }
1141 ui.newButton->setEnabled(newEnabled);
1142 ui.removeButton->setEnabled(removeEnabled);
1143 ui.renameButton->setEnabled(renameEnabled);
1144 ui.upButton->setEnabled(upEnabled);
1145 ui.downButton->setEnabled(downEnabled);
1146 ui.leftButton->setEnabled(leftEnabled);
1147 ui.rightButton->setEnabled(rightEnabled);
1148}
1149
1150void QtToolBarDialogPrivate::newClicked()
1151{
1152 QString toolBarName = QtToolBarDialog::tr(s: "Custom Toolbar"); // = QInputDialog::getString();
1153 // produce unique name
1154 ToolBarItem *item = createItem(toolBarName);
1155 currentState.insert(key: item, value: QList<QAction *>());
1156 createdItems.insert(value: item);
1157 QListWidgetItem *i = new QListWidgetItem(toolBarName, ui.toolBarList);
1158 i->setFlags(i->flags() | Qt::ItemIsEditable);
1159 ui.toolBarList->setCurrentItem(i);
1160 itemToToolBar.insert(i, item);
1161 toolBarToItem.insert(item, i);
1162 ui.toolBarList->sortItems();
1163 ui.toolBarList->setCurrentItem(i);
1164 currentToolBarChanged(i);
1165 renameClicked();
1166}
1167
1168void QtToolBarDialogPrivate::removeToolBar(ToolBarItem *item)
1169{
1170 if (!item)
1171 return;
1172 if (item->toolBar() && toolBarManager->isDefaultToolBar(toolBar: item->toolBar()))
1173 return;
1174 if (!toolBarToItem.contains(item))
1175 return;
1176 QListWidgetItem *i = toolBarToItem.value(item);
1177 bool wasCurrent = false;
1178 if (i == ui.toolBarList->currentItem())
1179 wasCurrent = true;
1180 int row = ui.toolBarList->row(i);
1181 const auto itToolBar = toolBarToWidgetActions.find(key: item);
1182 if (itToolBar != toolBarToWidgetActions.end()) {
1183 for (QAction *action : std::as_const(t&: itToolBar.value()))
1184 widgetActionToToolBar.insert(key: action, value: 0);
1185 toolBarToWidgetActions.erase(it: itToolBar);
1186 }
1187
1188 currentState.remove(key: item);
1189 createdItems.remove(value: item);
1190 toolBarToItem.remove(item);
1191 itemToToolBar.remove(i);
1192 delete i;
1193 if (item->toolBar())
1194 removedItems.insert(value: item);
1195 else
1196 deleteItem(item);
1197 if (wasCurrent) {
1198 if (row == ui.toolBarList->count())
1199 row--;
1200 if (row < 0)
1201 ;
1202 else
1203 ui.toolBarList->setCurrentRow(row);
1204 }
1205 setButtons();
1206}
1207
1208void QtToolBarDialogPrivate::removeClicked()
1209{
1210 QListWidgetItem *i = ui.toolBarList->currentItem();
1211 if (!i)
1212 return;
1213 ToolBarItem *item = itemToToolBar.value(i);
1214 removeToolBar(item);
1215}
1216
1217void QtToolBarDialogPrivate::defaultClicked()
1218{
1219 const auto defaultToolBars = toolBarManager->defaultToolBars();
1220 auto itToolBar = defaultToolBars.constBegin();
1221 while (itToolBar != defaultToolBars.constEnd()) {
1222 QToolBar *toolBar = itToolBar.key();
1223 ToolBarItem *toolBarItem = toolBarItems.value(key: toolBar);
1224
1225 const auto tbwit = toolBarToWidgetActions.find(key: toolBarItem);
1226 if (tbwit != toolBarToWidgetActions.end()) {
1227 for (QAction *action : std::as_const(t&: tbwit.value()))
1228 widgetActionToToolBar.insert(key: action, value: 0);
1229 toolBarToWidgetActions.erase(it: tbwit);
1230 }
1231
1232 currentState.remove(key: toolBarItem);
1233
1234 for (QAction *action : itToolBar.value()) {
1235 if (toolBarManager->isWidgetAction(action)) {
1236 ToolBarItem *otherToolBar = widgetActionToToolBar.value(key: action);
1237 if (otherToolBar) {
1238 toolBarToWidgetActions[otherToolBar].remove(value: action);
1239 currentState[otherToolBar].removeAll(t: action);
1240 }
1241 widgetActionToToolBar.insert(key: action, value: toolBarItem);
1242 toolBarToWidgetActions[toolBarItem].insert(value: action);
1243 }
1244 }
1245 currentState.insert(key: toolBarItem, value: itToolBar.value());
1246
1247 ++itToolBar;
1248 }
1249 currentToolBarChanged(toolBarToItem.value(currentToolBar));
1250
1251 const auto toolBars = currentState.keys();
1252 for (ToolBarItem *tb : toolBars)
1253 removeToolBar(item: tb);
1254}
1255
1256void QtToolBarDialogPrivate::okClicked()
1257{
1258 applyClicked();
1259 q_ptr->accept();
1260}
1261
1262void QtToolBarDialogPrivate::applyClicked()
1263{
1264 const auto toolBars = currentState;
1265 auto itToolBar = toolBars.constBegin();
1266 while (itToolBar != toolBars.constEnd()) {
1267 ToolBarItem *item = itToolBar.key();
1268 QToolBar *toolBar = item->toolBar();
1269 if (toolBar) {
1270 toolBarManager->setToolBar(toolBar, actions: itToolBar.value());
1271 toolBar->setWindowTitle(item->toolBarName());
1272 }
1273
1274 ++itToolBar;
1275 }
1276
1277 const QSet<ToolBarItem *> toRemove = removedItems;
1278 for (ToolBarItem *item : toRemove) {
1279 QToolBar *toolBar = item->toolBar();
1280 removedItems.remove(value: item);
1281 currentState.remove(key: item);
1282 deleteItem(item);
1283 if (toolBar)
1284 toolBarManager->deleteToolBar(toolBar);
1285 }
1286
1287 const QSet<ToolBarItem *> toCreate = createdItems;
1288 for (ToolBarItem *item : toCreate) {
1289 QString toolBarName = item->toolBarName();
1290 createdItems.remove(value: item);
1291 const auto actions = currentState.value(key: item);
1292 QToolBar *toolBar = toolBarManager->createToolBar(toolBarName);
1293 item->setToolBar(toolBar);
1294 toolBarManager->setToolBar(toolBar, actions);
1295 }
1296}
1297
1298void QtToolBarDialogPrivate::upClicked()
1299{
1300 QListWidgetItem *currentToolBarAction = ui.currentToolBarList->currentItem();
1301 if (!currentToolBarAction)
1302 return;
1303 int row = ui.currentToolBarList->row(currentToolBarAction);
1304 if (row == 0)
1305 return;
1306 ui.currentToolBarList->takeItem(row);
1307 int newRow = row - 1;
1308 ui.currentToolBarList->insertItem(newRow, currentToolBarAction);
1309 auto actions = currentState.value(key: currentToolBar);
1310 QAction *action = actions.at(i: row);
1311 actions.removeAt(i: row);
1312 actions.insert(i: newRow, t: action);
1313 currentState.insert(key: currentToolBar, value: actions);
1314 ui.currentToolBarList->setCurrentItem(currentToolBarAction);
1315 setButtons();
1316}
1317
1318void QtToolBarDialogPrivate::downClicked()
1319{
1320 QListWidgetItem *currentToolBarAction = ui.currentToolBarList->currentItem();
1321 if (!currentToolBarAction)
1322 return;
1323 int row = ui.currentToolBarList->row(currentToolBarAction);
1324 if (row == ui.currentToolBarList->count() - 1)
1325 return;
1326 ui.currentToolBarList->takeItem(row);
1327 int newRow = row + 1;
1328 ui.currentToolBarList->insertItem(newRow, currentToolBarAction);
1329 auto actions = currentState.value(key: currentToolBar);
1330 QAction *action = actions.at(i: row);
1331 actions.removeAt(i: row);
1332 actions.insert(i: newRow, t: action);
1333 currentState.insert(key: currentToolBar, value: actions);
1334 ui.currentToolBarList->setCurrentItem(currentToolBarAction);
1335 setButtons();
1336}
1337
1338void QtToolBarDialogPrivate::leftClicked()
1339{
1340 QListWidgetItem *currentToolBarAction = ui.currentToolBarList->currentItem();
1341 if (!currentToolBarAction)
1342 return;
1343 int row = ui.currentToolBarList->row(currentToolBarAction);
1344 currentState[currentToolBar].removeAt(i: row);
1345 QAction *action = currentItemToAction.value(currentToolBarAction);
1346 if (widgetActionToToolBar.contains(key: action)) {
1347 ToolBarItem *item = widgetActionToToolBar.value(key: action);
1348 if (item == currentToolBar) { // have to be
1349 toolBarToWidgetActions[item].remove(value: action);
1350 if (toolBarToWidgetActions[item].isEmpty())
1351 toolBarToWidgetActions.remove(key: item);
1352 }
1353 widgetActionToToolBar.insert(key: action, value: 0);
1354 }
1355 if (action)
1356 actionToCurrentItem.remove(action);
1357 currentItemToAction.remove(currentToolBarAction);
1358 delete currentToolBarAction;
1359 if (row == ui.currentToolBarList->count())
1360 row--;
1361 if (row >= 0) {
1362 QListWidgetItem *item = ui.currentToolBarList->item(row);
1363 ui.currentToolBarList->setCurrentItem(item);
1364 }
1365 setButtons();
1366}
1367
1368void QtToolBarDialogPrivate::rightClicked()
1369{
1370 if (!currentAction)
1371 return;
1372 if (!currentToolBar)
1373 return;
1374 QListWidgetItem *currentToolBarAction = ui.currentToolBarList->currentItem();
1375
1376 QAction *action = itemToAction.value(currentAction);
1377 QListWidgetItem *item = nullptr;
1378 if (action) {
1379 if (currentState[currentToolBar].contains(t: action)) {
1380 item = actionToCurrentItem.value(action);
1381 if (item == currentToolBarAction)
1382 return;
1383 int row = ui.currentToolBarList->row(item);
1384 ui.currentToolBarList->takeItem(row);
1385 currentState[currentToolBar].removeAt(i: row);
1386 // only reorder here
1387 } else {
1388 item = new QListWidgetItem(action->text());
1389 item->setIcon(action->icon());
1390 item->setTextAlignment(Qt::Alignment(Qt::AlignLeft | Qt::AlignVCenter | Qt::TextShowMnemonic));
1391 currentItemToAction.insert(item, action);
1392 actionToCurrentItem.insert(action, item);
1393 if (widgetActionToToolBar.contains(key: action)) {
1394 item->setData(Qt::ForegroundRole, QColor(Qt::blue));
1395 ToolBarItem *toolBar = widgetActionToToolBar.value(key: action);
1396 if (toolBar) {
1397 currentState[toolBar].removeAll(t: action);
1398 toolBarToWidgetActions[toolBar].remove(value: action);
1399 if (toolBarToWidgetActions[toolBar].isEmpty())
1400 toolBarToWidgetActions.remove(key: toolBar);
1401 }
1402 widgetActionToToolBar.insert(key: action, value: currentToolBar);
1403 toolBarToWidgetActions[currentToolBar].insert(value: action);
1404 }
1405 }
1406 } else {
1407 item = new QListWidgetItem(separatorText);
1408 currentItemToAction.insert(item, 0);
1409 }
1410
1411 int row = ui.currentToolBarList->count();
1412 if (currentToolBarAction) {
1413 row = ui.currentToolBarList->row(currentToolBarAction) + 1;
1414 }
1415 ui.currentToolBarList->insertItem(row, item);
1416 currentState[currentToolBar].insert(i: row, t: action);
1417 ui.currentToolBarList->setCurrentItem(item);
1418
1419 setButtons();
1420}
1421
1422void QtToolBarDialogPrivate::renameClicked()
1423{
1424 if (!currentToolBar)
1425 return;
1426
1427 QListWidgetItem *item = toolBarToItem.value(currentToolBar);
1428 ui.toolBarList->editItem(item);
1429}
1430
1431void QtToolBarDialogPrivate::toolBarRenamed(QListWidgetItem *item)
1432{
1433 if (!currentToolBar)
1434 return;
1435
1436 ToolBarItem *tbItem = itemToToolBar.value(item);
1437 if (!tbItem)
1438 return;
1439 tbItem->setToolBarName(item->text());
1440 //ui.toolBarList->sortItems();
1441}
1442
1443void QtToolBarDialogPrivate::currentActionChanged(QTreeWidgetItem *current)
1444{
1445 if (itemToAction.contains(current))
1446 currentAction = current;
1447 else
1448 currentAction = NULL;
1449 setButtons();
1450}
1451
1452void QtToolBarDialogPrivate::currentToolBarChanged(QListWidgetItem *current)
1453{
1454 currentToolBar = itemToToolBar.value(current);
1455 ui.currentToolBarList->clear();
1456 actionToCurrentItem.clear();
1457 currentItemToAction.clear();
1458 setButtons();
1459 if (!currentToolBar) {
1460 return;
1461 }
1462 const auto actions = currentState.value(key: currentToolBar);
1463 QListWidgetItem *first = nullptr;
1464 for (QAction *action : actions) {
1465 QString actionName = separatorText;
1466 if (action)
1467 actionName = action->text();
1468 QListWidgetItem *item = new QListWidgetItem(actionName, ui.currentToolBarList);
1469 if (action) {
1470 item->setIcon(action->icon());
1471 item->setTextAlignment(Qt::Alignment(Qt::AlignLeft | Qt::AlignVCenter | Qt::TextShowMnemonic));
1472 actionToCurrentItem.insert(action, item);
1473 if (widgetActionToToolBar.contains(key: action))
1474 item->setData(Qt::ForegroundRole, QColor(Qt::blue));
1475 }
1476 currentItemToAction.insert(item, action);
1477 if (!first)
1478 first = item;
1479 }
1480 if (first)
1481 ui.currentToolBarList->setCurrentItem(first);
1482}
1483
1484void QtToolBarDialogPrivate::currentToolBarActionChanged(QListWidgetItem *)
1485{
1486 setButtons();
1487}
1488
1489void QtToolBarDialogPrivate::cancelClicked()
1490{
1491 // just nothing
1492 q_ptr->reject();
1493}
1494
1495//////////////////////
1496/*
1497class FeedbackItemDelegate : public QItemDelegate
1498{
1499 Q_OBJECT
1500public:
1501 FeedbackItemDelegate(QObject *parent = 0) : QItemDelegate(parent) { }
1502
1503 virtual void paint(QPainter *painter, const QStyleOptionViewItem &option,
1504 const QModelIndex & index) const;
1505 virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
1506};
1507
1508void FeedbackItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
1509 const QModelIndex &index) const
1510{
1511 if ()
1512 painter->save();
1513 QRect r = option.rect;
1514 float yCentral = r.height() / 2.0;
1515 float margin = 2.0;
1516 float arrowWidth = 5.0;
1517 float width = 20;
1518 qDebug("rect: x %d, y %d, w %d, h %d", r.x(), r.y(), r.width(), r.height());
1519 QLineF lineBase(0.0 + margin, r.y() + yCentral, width - margin, r.y() + yCentral);
1520 QLineF lineArrowLeft(width - margin - arrowWidth, r.y() + yCentral - arrowWidth,
1521 width - margin, r.y() + yCentral);
1522 QLineF lineArrowRight(width - margin - arrowWidth, r.y() + yCentral + arrowWidth,
1523 width - margin, r.y() + yCentral);
1524 painter->drawLine(lineBase);
1525 painter->drawLine(lineArrowLeft);
1526 painter->drawLine(lineArrowRight);
1527 painter->translate(QPoint(width, 0));
1528 QItemDelegate::paint(painter, option, index);
1529 painter->restore();
1530}
1531
1532QSize FeedbackItemDelegate::sizeHint(const QStyleOptionViewItem &option,
1533 const QModelIndex &index) const
1534{
1535 //return QItemDelegate::sizeHint(option, index);
1536 QSize s = QItemDelegate::sizeHint(option, index);
1537 s.setWidth(s.width() - 20);
1538 return s;
1539}
1540
1541class QtToolBarListWidget : public QListWidget
1542{
1543 Q_OBJECT
1544public:
1545 QtToolBarListWidget(QWidget *parent) : QListWidget(parent), actionDrag(false) {}
1546
1547protected:
1548 void startDrag(Qt::DropActions supportedActions);
1549
1550 void dragEnterEvent(QDragEnterEvent *event);
1551 void dragMoveEvent(QDragMoveEvent *event);
1552 void dragLeaveEvent(QDragLeaveEvent *);
1553 void dropEvent(QDropEvent *event);
1554
1555 void setDragAction(const QString *action) { actionName = action; }
1556private:
1557 QPersistentModelIndex lastDropIndicator;
1558 QString actionName;
1559 bool actionDrag;
1560};
1561
1562void QtToolBarListWidget::startDrag(Qt::DropActions supportedActions)
1563{
1564 QListWidgetItem *item = currentItem();
1565 if (item) {
1566 actionName = QString();
1567 emit aboutToDrag(item);
1568 if (!actionName.isEmpty()) {
1569 QDrag *drag = new QDrag(this);
1570 QMimeData *data = new QMimeData;
1571 data->setData("action", actionName.toLocal8Bit().constData());
1572 drag->setMimeData(data);
1573 drag->exec(supportedActions);
1574 }
1575 }
1576}
1577
1578void QtToolBarListWidget::dragEnterEvent(QDragEnterEvent *event)
1579{
1580 const QMimeData *mime = event->mimeData();
1581 actionDrag = mime->hasFormat("action");
1582 if (actionDrag)
1583 event->accept();
1584 else
1585 event->ignore();
1586}
1587
1588void QtToolBarListWidget::dragMoveEvent(QDragMoveEvent *event)
1589{
1590 event->ignore();
1591 if (actionDrag) {
1592 QPoint p = event->pos();
1593 QListWidgetItem *item = itemAt(p);
1594 Indicator indic = QtToolBarListWidget::None;
1595 if (item) {
1596 QRect rect = visualItemRect(item);
1597 if (p.y() - rect.top() < rect.height() / 2)
1598 indic = QtToolBarListWidget::Above;
1599 else
1600 indic = QtToolBarListWidget::Below;
1601 }
1602 setIndicator(item, indic);
1603 event->accept();
1604 }
1605}
1606
1607void QtToolBarListWidget::dragLeaveEvent(QDragLeaveEvent *)
1608{
1609 if (actionDrag) {
1610 actionDrag = false;
1611 setIndicator(item, QtToolBarListWidget::None);
1612 }
1613}
1614
1615void QtToolBarListWidget::dropEvent(QDropEvent *event)
1616{
1617 if (actionDrag) {
1618 QListWidgetItem *item = indicatorItem();
1619 Indicator indic = indicator();
1620 QByteArray array = event->mimeData()->data("action");
1621 QDataStream stream(&array, QIODevice::ReadOnly);
1622 QString action;
1623 stream >> action;
1624 emit actionDropped(action, item, );
1625
1626 actionDrag = false;
1627 setIndicator(item, QtToolBarListWidget::None);
1628 }
1629}
1630*/
1631
1632/*! \class QtToolBarDialog
1633 \internal
1634 \inmodule QtDesigner
1635 \since 4.4
1636
1637 \brief The QtToolBarDialog class provides a dialog for customizing
1638 toolbars.
1639
1640 QtToolBarDialog allows the user to customize the toolbars for a
1641 given main window.
1642
1643 \image qttoolbardialog.png
1644
1645 The dialog lets the users add, rename and remove custom toolbars.
1646 Note that built-in toolbars are marked with a green color, and
1647 cannot be removed or renamed.
1648
1649 The users can also add and remove actions from the toolbars. An
1650 action can be added to many toolbars, but a toolbar can only
1651 contain one instance of each action. Actions that contains a
1652 widget are marked with a blue color in the list of actions, and
1653 can only be added to one single toolbar.
1654
1655 Finally, the users can add separators to the toolbars.
1656
1657 The original toolbars can be restored by clicking the \gui
1658 {Restore all} button. All custom toolbars will then be removed,
1659 and all built-in toolbars will be restored to their original state.
1660
1661 The QtToolBarDialog class's functionality is controlled by an
1662 instance of the QtToolBarManager class, and the main window is
1663 specified using the QtToolBarManager::setMainWindow() function.
1664
1665 All you need to do to use QtToolBarDialog is to specify an
1666 QtToolBarManager instance and call the QDialog::exec() slot:
1667
1668 \snippet doc/src/snippets/code/tools_shared_qttoolbardialog_qttoolbardialog.cpp 0
1669
1670 \sa QtToolBarManager
1671*/
1672
1673/*!
1674 Creates a toolbar dialog with the given \a parent and the specified
1675 window \a flags.
1676*/
1677QtToolBarDialog::QtToolBarDialog(QWidget *parent, Qt::WindowFlags flags)
1678 : QDialog(parent, flags), d_ptr(new QtToolBarDialogPrivate)
1679{
1680 d_ptr->q_ptr = this;
1681 d_ptr->ui.setupUi(this);
1682 d_ptr->separatorText = tr(s: "< S E P A R A T O R >");
1683
1684 d_ptr->ui.actionTree->setColumnCount(1);
1685 d_ptr->ui.actionTree->setRootIsDecorated(false);
1686 d_ptr->ui.actionTree->header()->hide();
1687
1688 d_ptr->ui.upButton->setIcon(QIcon(":/qt-project.org/qttoolbardialog/images/up.png"_L1));
1689 d_ptr->ui.downButton->setIcon(QIcon(":/qt-project.org/qttoolbardialog/images/down.png"_L1));
1690 d_ptr->ui.leftButton->setIcon(QIcon(":/qt-project.org/qttoolbardialog/images/back.png"_L1));
1691 d_ptr->ui.rightButton->setIcon(QIcon(":/qt-project.org/qttoolbardialog/images/forward.png"_L1));
1692 d_ptr->ui.newButton->setIcon(QIcon(":/qt-project.org/qttoolbardialog/images/plus.png"_L1));
1693 d_ptr->ui.removeButton->setIcon(QIcon(":/qt-project.org/qttoolbardialog/images/minus.png"_L1));
1694
1695 connect(d_ptr->ui.newButton, &QAbstractButton::clicked, this, [this] { d_ptr->newClicked(); });
1696 connect(d_ptr->ui.removeButton, &QAbstractButton::clicked, this, [this] { d_ptr->removeClicked(); });
1697 connect(d_ptr->ui.renameButton, &QAbstractButton::clicked, this, [this] { d_ptr->renameClicked(); });
1698 connect(d_ptr->ui.upButton, &QAbstractButton::clicked, this, [this] { d_ptr->upClicked(); });
1699 connect(d_ptr->ui.downButton, &QAbstractButton::clicked, this, [this] { d_ptr->downClicked(); });
1700 connect(d_ptr->ui.leftButton, &QAbstractButton::clicked, this, [this] { d_ptr->leftClicked(); });
1701 connect(d_ptr->ui.rightButton, &QAbstractButton::clicked, this, [this] { d_ptr->rightClicked(); });
1702
1703 connect(d_ptr->ui.buttonBox->button(QDialogButtonBox::RestoreDefaults),
1704 &QAbstractButton::clicked, this, [this] { d_ptr->defaultClicked(); });
1705 connect(d_ptr->ui.buttonBox->button(QDialogButtonBox::Ok),
1706 &QAbstractButton::clicked, this, [this] { d_ptr->okClicked(); });
1707 connect(d_ptr->ui.buttonBox->button(QDialogButtonBox::Apply),
1708 &QAbstractButton::clicked, this, [this] { d_ptr->applyClicked(); });
1709 connect(d_ptr->ui.buttonBox->button(QDialogButtonBox::Cancel),
1710 &QAbstractButton::clicked, this, [this] { d_ptr->cancelClicked(); });
1711
1712 connect(d_ptr->ui.actionTree, &QTreeWidget::currentItemChanged,
1713 this, [this](QTreeWidgetItem *current) { d_ptr->currentActionChanged(current); });
1714 connect(d_ptr->ui.currentToolBarList, &QListWidget::currentItemChanged,
1715 this, [this](QListWidgetItem *current) { d_ptr->currentToolBarActionChanged(current); });
1716 connect(d_ptr->ui.toolBarList, &QListWidget::currentItemChanged,
1717 this, [this](QListWidgetItem *current) { d_ptr->currentToolBarChanged(current); });
1718
1719 connect(d_ptr->ui.actionTree, &QTreeWidget::itemDoubleClicked,
1720 this, [this] { d_ptr->rightClicked(); });
1721 connect(d_ptr->ui.currentToolBarList, &QListWidget::itemDoubleClicked,
1722 this, [this] { d_ptr->leftClicked(); });
1723 connect(d_ptr->ui.toolBarList, &QListWidget::itemChanged,
1724 this, [this](QListWidgetItem *current) { d_ptr->toolBarRenamed(current); });
1725}
1726
1727/*!
1728 Destroys the toolbar dialog.
1729*/
1730QtToolBarDialog::~QtToolBarDialog()
1731{
1732 d_ptr->clearOld();
1733}
1734
1735/*!
1736 Connects the toolbar dialog to the given \a toolBarManager. Then,
1737 when exec() is called, the toolbar dialog will operate using the
1738 given \a toolBarManager.
1739*/
1740void QtToolBarDialog::setToolBarManager(QtToolBarManager *toolBarManager)
1741{
1742 if (d_ptr->toolBarManager == toolBarManager->d_ptr->manager)
1743 return;
1744 if (isVisible())
1745 d_ptr->clearOld();
1746 d_ptr->toolBarManager = toolBarManager->d_ptr->manager;
1747 if (isVisible())
1748 d_ptr->fillNew();
1749}
1750
1751/*!
1752 \reimp
1753*/
1754void QtToolBarDialog::showEvent(QShowEvent *event)
1755{
1756 if (!event->spontaneous())
1757 d_ptr->fillNew();
1758}
1759
1760/*!
1761 \reimp
1762*/
1763void QtToolBarDialog::hideEvent(QHideEvent *event)
1764{
1765 if (!event->spontaneous())
1766 d_ptr->clearOld();
1767}
1768
1769QT_END_NAMESPACE
1770
1771#include "moc_qttoolbardialog.cpp"
1772#include "qttoolbardialog.moc"
1773

source code of qttools/src/shared/qttoolbardialog/qttoolbardialog.cpp