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