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

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