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 Qt Designer of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
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 General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29#include "qdesigner_toolbox_p.h"
30#include "qdesigner_command_p.h"
31#include "orderdialog_p.h"
32#include "promotiontaskmenu_p.h"
33#include "formwindowbase_p.h"
34
35#include <QtDesigner/abstractformwindow.h>
36
37#include <QtWidgets/qaction.h>
38#include <QtWidgets/qtoolbox.h>
39#include <QtWidgets/qmenu.h>
40#include <QtWidgets/qlayout.h>
41#include <QtWidgets/qapplication.h>
42#include <QtGui/qevent.h>
43#include <QtCore/qhash.h>
44
45QT_BEGIN_NAMESPACE
46
47QToolBoxHelper::QToolBoxHelper(QToolBox *toolbox) :
48 QObject(toolbox),
49 m_toolbox(toolbox),
50 m_actionDeletePage(new QAction(tr(s: "Delete Page"), this)),
51 m_actionInsertPage(new QAction(tr(s: "Before Current Page"), this)),
52 m_actionInsertPageAfter(new QAction(tr(s: "After Current Page"), this)),
53 m_actionChangePageOrder(new QAction(tr(s: "Change Page Order..."), this)),
54 m_pagePromotionTaskMenu(new qdesigner_internal::PromotionTaskMenu(nullptr, qdesigner_internal::PromotionTaskMenu::ModeSingleWidget, this))
55{
56 connect(sender: m_actionDeletePage, signal: &QAction::triggered, receiver: this, slot: &QToolBoxHelper::removeCurrentPage);
57 connect(sender: m_actionInsertPage, signal: &QAction::triggered, receiver: this, slot: &QToolBoxHelper::addPage);
58 connect(sender: m_actionInsertPageAfter, signal: &QAction::triggered, receiver: this, slot: &QToolBoxHelper::addPageAfter);
59 connect(sender: m_actionChangePageOrder, signal: &QAction::triggered, receiver: this, slot: &QToolBoxHelper::changeOrder);
60
61 m_toolbox->installEventFilter(filterObj: this);
62}
63
64void QToolBoxHelper::install(QToolBox *toolbox)
65{
66 new QToolBoxHelper(toolbox);
67}
68
69bool QToolBoxHelper::eventFilter(QObject *watched, QEvent *event)
70{
71 switch (event->type()) {
72 case QEvent::ChildPolished:
73 // Install on the buttons
74 if (watched == m_toolbox) {
75 QChildEvent *ce = static_cast<QChildEvent *>(event);
76 if (!qstrcmp(str1: ce->child()->metaObject()->className(), str2: "QToolBoxButton"))
77 ce->child()->installEventFilter(filterObj: this);
78 }
79 break;
80 case QEvent::ContextMenu:
81 if (watched != m_toolbox) {
82 // An action invoked from the passive interactor (ToolBox button) might
83 // cause its deletion within its event handler, triggering a warning. Re-post
84 // the event to the toolbox.
85 QContextMenuEvent *current = static_cast<QContextMenuEvent *>(event);
86 QContextMenuEvent *copy = new QContextMenuEvent(current->reason(), current->pos(), current-> globalPos(), current->modifiers());
87 QApplication::postEvent(receiver: m_toolbox, event: copy);
88 current->accept();
89 return true;
90 }
91 break;
92 case QEvent::MouseButtonRelease:
93 if (watched != m_toolbox)
94 if (QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(w: m_toolbox)) {
95 fw->clearSelection();
96 fw->selectWidget(w: m_toolbox, select: true);
97 }
98 break;
99 default:
100 break;
101 }
102 return QObject::eventFilter(watched, event);
103}
104
105QToolBoxHelper *QToolBoxHelper::helperOf(const QToolBox *toolbox)
106{
107 // Look for 1st order children only..otherwise, we might get filters of nested widgets
108 for (QObject *o : toolbox->children()) {
109 if (!o->isWidgetType())
110 if (QToolBoxHelper *h = qobject_cast<QToolBoxHelper *>(object: o))
111 return h;
112 }
113 return nullptr;
114}
115
116QMenu *QToolBoxHelper::addToolBoxContextMenuActions(const QToolBox *toolbox, QMenu *popup)
117{
118 QToolBoxHelper *helper = helperOf(toolbox);
119 if (!helper)
120 return nullptr;
121 return helper->addContextMenuActions(popup);
122}
123
124void QToolBoxHelper::removeCurrentPage()
125{
126 if (m_toolbox->currentIndex() == -1 || !m_toolbox->widget(index: m_toolbox->currentIndex()))
127 return;
128
129 if (QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(w: m_toolbox)) {
130 qdesigner_internal::DeleteToolBoxPageCommand *cmd = new qdesigner_internal::DeleteToolBoxPageCommand(fw);
131 cmd->init(toolBox: m_toolbox);
132 fw->commandHistory()->push(cmd);
133 }
134}
135
136void QToolBoxHelper::addPage()
137{
138 if (QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(w: m_toolbox)) {
139 qdesigner_internal::AddToolBoxPageCommand *cmd = new qdesigner_internal::AddToolBoxPageCommand(fw);
140 cmd->init(toolBox: m_toolbox, mode: qdesigner_internal::AddToolBoxPageCommand::InsertBefore);
141 fw->commandHistory()->push(cmd);
142 }
143}
144
145void QToolBoxHelper::changeOrder()
146{
147 QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(w: m_toolbox);
148
149 if (!fw)
150 return;
151
152 const QWidgetList oldPages = qdesigner_internal::OrderDialog::pagesOfContainer(core: fw->core(), container: m_toolbox);
153 const int pageCount = oldPages.size();
154 if (pageCount < 2)
155 return;
156
157 qdesigner_internal::OrderDialog dlg(fw);
158 dlg.setPageList(oldPages);
159 if (dlg.exec() == QDialog::Rejected)
160 return;
161
162 const QWidgetList newPages = dlg.pageList();
163 if (newPages == oldPages)
164 return;
165
166 fw->beginCommand(description: tr(s: "Change Page Order"));
167 for(int i=0; i < pageCount; ++i) {
168 if (newPages.at(i) == m_toolbox->widget(index: i))
169 continue;
170 qdesigner_internal::MoveToolBoxPageCommand *cmd = new qdesigner_internal::MoveToolBoxPageCommand(fw);
171 cmd->init(toolBox: m_toolbox, page: newPages.at(i), newIndex: i);
172 fw->commandHistory()->push(cmd);
173 }
174 fw->endCommand();
175}
176
177void QToolBoxHelper::addPageAfter()
178{
179 if (QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(w: m_toolbox)) {
180 qdesigner_internal::AddToolBoxPageCommand *cmd = new qdesigner_internal::AddToolBoxPageCommand(fw);
181 cmd->init(toolBox: m_toolbox, mode: qdesigner_internal::AddToolBoxPageCommand::InsertAfter);
182 fw->commandHistory()->push(cmd);
183 }
184}
185
186QPalette::ColorRole QToolBoxHelper::currentItemBackgroundRole() const
187{
188 const QWidget *w = m_toolbox->widget(index: 0);
189 if (!w)
190 return QPalette::Window;
191 return w->backgroundRole();
192}
193
194void QToolBoxHelper::setCurrentItemBackgroundRole(QPalette::ColorRole role)
195{
196 const int count = m_toolbox->count();
197 for (int i = 0; i < count; ++i) {
198 QWidget *w = m_toolbox->widget(index: i);
199 w->setBackgroundRole(role);
200 w->update();
201 }
202}
203
204QMenu *QToolBoxHelper::addContextMenuActions(QMenu *popup) const
205{
206 QMenu *pageMenu = nullptr;
207 const int count = m_toolbox->count();
208 m_actionDeletePage->setEnabled(count > 1);
209 if (count) {
210 const QString pageSubMenuLabel = tr(s: "Page %1 of %2").arg(a: m_toolbox->currentIndex() + 1).arg(a: count);
211 pageMenu = popup->addMenu(title: pageSubMenuLabel);
212
213 pageMenu->addAction(action: m_actionDeletePage);
214 // Set up promotion menu for current widget.
215 if (QWidget *page = m_toolbox->currentWidget ()) {
216 m_pagePromotionTaskMenu->setWidget(page);
217 m_pagePromotionTaskMenu->addActions(fw: QDesignerFormWindowInterface::findFormWindow(w: m_toolbox),
218 flags: qdesigner_internal::PromotionTaskMenu::SuppressGlobalEdit,
219 menu: pageMenu);
220 }
221 }
222 QMenu *insertPageMenu = popup->addMenu(title: tr(s: "Insert Page"));
223 insertPageMenu->addAction(action: m_actionInsertPageAfter);
224 insertPageMenu->addAction(action: m_actionInsertPage);
225 if (count > 1) {
226 popup->addAction(action: m_actionChangePageOrder);
227 }
228 popup->addSeparator();
229 return pageMenu;
230}
231
232// -------- QToolBoxWidgetPropertySheet
233
234static const char *currentItemTextKey = "currentItemText";
235static const char *currentItemNameKey = "currentItemName";
236static const char *currentItemIconKey = "currentItemIcon";
237static const char *currentItemToolTipKey = "currentItemToolTip";
238static const char *tabSpacingKey = "tabSpacing";
239
240enum { tabSpacingDefault = -1 };
241
242QToolBoxWidgetPropertySheet::QToolBoxWidgetPropertySheet(QToolBox *object, QObject *parent) :
243 QDesignerPropertySheet(object, parent),
244 m_toolBox(object)
245{
246 createFakeProperty(propertyName: QLatin1String(currentItemTextKey), value: QVariant::fromValue(value: qdesigner_internal::PropertySheetStringValue()));
247 createFakeProperty(propertyName: QLatin1String(currentItemNameKey), value: QString());
248 createFakeProperty(propertyName: QLatin1String(currentItemIconKey), value: QVariant::fromValue(value: qdesigner_internal::PropertySheetIconValue()));
249 if (formWindowBase())
250 formWindowBase()->addReloadableProperty(sheet: this, index: indexOf(name: QLatin1String(currentItemIconKey)));
251 createFakeProperty(propertyName: QLatin1String(currentItemToolTipKey), value: QVariant::fromValue(value: qdesigner_internal::PropertySheetStringValue()));
252 createFakeProperty(propertyName: QLatin1String(tabSpacingKey), value: QVariant(tabSpacingDefault));
253}
254
255QToolBoxWidgetPropertySheet::ToolBoxProperty QToolBoxWidgetPropertySheet::toolBoxPropertyFromName(const QString &name)
256{
257 using ToolBoxPropertyHash = QHash<QString, ToolBoxProperty>;
258 static ToolBoxPropertyHash toolBoxPropertyHash;
259 if (toolBoxPropertyHash.isEmpty()) {
260 toolBoxPropertyHash.insert(akey: QLatin1String(currentItemTextKey), avalue: PropertyCurrentItemText);
261 toolBoxPropertyHash.insert(akey: QLatin1String(currentItemNameKey), avalue: PropertyCurrentItemName);
262 toolBoxPropertyHash.insert(akey: QLatin1String(currentItemIconKey), avalue: PropertyCurrentItemIcon);
263 toolBoxPropertyHash.insert(akey: QLatin1String(currentItemToolTipKey), avalue: PropertyCurrentItemToolTip);
264 toolBoxPropertyHash.insert(akey: QLatin1String(tabSpacingKey), avalue: PropertyTabSpacing);
265 }
266 return toolBoxPropertyHash.value(akey: name, adefaultValue: PropertyToolBoxNone);
267}
268
269void QToolBoxWidgetPropertySheet::setProperty(int index, const QVariant &value)
270{
271 const ToolBoxProperty toolBoxProperty = toolBoxPropertyFromName(name: propertyName(index));
272 // independent of index
273 switch (toolBoxProperty) {
274 case PropertyTabSpacing:
275 m_toolBox->layout()->setSpacing(value.toInt());
276 return;
277 case PropertyToolBoxNone:
278 QDesignerPropertySheet::setProperty(index, value);
279 return;
280 default:
281 break;
282 }
283 // index-dependent
284 const int currentIndex = m_toolBox->currentIndex();
285 QWidget *currentWidget = m_toolBox->currentWidget();
286 if (!currentWidget)
287 return;
288
289 switch (toolBoxProperty) {
290 case PropertyCurrentItemText:
291 m_toolBox->setItemText(index: currentIndex, text: qvariant_cast<QString>(v: resolvePropertyValue(index, value)));
292 m_pageToData[currentWidget].text = qvariant_cast<qdesigner_internal::PropertySheetStringValue>(v: value);
293 break;
294 case PropertyCurrentItemName:
295 currentWidget->setObjectName(value.toString());
296 break;
297 case PropertyCurrentItemIcon:
298 m_toolBox->setItemIcon(index: currentIndex, icon: qvariant_cast<QIcon>(v: resolvePropertyValue(index, value)));
299 m_pageToData[currentWidget].icon = qvariant_cast<qdesigner_internal::PropertySheetIconValue>(v: value);
300 break;
301 case PropertyCurrentItemToolTip:
302 m_toolBox->setItemToolTip(index: currentIndex, toolTip: qvariant_cast<QString>(v: resolvePropertyValue(index, value)));
303 m_pageToData[currentWidget].tooltip = qvariant_cast<qdesigner_internal::PropertySheetStringValue>(v: value);
304 break;
305 case PropertyTabSpacing:
306 case PropertyToolBoxNone:
307 break;
308 }
309}
310
311bool QToolBoxWidgetPropertySheet::isEnabled(int index) const
312{
313 switch (toolBoxPropertyFromName(name: propertyName(index))) {
314 case PropertyToolBoxNone: // independent of index
315 case PropertyTabSpacing:
316 return QDesignerPropertySheet::isEnabled(index);
317 default:
318 break;
319 }
320 return m_toolBox->currentIndex() != -1;
321}
322
323QVariant QToolBoxWidgetPropertySheet::property(int index) const
324{
325 const ToolBoxProperty toolBoxProperty = toolBoxPropertyFromName(name: propertyName(index));
326 // independent of index
327 switch (toolBoxProperty) {
328 case PropertyTabSpacing:
329 return m_toolBox->layout()->spacing();
330 case PropertyToolBoxNone:
331 return QDesignerPropertySheet::property(index);
332 default:
333 break;
334 }
335 // index-dependent
336 QWidget *currentWidget = m_toolBox->currentWidget();
337 if (!currentWidget) {
338 if (toolBoxProperty == PropertyCurrentItemIcon)
339 return QVariant::fromValue(value: qdesigner_internal::PropertySheetIconValue());
340 if (toolBoxProperty == PropertyCurrentItemText)
341 return QVariant::fromValue(value: qdesigner_internal::PropertySheetStringValue());
342 if (toolBoxProperty == PropertyCurrentItemToolTip)
343 return QVariant::fromValue(value: qdesigner_internal::PropertySheetStringValue());
344 return QVariant(QString());
345 }
346
347 // index-dependent
348 switch (toolBoxProperty) {
349 case PropertyCurrentItemText:
350 return QVariant::fromValue(value: m_pageToData.value(akey: currentWidget).text);
351 case PropertyCurrentItemName:
352 return currentWidget->objectName();
353 case PropertyCurrentItemIcon:
354 return QVariant::fromValue(value: m_pageToData.value(akey: currentWidget).icon);
355 case PropertyCurrentItemToolTip:
356 return QVariant::fromValue(value: m_pageToData.value(akey: currentWidget).tooltip);
357 case PropertyTabSpacing:
358 case PropertyToolBoxNone:
359 break;
360 }
361 return QVariant();
362}
363
364bool QToolBoxWidgetPropertySheet::reset(int index)
365{
366 const ToolBoxProperty toolBoxProperty = toolBoxPropertyFromName(name: propertyName(index));
367 // independent of index
368 switch (toolBoxProperty) {
369 case PropertyTabSpacing:
370 setProperty(index, value: QVariant(tabSpacingDefault));
371 return true;
372 case PropertyToolBoxNone:
373 return QDesignerPropertySheet::reset(index);
374 default:
375 break;
376 }
377 // index-dependent
378 QWidget *currentWidget = m_toolBox->currentWidget();
379 if (!currentWidget)
380 return false;
381
382 // index-dependent
383 switch (toolBoxProperty) {
384 case PropertyCurrentItemName:
385 setProperty(index, value: QString());
386 break;
387 case PropertyCurrentItemToolTip:
388 m_pageToData[currentWidget].tooltip = qdesigner_internal::PropertySheetStringValue();
389 setProperty(index, value: QString());
390 break;
391 case PropertyCurrentItemText:
392 m_pageToData[currentWidget].text = qdesigner_internal::PropertySheetStringValue();
393 setProperty(index, value: QString());
394 break;
395 case PropertyCurrentItemIcon:
396 m_pageToData[currentWidget].icon = qdesigner_internal::PropertySheetIconValue();
397 setProperty(index, value: QIcon());
398 break;
399 case PropertyTabSpacing:
400 case PropertyToolBoxNone:
401 break;
402 }
403 return true;
404}
405
406bool QToolBoxWidgetPropertySheet::checkProperty(const QString &propertyName)
407{
408 switch (toolBoxPropertyFromName(name: propertyName)) {
409 case PropertyCurrentItemText:
410 case PropertyCurrentItemName:
411 case PropertyCurrentItemToolTip:
412 case PropertyCurrentItemIcon:
413 return false;
414 default:
415 break;
416 }
417 return true;
418}
419
420QT_END_NAMESPACE
421

source code of qttools/src/designer/src/lib/shared/qdesigner_toolbox.cpp