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_stackedbox.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
11
12#include <QtDesigner/abstractformwindow.h>
13
14#include <QtWidgets/qtoolbutton.h>
15#include <QtWidgets/qmenu.h>
16#include <QtWidgets/qstackedwidget.h>
17
18#include <QtGui/qaction.h>
19#include <QtGui/qevent.h>
20
21#include <QtCore/qdebug.h>
22
24
25using namespace Qt::StringLiterals;
26
27static QToolButton *createToolButton(QWidget *parent, Qt::ArrowType at, const QString &name)
28{
29 QToolButton *rc = new QToolButton();
30 rc->setAttribute(Qt::WA_NoChildEventsForParent, true);
31 rc->setParent(parent);
32 rc->setObjectName(name);
33 rc->setArrowType(at);
34 rc->setAutoRaise(true);
35 rc->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
36 rc->setFixedSize(QSize(15, 15));
37 return rc;
38}
39
40// --------------- QStackedWidgetPreviewEventFilter
41QStackedWidgetPreviewEventFilter::QStackedWidgetPreviewEventFilter(QStackedWidget *parent) :
42 QObject(parent),
43 m_buttonToolTipEnabled(false), // Not on preview
44 m_stackedWidget(parent),
45 m_prev(createToolButton(m_stackedWidget, Qt::LeftArrow, u"__qt__passive_prev"_s)),
46 m_next(createToolButton(m_stackedWidget, Qt::RightArrow, u"__qt__passive_next"_s))
47{
48 connect(m_prev, &QAbstractButton::clicked, this, &QStackedWidgetPreviewEventFilter::prevPage);
49 connect(m_next, &QAbstractButton::clicked, this, &QStackedWidgetPreviewEventFilter::nextPage);
50
51 updateButtons();
52 m_stackedWidget->installEventFilter(this);
53 m_prev->installEventFilter(this);
54 m_next->installEventFilter(this);
55}
56
57void QStackedWidgetPreviewEventFilter::install(QStackedWidget *stackedWidget)
58{
59 new QStackedWidgetPreviewEventFilter(stackedWidget);
60}
61
62void QStackedWidgetPreviewEventFilter::updateButtons()
63{
64 m_prev->move(m_stackedWidget->width() - 31, 1);
65 m_prev->show();
66 m_prev->raise();
67
68 m_next->move(m_stackedWidget->width() - 16, 1);
69 m_next->show();
70 m_next->raise();
71}
72
73void QStackedWidgetPreviewEventFilter::prevPage()
74{
75 if (QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(stackedWidget())) {
76 fw->clearSelection();
77 fw->selectWidget(stackedWidget(), true);
78 }
79 const int count = m_stackedWidget->count();
80 if (count > 1) {
81 int newIndex = m_stackedWidget->currentIndex() - 1;
82 if (newIndex < 0)
83 newIndex = count - 1;
84 gotoPage(newIndex);
85 }
86}
87
88void QStackedWidgetPreviewEventFilter::nextPage()
89{
90 if (QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(stackedWidget())) {
91 fw->clearSelection();
92 fw->selectWidget(stackedWidget(), true);
93 }
94 const int count = m_stackedWidget->count();
95 if (count > 1)
96 gotoPage((m_stackedWidget->currentIndex() + 1) % count);
97}
98
99bool QStackedWidgetPreviewEventFilter::eventFilter(QObject *watched, QEvent *event)
100{
101 if (watched->isWidgetType()) {
102 if (watched == m_stackedWidget) {
103 switch (event->type()) {
104 case QEvent::LayoutRequest:
105 updateButtons();
106 break;
107 case QEvent::ChildAdded:
108 case QEvent::ChildRemoved:
109 case QEvent::Resize:
110 case QEvent::Show:
111 updateButtons();
112 break;
113 default:
114 break;
115 }
116 }
117 if (m_buttonToolTipEnabled && (watched == m_next || watched == m_prev)) {
118 switch (event->type()) {
119 case QEvent::ToolTip:
120 updateButtonToolTip(watched); // Tooltip includes page number, so, refresh on demand
121 break;
122 default:
123 break;
124 }
125 }
126 }
127 return QObject::eventFilter(watched, event);
128}
129
130void QStackedWidgetPreviewEventFilter::gotoPage(int page)
131{
132 m_stackedWidget->setCurrentIndex(page);
133 updateButtons();
134}
135
136static inline QString stackedClassName(QStackedWidget *w)
137{
138 if (const QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(w))
139 return qdesigner_internal::WidgetFactory::classNameOf(fw->core(), w);
140 return u"Stacked widget"_s;
141}
142
143void QStackedWidgetPreviewEventFilter::updateButtonToolTip(QObject *o)
144{
145 if (o == m_prev) {
146 const QString msg = tr("Go to previous page of %1 '%2' (%3/%4).")
147 .arg(stackedClassName(m_stackedWidget), m_stackedWidget->objectName())
148 .arg(m_stackedWidget->currentIndex() + 1)
149 .arg(m_stackedWidget->count());
150 m_prev->setToolTip(msg);
151 } else {
152 if (o == m_next) {
153 const QString msg = tr("Go to next page of %1 '%2' (%3/%4).")
154 .arg(stackedClassName(m_stackedWidget), m_stackedWidget->objectName())
155 .arg(m_stackedWidget->currentIndex() + 1)
156 .arg(m_stackedWidget->count());
157 m_next->setToolTip(msg);
158 }
159 }
160}
161
162// --------------- QStackedWidgetEventFilter
163QStackedWidgetEventFilter::QStackedWidgetEventFilter(QStackedWidget *parent) :
164 QStackedWidgetPreviewEventFilter(parent),
165 m_actionPreviousPage(new QAction(tr("Previous Page"), this)),
166 m_actionNextPage(new QAction(tr("Next Page"), this)),
167 m_actionDeletePage(new QAction(tr("Delete"), this)),
168 m_actionInsertPage(new QAction(tr("Before Current Page"), this)),
169 m_actionInsertPageAfter(new QAction(tr("After Current Page"), this)),
170 m_actionChangePageOrder(new QAction(tr("Change Page Order..."), this)),
171 m_pagePromotionTaskMenu(new qdesigner_internal::PromotionTaskMenu(nullptr, qdesigner_internal::PromotionTaskMenu::ModeSingleWidget, this))
172{
173 setButtonToolTipEnabled(true);
174 connect(m_actionPreviousPage, &QAction::triggered, this, &QStackedWidgetEventFilter::prevPage);
175 connect(m_actionNextPage, &QAction::triggered, this, &QStackedWidgetEventFilter::nextPage);
176 connect(m_actionDeletePage, &QAction::triggered, this, &QStackedWidgetEventFilter::removeCurrentPage);
177 connect(m_actionInsertPage, &QAction::triggered, this, &QStackedWidgetEventFilter::addPage);
178 connect(m_actionInsertPageAfter, &QAction::triggered, this, &QStackedWidgetEventFilter::addPageAfter);
179 connect(m_actionChangePageOrder, &QAction::triggered, this, &QStackedWidgetEventFilter::changeOrder);
180}
181
182void QStackedWidgetEventFilter::install(QStackedWidget *stackedWidget)
183{
184 new QStackedWidgetEventFilter(stackedWidget);
185}
186
187QStackedWidgetEventFilter *QStackedWidgetEventFilter::eventFilterOf(const QStackedWidget *stackedWidget)
188{
189 // Look for 1st order children only..otherwise, we might get filters of nested widgets
190 for (QObject *o : stackedWidget->children()) {
191 if (!o->isWidgetType())
192 if (QStackedWidgetEventFilter *ef = qobject_cast<QStackedWidgetEventFilter *>(o))
193 return ef;
194 }
195 return nullptr;
196}
197
198QMenu *QStackedWidgetEventFilter::addStackedWidgetContextMenuActions(const QStackedWidget *stackedWidget, QMenu *popup)
199{
200 QStackedWidgetEventFilter *filter = eventFilterOf(stackedWidget);
201 if (!filter)
202 return nullptr;
203 return filter->addContextMenuActions(popup);
204}
205
206void QStackedWidgetEventFilter::removeCurrentPage()
207{
208 if (stackedWidget()->currentIndex() == -1)
209 return;
210
211 if (QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(stackedWidget())) {
212 qdesigner_internal::DeleteStackedWidgetPageCommand *cmd = new qdesigner_internal::DeleteStackedWidgetPageCommand(fw);
213 cmd->init(stackedWidget());
214 fw->commandHistory()->push(cmd);
215 }
216}
217
218void QStackedWidgetEventFilter::changeOrder()
219{
220 QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(stackedWidget());
221
222 if (!fw)
223 return;
224
225 const QWidgetList oldPages = qdesigner_internal::OrderDialog::pagesOfContainer(fw->core(), stackedWidget());
226 const int pageCount = oldPages.size();
227 if (pageCount < 2)
228 return;
229
230 qdesigner_internal::OrderDialog dlg(fw);
231 dlg.setPageList(oldPages);
232 if (dlg.exec() == QDialog::Rejected)
233 return;
234
235 const QWidgetList newPages = dlg.pageList();
236 if (newPages == oldPages)
237 return;
238
239 fw->beginCommand(tr("Change Page Order"));
240 for(int i=0; i < pageCount; ++i) {
241 if (newPages.at(i) == stackedWidget()->widget(i))
242 continue;
243 qdesigner_internal::MoveStackedWidgetCommand *cmd = new qdesigner_internal::MoveStackedWidgetCommand(fw);
244 cmd->init(stackedWidget(), newPages.at(i), i);
245 fw->commandHistory()->push(cmd);
246 }
247 fw->endCommand();
248}
249
250void QStackedWidgetEventFilter::addPage()
251{
252 if (QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(stackedWidget())) {
253 qdesigner_internal::AddStackedWidgetPageCommand *cmd = new qdesigner_internal::AddStackedWidgetPageCommand(fw);
254 cmd->init(stackedWidget(), qdesigner_internal::AddStackedWidgetPageCommand::InsertBefore);
255 fw->commandHistory()->push(cmd);
256 }
257}
258
259void QStackedWidgetEventFilter::addPageAfter()
260{
261 if (QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(stackedWidget())) {
262 qdesigner_internal::AddStackedWidgetPageCommand *cmd = new qdesigner_internal::AddStackedWidgetPageCommand(fw);
263 cmd->init(stackedWidget(), qdesigner_internal::AddStackedWidgetPageCommand::InsertAfter);
264 fw->commandHistory()->push(cmd);
265 }
266}
267
268void QStackedWidgetEventFilter::gotoPage(int page) {
269 // Are we on a form or in a preview?
270 if (QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(stackedWidget())) {
271 qdesigner_internal::SetPropertyCommand *cmd = new qdesigner_internal::SetPropertyCommand(fw);
272 cmd->init(stackedWidget(), u"currentIndex"_s, page);
273 fw->commandHistory()->push(cmd);
274 fw->emitSelectionChanged(); // Magically prevent an endless loop triggered by auto-repeat.
275 updateButtons();
276 } else {
277 QStackedWidgetPreviewEventFilter::gotoPage(page);
278 }
279}
280
281QMenu *QStackedWidgetEventFilter::addContextMenuActions(QMenu *popup)
282{
283 QMenu *pageMenu = nullptr;
284 const int count = stackedWidget()->count();
285 const bool hasSeveralPages = count > 1;
286 m_actionDeletePage->setEnabled(count);
287 if (count) {
288 const QString pageSubMenuLabel = tr("Page %1 of %2").arg(stackedWidget()->currentIndex() + 1).arg(count);
289 pageMenu = popup->addMenu(pageSubMenuLabel);
290 pageMenu->addAction(m_actionDeletePage);
291 // Set up promotion menu for current widget.
292 if (QWidget *page = stackedWidget()->currentWidget ()) {
293 m_pagePromotionTaskMenu->setWidget(page);
294 m_pagePromotionTaskMenu->addActions(QDesignerFormWindowInterface::findFormWindow(stackedWidget()),
295 qdesigner_internal::PromotionTaskMenu::SuppressGlobalEdit,
296 pageMenu);
297 }
298 QMenu *insertPageMenu = popup->addMenu(tr("Insert Page"));
299 insertPageMenu->addAction(m_actionInsertPageAfter);
300 insertPageMenu->addAction(m_actionInsertPage);
301 } else {
302 QAction *insertPageAction = popup->addAction(tr("Insert Page"));
303 connect(insertPageAction, &QAction::triggered, this, &QStackedWidgetEventFilter::addPage);
304 }
305 popup->addAction(m_actionNextPage);
306 m_actionNextPage->setEnabled(hasSeveralPages);
307 popup->addAction(m_actionPreviousPage);
308 m_actionPreviousPage->setEnabled(hasSeveralPages);
309 popup->addAction(m_actionChangePageOrder);
310 m_actionChangePageOrder->setEnabled(hasSeveralPages);
311 popup->addSeparator();
312 return pageMenu;
313}
314
315// -------- QStackedWidgetPropertySheet
316
317static constexpr auto pagePropertyName = "currentPageName"_L1;
318
319QStackedWidgetPropertySheet::QStackedWidgetPropertySheet(QStackedWidget *object, QObject *parent) :
320 QDesignerPropertySheet(object, parent),
321 m_stackedWidget(object)
322{
323 createFakeProperty(pagePropertyName, QString());
324}
325
326bool QStackedWidgetPropertySheet::isEnabled(int index) const
327{
328 if (propertyName(index) != pagePropertyName)
329 return QDesignerPropertySheet::isEnabled(index);
330 return m_stackedWidget->currentWidget() != nullptr;
331}
332
333void QStackedWidgetPropertySheet::setProperty(int index, const QVariant &value)
334{
335 if (propertyName(index) == pagePropertyName) {
336 if (QWidget *w = m_stackedWidget->currentWidget())
337 w->setObjectName(value.toString());
338 } else {
339 QDesignerPropertySheet::setProperty(index, value);
340 }
341}
342
343QVariant QStackedWidgetPropertySheet::property(int index) const
344{
345 if (propertyName(index) == pagePropertyName) {
346 if (const QWidget *w = m_stackedWidget->currentWidget())
347 return w->objectName();
348 return QString();
349 }
350 return QDesignerPropertySheet::property(index);
351}
352
353bool QStackedWidgetPropertySheet::reset(int index)
354{
355 if (propertyName(index) == pagePropertyName) {
356 setProperty(index, QString());
357 return true;
358 }
359 return QDesignerPropertySheet::reset(index);
360}
361
362bool QStackedWidgetPropertySheet::checkProperty(const QString &propertyName)
363{
364 return propertyName != pagePropertyName;
365}
366
367QT_END_NAMESPACE
friend class QWidget
Definition qpainter.h:432
Combined button and popup list for selecting options.
static QString stackedClassName(QStackedWidget *w)
static constexpr auto pagePropertyName
static QToolButton * createToolButton(QWidget *parent, Qt::ArrowType at, const QString &name)