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