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