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
qwizard.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5#include "qwizard.h"
6#include <QtWidgets/private/qtwidgetsglobal_p.h>
7
8#if QT_CONFIG(spinbox)
9#include "qabstractspinbox.h"
10#endif
11#include "qalgorithms.h"
12#include "qapplication.h"
13#include "qboxlayout.h"
14#include "qlayoutitem.h"
15#include "qevent.h"
16#include "qframe.h"
17#include "qlabel.h"
18#if QT_CONFIG(lineedit)
19#include "qlineedit.h"
20#endif
21#include <qpointer.h>
22#include "qstylepainter.h"
23#include "qwindow.h"
24#include "qpushbutton.h"
25#include "qset.h"
26#if QT_CONFIG(shortcut)
27# include "qshortcut.h"
28#endif
29#include "qstyle.h"
30#include "qstyleoption.h"
32#if defined(Q_OS_MACOS)
33#include <AppKit/AppKit.h>
34#include <QtGui/private/qcoregraphics_p.h>
35#elif QT_CONFIG(style_windowsvista)
36#include "qwizard_win_p.h"
37#endif
38
39#include "private/qdialog_p.h"
40#include <qdebug.h>
41
42#include <string.h> // for memset()
43#include <algorithm>
44
46
47using namespace Qt::StringLiterals;
48
49// These fudge terms were needed a few places to obtain pixel-perfect results
52const int ClassicHMargin = 4;
53const int MacButtonTopMargin = 13;
54const int MacLayoutLeftMargin = 20;
55//const int MacLayoutTopMargin = 14; // Unused. Save some space and avoid warning.
56const int MacLayoutRightMargin = 20;
57const int MacLayoutBottomMargin = 17;
58
59static void changeSpacerSize(QLayout *layout, int index, int width, int height)
60{
61 QSpacerItem *spacer = layout->itemAt(index)->spacerItem();
62 if (!spacer)
63 return;
64 spacer->changeSize(width, height);
65}
66
67static QWidget *iWantTheFocus(QWidget *ancestor)
68{
69 const int MaxIterations = 100;
70
71 QWidget *candidate = ancestor;
72 for (int i = 0; i < MaxIterations; ++i) {
73 candidate = candidate->nextInFocusChain();
74 if (!candidate)
75 break;
76
77 if (candidate->focusPolicy() & Qt::TabFocus) {
78 if (candidate != ancestor && ancestor->isAncestorOf(candidate))
79 return candidate;
80 }
81 }
82 return nullptr;
83}
84
85static bool objectInheritsXAndXIsCloserThanY(const QObject *object, const QByteArray &classX,
86 const QByteArray &classY)
87{
88 const QMetaObject *metaObject = object->metaObject();
89 while (metaObject) {
90 if (metaObject->className() == classX)
91 return true;
92 if (metaObject->className() == classY)
93 return false;
94 metaObject = metaObject->superClass();
95 }
96 return false;
97}
98
99const struct {
100 const char className[16];
101 const char property[13];
102} fallbackProperties[] = {
103 // If you modify this list, make sure to update the documentation (and the auto test)
104 { "QAbstractButton", "checked" },
105 { "QAbstractSlider", "value" },
106 { "QComboBox", "currentIndex" },
107 { "QDateTimeEdit", "dateTime" },
108 { "QLineEdit", "text" },
109 { "QListWidget", "currentRow" },
110 { "QSpinBox", "value" },
112const size_t NFallbackDefaultProperties = sizeof fallbackProperties / sizeof *fallbackProperties;
113
114static const char *changed_signal(int which)
115{
116 // since it might expand to a runtime function call (to
117 // qFlagLocations()), we cannot store the result of SIGNAL() in a
118 // character array and expect it to be statically initialized. To
119 // avoid the relocations caused by a char pointer table, use a
120 // switch statement:
121 switch (which) {
122 case 0: return SIGNAL(toggled(bool));
123 case 1: return SIGNAL(valueChanged(int));
124 case 2: return SIGNAL(currentIndexChanged(int));
125 case 3: return SIGNAL(dateTimeChanged(QDateTime));
126 case 4: return SIGNAL(textChanged(QString));
127 case 5: return SIGNAL(currentRowChanged(int));
128 case 6: return SIGNAL(valueChanged(int));
129 };
130 static_assert(7 == NFallbackDefaultProperties);
131 Q_UNREACHABLE_RETURN(nullptr);
132}
133
135{
136public:
140
142 inline QWizardDefaultProperty(const char *className, const char *property,
143 const char *changedSignal)
145};
147
149{
150public:
151 inline QWizardField() {}
152 QWizardField(QWizardPage *page, const QString &spec, QObject *object, const char *property,
153 const char *changedSignal);
154
155 void resolve(const QList<QWizardDefaultProperty> &defaultPropertyTable);
156 void findProperty(const QWizardDefaultProperty *properties, int propertyCount);
157
158 QWizardPage *page;
164 QVariant initialValue;
165};
167
168QWizardField::QWizardField(QWizardPage *page, const QString &spec, QObject *object,
169 const char *property, const char *changedSignal)
170 : page(page), name(spec), mandatory(false), object(object), property(property),
172{
173 if (name.endsWith(u'*')) {
174 name.chop(1);
175 mandatory = true;
176 }
177}
178
179void QWizardField::resolve(const QList<QWizardDefaultProperty> &defaultPropertyTable)
180{
181 if (property.isEmpty())
182 findProperty(defaultPropertyTable.constData(), defaultPropertyTable.size());
183 initialValue = object->property(property);
184}
185
186void QWizardField::findProperty(const QWizardDefaultProperty *properties, int propertyCount)
187{
188 QByteArray className;
189
190 for (int i = 0; i < propertyCount; ++i) {
191 if (objectInheritsXAndXIsCloserThanY(object, properties[i].className, className)) {
192 className = properties[i].className;
193 property = properties[i].property;
194 changedSignal = properties[i].changedSignal;
195 }
196 }
197}
198
200{
201public:
210 int hspacing = -1;
211 int vspacing = -1;
214 bool header = false;
215 bool watermark = false;
216 bool title = false;
217 bool subTitle = false;
218 bool extension = false;
219 bool sideWidget = false;
220
221 bool operator==(const QWizardLayoutInfo &other) const;
222 inline bool operator!=(const QWizardLayoutInfo &other) const { return !operator==(other); }
223};
224
226{
227 return topLevelMarginLeft == other.topLevelMarginLeft
228 && topLevelMarginRight == other.topLevelMarginRight
229 && topLevelMarginTop == other.topLevelMarginTop
230 && topLevelMarginBottom == other.topLevelMarginBottom
231 && childMarginLeft == other.childMarginLeft
232 && childMarginRight == other.childMarginRight
233 && childMarginTop == other.childMarginTop
234 && childMarginBottom == other.childMarginBottom
235 && hspacing == other.hspacing
236 && vspacing == other.vspacing
237 && buttonSpacing == other.buttonSpacing
238 && wizStyle == other.wizStyle
239 && header == other.header
240 && watermark == other.watermark
241 && title == other.title
242 && subTitle == other.subTitle
243 && extension == other.extension
244 && sideWidget == other.sideWidget;
245}
246
247class QWizardHeader : public QWidget
248{
249protected:
250 enum RulerType { Ruler };
251
252 explicit
253 inline QWizardHeader(RulerType /* ruler */, QWidget *parent = nullptr)
254 : QWidget(parent) { setFixedHeight(2); }
255public:
256 explicit
257 QWizardHeader(QWidget *parent = nullptr);
258
259 void setup(const QWizardLayoutInfo &info, const QString &title,
260 const QString &subTitle, const QPixmap &logo, const QPixmap &banner,
261 Qt::TextFormat titleFormat, Qt::TextFormat subTitleFormat,
262 QWizard::WizardOptions wizardOptions);
263
264protected:
265 void paintEvent(QPaintEvent *event) override;
266#if QT_CONFIG(style_windowsvista)
267private:
268 bool vistaDisabled() const;
269#endif
270private:
271 QLabel *titleLabel;
272 QLabel *subTitleLabel;
273 QLabel *logoLabel;
274 QGridLayout *layout;
275 QPixmap bannerPixmap;
277};
278
280 : QWidget(parent)
281{
282 setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
283 setBackgroundRole(QPalette::Base);
284
285 titleLabel = new QLabel(this);
286 titleLabel->setBackgroundRole(QPalette::Base);
287
288 subTitleLabel = new QLabel(this);
289 subTitleLabel->setAlignment(Qt::AlignTop | Qt::AlignLeft);
290 subTitleLabel->setWordWrap(true);
291
292 logoLabel = new QLabel(this);
293
294 QFont font = titleLabel->font();
295 font.setBold(true);
296 titleLabel->setFont(font);
297
298 layout = new QGridLayout(this);
299 layout->setContentsMargins(QMargins());
300 layout->setSpacing(0);
301
302 layout->setRowMinimumHeight(3, 1);
303 layout->setRowStretch(4, 1);
304
305 layout->setColumnStretch(2, 1);
306 layout->setColumnMinimumWidth(4, 2 * GapBetweenLogoAndRightEdge);
307 layout->setColumnMinimumWidth(6, GapBetweenLogoAndRightEdge);
308
309 layout->addWidget(titleLabel, 2, 1, 1, 2);
310 layout->addWidget(subTitleLabel, 4, 2);
311 layout->addWidget(logoLabel, 1, 5, 5, 1);
312}
313
314#if QT_CONFIG(style_windowsvista)
315bool QWizardHeader::vistaDisabled() const
316{
317 bool styleDisabled = false;
318 QWizard *wiz = parentWidget() ? qobject_cast <QWizard *>(parentWidget()->parentWidget()) : 0;
319 if (wiz) {
320 // Designer doesn't support the Vista style for Wizards. This property is used to turn
321 // off the Vista style.
322 const QVariant v = wiz->property("_q_wizard_vista_off");
323 styleDisabled = v.isValid() && v.toBool();
324 }
325 return styleDisabled;
326}
327#endif
328
329void QWizardHeader::setup(const QWizardLayoutInfo &info, const QString &title,
330 const QString &subTitle, const QPixmap &logo, const QPixmap &banner,
331 Qt::TextFormat titleFormat, Qt::TextFormat subTitleFormat,
332 QWizard::WizardOptions options)
333{
334 bool modern = ((info.wizStyle == QWizard::ModernStyle)
335#if QT_CONFIG(style_windowsvista)
336 || vistaDisabled()
337#endif
338 );
339 wizardOptions = options;
340 layout->setRowMinimumHeight(0, modern ? ModernHeaderTopMargin : 0);
341 layout->setRowMinimumHeight(1, modern ? info.topLevelMarginTop - ModernHeaderTopMargin - 1 : 0);
342 layout->setRowMinimumHeight(6, (modern ? 3 : GapBetweenLogoAndRightEdge) + 2);
343
344 int minColumnWidth0 = modern ? info.topLevelMarginLeft + info.topLevelMarginRight : 0;
345 int minColumnWidth1 = modern ? info.topLevelMarginLeft + info.topLevelMarginRight + 1
347 layout->setColumnMinimumWidth(0, minColumnWidth0);
348 layout->setColumnMinimumWidth(1, minColumnWidth1);
349
350 titleLabel->setTextFormat(titleFormat);
351 titleLabel->setText(title);
352 logoLabel->setPixmap(logo);
353
354 subTitleLabel->setTextFormat(subTitleFormat);
355 subTitleLabel->setText("Pq\nPq"_L1);
356 int desiredSubTitleHeight = subTitleLabel->sizeHint().height();
357 subTitleLabel->setText(subTitle);
358
359 if (modern) {
360 bannerPixmap = banner;
361 } else {
362 bannerPixmap = QPixmap();
363 }
364
365 if (bannerPixmap.isNull() || wizardOptions.testFlag(QWizard::StretchBanner)) {
366 /*
367 There is no widthForHeight() function, so we simulate it with a loop.
368 */
369 int candidateSubTitleWidth = qMin(512, 2 * QGuiApplication::primaryScreen()->virtualGeometry().width() / 3);
370 int delta = candidateSubTitleWidth >> 1;
371 while (delta > 0) {
372 if (subTitleLabel->heightForWidth(candidateSubTitleWidth - delta)
373 <= desiredSubTitleHeight)
374 candidateSubTitleWidth -= delta;
375 delta >>= 1;
376 }
377
378 subTitleLabel->setMinimumSize(candidateSubTitleWidth, desiredSubTitleHeight);
379
380 QSize size = layout->totalMinimumSize();
381 setMinimumSize(size);
382 setMaximumSize(QWIDGETSIZE_MAX, size.height());
383 } else {
384 subTitleLabel->setMinimumSize(0, 0);
385 setFixedSize(banner.size() + QSize(0, 2));
386 }
387 updateGeometry();
388}
389
390void QWizardHeader::paintEvent(QPaintEvent * /* event */)
391{
392 QStylePainter painter(this);
393 if (wizardOptions.testFlag(QWizard::StretchBanner)) {
394 painter.setRenderHint(QPainter::SmoothPixmapTransform);
395 painter.drawPixmap(0, 0, width(), height(), bannerPixmap);
396 } else {
397 painter.drawPixmap(0, 0, bannerPixmap);
398 }
399
400 // With fractional scaling the 1px difference in y-coordinate can map to
401 // the same pixel, so make sure that we take DPR into account when drawing
402 // the lines.
403 const qreal dpr = devicePixelRatio();
404 const int devHeight = qRound(height() * dpr);
405 const int devWidth = qRound(width() * dpr);
406
407 const qreal x = (devWidth - 2) / dpr;
408 const qreal y = (devHeight - 2) / dpr;
409
410 const qreal x1 = (devWidth - 1) / dpr;
411 const qreal y1 = (devHeight - 1) / dpr;
412
413 const QPalette &pal = palette();
414 painter.setPen(pal.mid().color());
415 painter.drawLine(QLineF(0, y, x, y));
416 painter.setPen(pal.base().color());
417 painter.drawPoint(QPointF(x1, y));
418 painter.drawLine(QLineF(0, y1, x1, y1));
419}
420
421// We save one vtable by basing QWizardRuler on QWizardHeader
423{
424public:
425 inline QWizardRuler(QWidget *parent = nullptr)
426 : QWizardHeader(Ruler, parent) {}
427};
428
430{
431public:
432 QWatermarkLabel(QWidget *parent, QWidget *sideWidget) : QLabel(parent), m_sideWidget(sideWidget) {
433 m_layout = new QVBoxLayout(this);
434 if (m_sideWidget)
435 m_layout->addWidget(m_sideWidget);
436 }
437
438 QSize minimumSizeHint() const override {
439 if (!pixmap().isNull())
440 return pixmap().deviceIndependentSize().toSize();
441 return QFrame::minimumSizeHint();
442 }
443
444 void setSideWidget(QWidget *widget) {
445 if (m_sideWidget == widget)
446 return;
447 if (m_sideWidget) {
448 m_layout->removeWidget(m_sideWidget);
449 m_sideWidget->hide();
450 }
451 m_sideWidget = widget;
452 if (m_sideWidget)
453 m_layout->addWidget(m_sideWidget);
454 }
456 return m_sideWidget;
457 }
458private:
459 QVBoxLayout *m_layout;
460 QWidget *m_sideWidget;
461};
462
485
487{
488 Q_Q(const QWizardPage);
489 if (completeState == Tri_Unknown)
490 completeState = q->isComplete() ? Tri_True : Tri_False;
491 return completeState == Tri_True;
492}
493
495{
496 Q_Q(QWizardPage);
497 TriState newState = q->isComplete() ? Tri_True : Tri_False;
498 if (newState != completeState)
499 emit q->completeChanged();
500}
501
503{
504 Q_Q(QWizardPage);
505 completeState = q->isComplete() ? Tri_True : Tri_False;
506}
507
509{
510public:
511#if QT_CONFIG(style_windowsvista)
514 : QWidget(wizard)
516protected:
518#else
520 : QWidget(wizard)
521 {}
522#endif
523};
524
526{
527 Q_DECLARE_PUBLIC(QWizard)
528
529public:
530 typedef QMap<int, QWizardPage *> PageMap;
531
536
537 void init();
538 void reset();
540 void addField(const QWizardField &field);
541 void removeFieldAt(int index);
542 void switchToPage(int newId, Direction direction);
549 bool ensureButton(QWizard::WizardButton which) const;
550 void connectButton(QWizard::WizardButton which) const;
553 void setButtonLayout(const QWizard::WizardButton *array, int size);
554 bool buttonLayoutContains(QWizard::WizardButton which);
555 void updatePixmap(QWizard::WizardPixmap which);
556#if QT_CONFIG(style_windowsvista)
557 bool vistaDisabled() const;
559#endif
566 void setStyle(QStyle *style);
567#ifdef Q_OS_MACOS
569#endif
570
576 int start = -1;
577 bool startSetByUser = false;
578 int current = -1;
579 bool canContinue = false;
580 bool canFinish = false;
583
592
593 union {
594 // keep in sync with QWizard::WizardButton
595 mutable struct {
596 QAbstractButton *back;
597 QAbstractButton *next;
598 QAbstractButton *commit;
599 QAbstractButton *finish;
600 QAbstractButton *cancel;
601 QAbstractButton *help;
602 } btn;
603 mutable QAbstractButton *btns[QWizard::NButtons];
604 };
610 QWidget *sideWidget = nullptr;
611 QFrame *pageFrame = nullptr;
612 QLabel *titleLabel = nullptr;
615
619
620#if QT_CONFIG(style_windowsvista)
621 QVistaHelper *vistaHelper = nullptr;
622# if QT_CONFIG(shortcut)
624# endif
625 bool vistaInitPending = false;
626 bool vistaDirty = true;
627 bool vistaStateChanged = false;
628 bool inHandleAeroStyleChange = false;
629#endif
634};
635
636static QString buttonDefaultText(int wstyle, int which, const QWizardPrivate *wizardPrivate)
637{
638#if !QT_CONFIG(style_windowsvista)
639 Q_UNUSED(wizardPrivate);
640#endif
641 const bool macStyle = (wstyle == QWizard::MacStyle);
642 switch (which) {
643 case QWizard::BackButton:
644 return macStyle ? QWizard::tr("Go Back") : QWizard::tr("< &Back");
645 case QWizard::NextButton:
646 if (macStyle)
647 return QWizard::tr("Continue");
648 else
649 return wizardPrivate->isVistaThemeEnabled()
650 ? QWizard::tr("&Next") : QWizard::tr("&Next >");
651 case QWizard::CommitButton:
652 return QWizard::tr("Commit");
653 case QWizard::FinishButton:
654 return macStyle ? QWizard::tr("Done") : QWizard::tr("&Finish");
655 case QWizard::CancelButton:
656 return QWizard::tr("Cancel");
657 case QWizard::HelpButton:
658 return macStyle ? QWizard::tr("Help") : QWizard::tr("&Help");
659 default:
660 return QString();
661 }
662}
663
665{
666 Q_Q(QWizard);
667
668 std::fill(btns, btns + QWizard::NButtons, nullptr);
669
670 antiFlickerWidget = new QWizardAntiFlickerWidget(q, this);
671 wizStyle = QWizard::WizardStyle(q->style()->styleHint(QStyle::SH_WizardStyle, nullptr, q));
672 switch (wizStyle) {
673 case QWizard::ModernStyle:
674 opts = QWizard::HelpButtonOnRight;
675 break;
676 case QWizard::MacStyle:
677 opts = (QWizard::NoDefaultButton | QWizard::NoCancelButton);
678 break;
679#if QT_CONFIG(style_windowsvista)
680 case QWizard::AeroStyle:
681 vistaInitPending = true;
682#endif
683 default:
684 break;
685 }
686
687#if QT_CONFIG(style_windowsvista)
688 vistaHelper = new QVistaHelper(q);
689#endif
690
691 // create these buttons right away; create the other buttons as necessary
692 ensureButton(QWizard::BackButton);
693 ensureButton(QWizard::NextButton);
694 ensureButton(QWizard::CommitButton);
695 ensureButton(QWizard::FinishButton);
696
697 pageFrame = new QFrame(antiFlickerWidget);
698 pageFrame->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
699
700 pageVBoxLayout = new QVBoxLayout(pageFrame);
701 pageVBoxLayout->setSpacing(0);
702 pageVBoxLayout->addSpacing(0);
703 QSpacerItem *spacerItem = new QSpacerItem(0, 0, QSizePolicy::Ignored, QSizePolicy::MinimumExpanding);
704 pageVBoxLayout->addItem(spacerItem);
705
706 buttonLayout = new QHBoxLayout;
707 mainLayout = new QGridLayout(antiFlickerWidget);
708 mainLayout->setSizeConstraint(QLayout::SetNoConstraint);
709
711
712 defaultPropertyTable.reserve(NFallbackDefaultProperties);
713 for (uint i = 0; i < NFallbackDefaultProperties; ++i)
714 defaultPropertyTable.append(QWizardDefaultProperty(fallbackProperties[i].className,
715 fallbackProperties[i].property,
716 changed_signal(i)));
717}
718
720{
721 Q_Q(QWizard);
722 if (current != -1) {
723 q->currentPage()->hide();
725 const auto end = history.crend();
726 for (auto it = history.crbegin(); it != end; ++it)
727 q->cleanupPage(*it);
728 history.clear();
729 for (QWizardPage *page : std::as_const(pageMap))
730 page->d_func()->initialized = false;
731
732 current = -1;
733 emit q->currentIdChanged(-1);
734 }
735}
736
738{
739 Q_Q(QWizard);
740
741 for (auto it = pageMap.begin(), end = pageMap.end(); it != end; ++it) {
742 const auto idx = it.key();
743 const auto page = it.value()->d_func();
744 if (page->initialized && !history.contains(idx)) {
745 q->cleanupPage(idx);
746 page->initialized = false;
747 }
748 }
749}
750
752{
753 Q_Q(QWizard);
754
755 QWizardField myField = field;
756 myField.resolve(defaultPropertyTable);
757
758 if (Q_UNLIKELY(fieldIndexMap.contains(myField.name))) {
759 qWarning("QWizardPage::addField: Duplicate field '%ls'", qUtf16Printable(myField.name));
760 return;
761 }
762
763 fieldIndexMap.insert(myField.name, fields.size());
764 fields += myField;
765 if (myField.mandatory && !myField.changedSignal.isEmpty())
766 QObject::connect(myField.object, myField.changedSignal,
767 myField.page, SLOT(_q_maybeEmitCompleteChanged()));
768 QObject::connect(
769 myField.object, SIGNAL(destroyed(QObject*)), q,
770 SLOT(_q_handleFieldObjectDestroyed(QObject*)));
771}
772
774{
775 Q_Q(QWizard);
776
777 const QWizardField &field = fields.at(index);
778 fieldIndexMap.remove(field.name);
779 if (field.mandatory && !field.changedSignal.isEmpty())
780 QObject::disconnect(field.object, field.changedSignal,
781 field.page, SLOT(_q_maybeEmitCompleteChanged()));
782 QObject::disconnect(
783 field.object, SIGNAL(destroyed(QObject*)), q,
784 SLOT(_q_handleFieldObjectDestroyed(QObject*)));
785 fields.remove(index);
786}
787
788void QWizardPrivate::switchToPage(int newId, Direction direction)
789{
790 Q_Q(QWizard);
791
793
794 int oldId = current;
795 if (QWizardPage *oldPage = q->currentPage()) {
796 oldPage->hide();
797
798 if (direction == Backward) {
799 if (!(opts & QWizard::IndependentPages)) {
800 q->cleanupPage(oldId);
801 oldPage->d_func()->initialized = false;
802 }
803 Q_ASSERT(history.constLast() == oldId);
804 history.removeLast();
805 Q_ASSERT(history.constLast() == newId);
806 }
807 }
808
809 current = newId;
810
811 QWizardPage *newPage = q->currentPage();
812 if (newPage) {
813 if (direction == Forward) {
814 if (!newPage->d_func()->initialized) {
815 newPage->d_func()->initialized = true;
816 q->initializePage(current);
817 }
818 history.append(current);
819 }
820 newPage->show();
821 }
822
823 canContinue = (q->nextId() != -1);
824 canFinish = (newPage && newPage->isFinalPage());
825
828
829 const QWizard::WizardButton nextOrCommit =
830 newPage && newPage->isCommitPage() ? QWizard::CommitButton : QWizard::NextButton;
831 QAbstractButton *nextOrFinishButton =
832 btns[canContinue ? nextOrCommit : QWizard::FinishButton];
833 QWidget *candidate = nullptr;
834
835 /*
836 If there is no default button and the Next or Finish button
837 is enabled, give focus directly to it as a convenience to the
838 user. This is the normal case on OS X.
839
840 Otherwise, give the focus to the new page's first child that
841 can handle it. If there is no such child, give the focus to
842 Next or Finish.
843 */
844 if ((opts & QWizard::NoDefaultButton) && nextOrFinishButton->isEnabled()) {
845 candidate = nextOrFinishButton;
846 } else if (newPage) {
847 candidate = iWantTheFocus(newPage);
848 }
849 if (!candidate)
850 candidate = nextOrFinishButton;
851 candidate->setFocus();
852
853 if (wizStyle == QWizard::MacStyle)
854 q->updateGeometry();
855
859
860 emit q->currentIdChanged(current);
861}
862
863// keep in sync with QWizard::WizardButton
864static const char * buttonSlots(QWizard::WizardButton which)
865{
866 switch (which) {
867 case QWizard::BackButton:
868 return SLOT(back());
869 case QWizard::NextButton:
870 case QWizard::CommitButton:
871 return SLOT(next());
872 case QWizard::FinishButton:
873 return SLOT(accept());
874 case QWizard::CancelButton:
875 return SLOT(reject());
876 case QWizard::HelpButton:
877 return SIGNAL(helpRequested());
878 case QWizard::CustomButton1:
879 case QWizard::CustomButton2:
880 case QWizard::CustomButton3:
881 case QWizard::Stretch:
882 case QWizard::NoButton:
883 Q_UNREACHABLE();
884 };
885 return nullptr;
886};
887
889{
890 Q_Q(QWizard);
891 QStyle *style = q->style();
892
894
895 QStyleOption option;
896 option.initFrom(q);
897 const int layoutHorizontalSpacing = style->pixelMetric(QStyle::PM_LayoutHorizontalSpacing, &option, q);
898 info.topLevelMarginLeft = style->pixelMetric(QStyle::PM_LayoutLeftMargin, nullptr, q);
899 info.topLevelMarginRight = style->pixelMetric(QStyle::PM_LayoutRightMargin, nullptr, q);
900 info.topLevelMarginTop = style->pixelMetric(QStyle::PM_LayoutTopMargin, nullptr, q);
901 info.topLevelMarginBottom = style->pixelMetric(QStyle::PM_LayoutBottomMargin, nullptr, q);
902 info.childMarginLeft = style->pixelMetric(QStyle::PM_LayoutLeftMargin, nullptr, titleLabel);
903 info.childMarginRight = style->pixelMetric(QStyle::PM_LayoutRightMargin, nullptr, titleLabel);
904 info.childMarginTop = style->pixelMetric(QStyle::PM_LayoutTopMargin, nullptr, titleLabel);
905 info.childMarginBottom = style->pixelMetric(QStyle::PM_LayoutBottomMargin, nullptr, titleLabel);
906 info.hspacing = (layoutHorizontalSpacing == -1)
907 ? style->layoutSpacing(QSizePolicy::DefaultType, QSizePolicy::DefaultType, Qt::Horizontal)
908 : layoutHorizontalSpacing;
909 info.vspacing = style->pixelMetric(QStyle::PM_LayoutVerticalSpacing, &option, q);
910 info.buttonSpacing = (layoutHorizontalSpacing == -1)
911 ? style->layoutSpacing(QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Horizontal)
912 : layoutHorizontalSpacing;
913
914 if (wizStyle == QWizard::MacStyle)
915 info.buttonSpacing = 12;
916
917 info.wizStyle = wizStyle;
918 if (info.wizStyle == QWizard::AeroStyle
919#if QT_CONFIG(style_windowsvista)
920 && vistaDisabled()
921#endif
922 )
923 info.wizStyle = QWizard::ModernStyle;
924
925 QString titleText;
926 QString subTitleText;
927 QPixmap backgroundPixmap;
928 QPixmap watermarkPixmap;
929
930 if (QWizardPage *page = q->currentPage()) {
931 titleText = page->title();
932 subTitleText = page->subTitle();
933 backgroundPixmap = page->pixmap(QWizard::BackgroundPixmap);
934 watermarkPixmap = page->pixmap(QWizard::WatermarkPixmap);
935 }
936
937 info.header = (info.wizStyle == QWizard::ClassicStyle || info.wizStyle == QWizard::ModernStyle)
938 && !(opts & QWizard::IgnoreSubTitles) && !subTitleText.isEmpty();
940 info.watermark = (info.wizStyle != QWizard::MacStyle) && (info.wizStyle != QWizard::AeroStyle)
941 && !watermarkPixmap.isNull();
942 info.title = !info.header && !titleText.isEmpty();
943 info.subTitle = !(opts & QWizard::IgnoreSubTitles) && !info.header && !subTitleText.isEmpty();
944 info.extension = (info.watermark || info.sideWidget) && (opts & QWizard::ExtendedWatermarkPixmap);
945
946 return info;
947}
948
950{
951 Q_Q(QWizard);
952
953 /*
954 Start by undoing the main layout.
955 */
956 for (int i = mainLayout->count() - 1; i >= 0; --i) {
957 QLayoutItem *item = mainLayout->takeAt(i);
958 if (item->layout()) {
959 item->layout()->setParent(nullptr);
960 } else {
961 delete item;
962 }
963 }
964 for (int i = mainLayout->columnCount() - 1; i >= 0; --i)
965 mainLayout->setColumnMinimumWidth(i, 0);
966 for (int i = mainLayout->rowCount() - 1; i >= 0; --i)
967 mainLayout->setRowMinimumHeight(i, 0);
968
969 /*
970 Now, recreate it.
971 */
972
973 bool mac = (info.wizStyle == QWizard::MacStyle);
974 bool classic = (info.wizStyle == QWizard::ClassicStyle);
975 bool modern = (info.wizStyle == QWizard::ModernStyle);
976 bool aero = (info.wizStyle == QWizard::AeroStyle);
977 int deltaMarginLeft = info.topLevelMarginLeft - info.childMarginLeft;
978 int deltaMarginRight = info.topLevelMarginRight - info.childMarginRight;
979 int deltaMarginTop = info.topLevelMarginTop - info.childMarginTop;
980 int deltaMarginBottom = info.topLevelMarginBottom - info.childMarginBottom;
981 int deltaVSpacing = info.topLevelMarginBottom - info.vspacing;
982
983 int row = 0;
984 int numColumns;
985 if (mac) {
986 numColumns = 3;
987 } else if (info.watermark || info.sideWidget) {
988 numColumns = 2;
989 } else {
990 numColumns = 1;
991 }
992 int pageColumn = qMin(1, numColumns - 1);
993
994 if (mac) {
995 mainLayout->setContentsMargins(QMargins());
996 mainLayout->setSpacing(0);
997 buttonLayout->setContentsMargins(MacLayoutLeftMargin, MacButtonTopMargin, MacLayoutRightMargin, MacLayoutBottomMargin);
998 pageVBoxLayout->setContentsMargins(7, 7, 7, 7);
999 } else {
1000 if (modern) {
1001 mainLayout->setContentsMargins(QMargins());
1002 mainLayout->setSpacing(0);
1003 pageVBoxLayout->setContentsMargins(deltaMarginLeft, deltaMarginTop,
1004 deltaMarginRight, deltaMarginBottom);
1005 buttonLayout->setContentsMargins(info.topLevelMarginLeft, info.topLevelMarginTop,
1006 info.topLevelMarginRight, info.topLevelMarginBottom);
1007 } else {
1008 mainLayout->setContentsMargins(info.topLevelMarginLeft, info.topLevelMarginTop,
1009 info.topLevelMarginRight, info.topLevelMarginBottom);
1010 mainLayout->setHorizontalSpacing(info.hspacing);
1011 mainLayout->setVerticalSpacing(info.vspacing);
1012 pageVBoxLayout->setContentsMargins(0, 0, 0, 0);
1013 buttonLayout->setContentsMargins(0, 0, 0, 0);
1014 }
1015 }
1016 buttonLayout->setSpacing(info.buttonSpacing);
1017
1018 if (info.header) {
1019 if (!headerWidget)
1020 headerWidget = new QWizardHeader(antiFlickerWidget);
1021 headerWidget->setAutoFillBackground(modern);
1022 mainLayout->addWidget(headerWidget, row++, 0, 1, numColumns);
1023 }
1024 if (headerWidget)
1025 headerWidget->setVisible(info.header);
1026
1027 int watermarkStartRow = row;
1028
1029 if (mac)
1030 mainLayout->setRowMinimumHeight(row++, 10);
1031
1032 if (info.title) {
1033 if (!titleLabel) {
1034 titleLabel = new QLabel(antiFlickerWidget);
1035 titleLabel->setBackgroundRole(QPalette::Base);
1036 titleLabel->setWordWrap(true);
1037 }
1038
1039 QFont titleFont = q->font();
1040 titleFont.setPointSize(titleFont.pointSize() + (mac ? 3 : 4));
1041 titleFont.setBold(true);
1042 titleLabel->setPalette(QPalette());
1043
1044 if (aero) {
1045 // ### hardcoded for now:
1046 titleFont = QFont("Segoe UI"_L1, 12);
1047 QPalette pal(titleLabel->palette());
1048 pal.setColor(QPalette::Text, QColor(0x00, 0x33, 0x99));
1049 titleLabel->setPalette(pal);
1050 }
1051
1052 titleLabel->setFont(titleFont);
1053 const int aeroTitleIndent = 25; // ### hardcoded for now - should be calculated somehow
1054 if (aero)
1055 titleLabel->setIndent(aeroTitleIndent);
1056 else if (mac)
1057 titleLabel->setIndent(2);
1058 else if (classic)
1059 titleLabel->setIndent(info.childMarginLeft);
1060 else
1061 titleLabel->setIndent(info.topLevelMarginLeft);
1062 if (modern) {
1063 if (!placeholderWidget1) {
1064 placeholderWidget1 = new QWidget(antiFlickerWidget);
1065 placeholderWidget1->setBackgroundRole(QPalette::Base);
1066 }
1067 placeholderWidget1->setFixedHeight(info.topLevelMarginLeft + 2);
1068 mainLayout->addWidget(placeholderWidget1, row++, pageColumn);
1069 }
1070 mainLayout->addWidget(titleLabel, row++, pageColumn);
1071 if (modern) {
1072 if (!placeholderWidget2) {
1073 placeholderWidget2 = new QWidget(antiFlickerWidget);
1074 placeholderWidget2->setBackgroundRole(QPalette::Base);
1075 }
1076 placeholderWidget2->setFixedHeight(5);
1077 mainLayout->addWidget(placeholderWidget2, row++, pageColumn);
1078 }
1079 if (mac)
1080 mainLayout->setRowMinimumHeight(row++, 7);
1081 }
1083 placeholderWidget1->setVisible(info.title && modern);
1085 placeholderWidget2->setVisible(info.title && modern);
1086
1087 if (info.subTitle) {
1088 if (!subTitleLabel) {
1089 subTitleLabel = new QLabel(pageFrame);
1090 subTitleLabel->setWordWrap(true);
1091
1092 subTitleLabel->setContentsMargins(info.childMarginLeft , 0,
1093 info.childMarginRight , 0);
1094
1095 pageVBoxLayout->insertWidget(1, subTitleLabel);
1096 }
1097 }
1098
1099 // ### try to replace with margin.
1100 changeSpacerSize(pageVBoxLayout, 0, 0, info.subTitle ? info.childMarginLeft : 0);
1101
1102 int hMargin = mac ? 1 : 0;
1103 int vMargin = hMargin;
1104
1105 pageFrame->setFrameStyle(mac ? (QFrame::Box | QFrame::Raised) : QFrame::NoFrame);
1106 pageFrame->setLineWidth(0);
1107 pageFrame->setMidLineWidth(hMargin);
1108
1109 if (info.header) {
1110 if (modern) {
1111 hMargin = info.topLevelMarginLeft;
1112 vMargin = deltaMarginBottom;
1113 } else if (classic) {
1114 hMargin = deltaMarginLeft + ClassicHMargin;
1115 vMargin = 0;
1116 }
1117 }
1118
1119 if (aero) {
1120 int leftMargin = 18; // ### hardcoded for now - should be calculated somehow
1121 int topMargin = vMargin;
1122 int rightMargin = hMargin; // ### for now
1123 int bottomMargin = vMargin;
1124 pageFrame->setContentsMargins(leftMargin, topMargin, rightMargin, bottomMargin);
1125 } else {
1126 pageFrame->setContentsMargins(hMargin, vMargin, hMargin, vMargin);
1127 }
1128
1129 if ((info.watermark || info.sideWidget) && !watermarkLabel) {
1130 watermarkLabel = new QWatermarkLabel(antiFlickerWidget, sideWidget);
1131 watermarkLabel->setBackgroundRole(QPalette::Base);
1132 watermarkLabel->setMinimumHeight(1);
1133 watermarkLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
1134 watermarkLabel->setAlignment(Qt::AlignLeft | Qt::AlignTop);
1135 }
1136
1137 //bool wasSemiTransparent = pageFrame->testAttribute(Qt::WA_SetPalette);
1138 const bool wasSemiTransparent =
1139 pageFrame->palette().brush(QPalette::Window).color().alpha() < 255
1140 || pageFrame->palette().brush(QPalette::Base).color().alpha() < 255;
1141 if (mac) {
1142 pageFrame->setAutoFillBackground(true);
1143 antiFlickerWidget->setAutoFillBackground(false);
1144 } else {
1145 if (wasSemiTransparent)
1146 pageFrame->setPalette(QPalette());
1147
1148 bool baseBackground = (modern && !info.header); // ### TAG1
1149 pageFrame->setBackgroundRole(baseBackground ? QPalette::Base : QPalette::Window);
1150
1151 if (titleLabel)
1152 titleLabel->setAutoFillBackground(baseBackground);
1153 pageFrame->setAutoFillBackground(baseBackground);
1154 if (watermarkLabel)
1155 watermarkLabel->setAutoFillBackground(baseBackground);
1157 placeholderWidget1->setAutoFillBackground(baseBackground);
1159 placeholderWidget2->setAutoFillBackground(baseBackground);
1160
1161 if (aero) {
1162 QPalette pal = pageFrame->palette();
1163 pal.setBrush(QPalette::Window, QColor(255, 255, 255));
1164 pageFrame->setPalette(pal);
1165 pageFrame->setAutoFillBackground(true);
1166 pal = antiFlickerWidget->palette();
1167 pal.setBrush(QPalette::Window, QColor(255, 255, 255));
1168 antiFlickerWidget->setPalette(pal);
1169 antiFlickerWidget->setAutoFillBackground(true);
1170 }
1171 }
1172
1173 mainLayout->addWidget(pageFrame, row++, pageColumn);
1174
1175 int watermarkEndRow = row;
1176 if (classic)
1177 mainLayout->setRowMinimumHeight(row++, deltaVSpacing);
1178
1179 if (aero) {
1180 buttonLayout->setContentsMargins(9, 9, 9, 9);
1181 mainLayout->setContentsMargins(0, 11, 0, 0);
1182 }
1183
1184 int buttonStartColumn = info.extension ? 1 : 0;
1185 int buttonNumColumns = info.extension ? 1 : numColumns;
1186
1187 if (classic || modern) {
1188 if (!bottomRuler)
1189 bottomRuler = new QWizardRuler(antiFlickerWidget);
1190 mainLayout->addWidget(bottomRuler, row++, buttonStartColumn, 1, buttonNumColumns);
1191 }
1192
1193 if (classic)
1194 mainLayout->setRowMinimumHeight(row++, deltaVSpacing);
1195
1196 mainLayout->addLayout(buttonLayout, row++, buttonStartColumn, 1, buttonNumColumns);
1197
1198 if (info.watermark || info.sideWidget) {
1199 if (info.extension)
1200 watermarkEndRow = row;
1201 mainLayout->addWidget(watermarkLabel, watermarkStartRow, 0,
1202 watermarkEndRow - watermarkStartRow, 1);
1203 }
1204
1205 mainLayout->setColumnMinimumWidth(0, mac && !info.watermark ? 181 : 0);
1206 if (mac)
1207 mainLayout->setColumnMinimumWidth(2, 21);
1208
1209 if (headerWidget)
1210 headerWidget->setVisible(info.header);
1211 if (titleLabel)
1212 titleLabel->setVisible(info.title);
1213 if (subTitleLabel)
1214 subTitleLabel->setVisible(info.subTitle);
1215 if (bottomRuler)
1216 bottomRuler->setVisible(classic || modern);
1217 if (watermarkLabel)
1218 watermarkLabel->setVisible(info.watermark || info.sideWidget);
1219
1220 layoutInfo = info;
1221}
1222
1224{
1225 Q_Q(QWizard);
1226
1228
1230 if (layoutInfo != info)
1231 recreateLayout(info);
1232 QWizardPage *page = q->currentPage();
1233
1234 // If the page can expand vertically, let it stretch "infinitely" more
1235 // than the QSpacerItem at the bottom. Otherwise, let the QSpacerItem
1236 // stretch "infinitely" more than the page. Change the bottom item's
1237 // policy accordingly. The case that the page has no layout is basically
1238 // for Designer, only.
1239 if (page) {
1240 bool expandPage = !page->layout();
1241 if (!expandPage) {
1242 const QLayoutItem *pageItem = pageVBoxLayout->itemAt(pageVBoxLayout->indexOf(page));
1243 expandPage = pageItem->expandingDirections() & Qt::Vertical;
1244 }
1245 QSpacerItem *bottomSpacer = pageVBoxLayout->itemAt(pageVBoxLayout->count() - 1)->spacerItem();
1246 Q_ASSERT(bottomSpacer);
1247 bottomSpacer->changeSize(0, 0, QSizePolicy::Ignored, expandPage ? QSizePolicy::Ignored : QSizePolicy::MinimumExpanding);
1248 pageVBoxLayout->invalidate();
1249 }
1250
1251 if (info.header) {
1252 Q_ASSERT(page);
1253 headerWidget->setup(info, page->title(), page->subTitle(),
1254 page->pixmap(QWizard::LogoPixmap), page->pixmap(QWizard::BannerPixmap),
1255 titleFmt, subTitleFmt, opts);
1256 }
1257
1258 if (info.watermark || info.sideWidget) {
1259 QPixmap pix;
1260 if (info.watermark) {
1261 if (page)
1262 pix = page->pixmap(QWizard::WatermarkPixmap);
1263 else
1264 pix = q->pixmap(QWizard::WatermarkPixmap);
1265 }
1266 watermarkLabel->setPixmap(pix); // in case there is no watermark and we show the side widget we need to clear the watermark
1267 }
1268
1269 if (info.title) {
1270 Q_ASSERT(page);
1271 titleLabel->setTextFormat(titleFmt);
1272 titleLabel->setText(page->title());
1273 }
1274 if (info.subTitle) {
1275 Q_ASSERT(page);
1276 subTitleLabel->setTextFormat(subTitleFmt);
1277 subTitleLabel->setText(page->subTitle());
1278 }
1279
1282}
1283
1285 if (wizStyle == QWizard::MacStyle) {
1286 // This is required to ensure visual semitransparency when
1287 // switching from ModernStyle to MacStyle.
1288 // See TAG1 in recreateLayout
1289 // This additionally ensures that the colors are correct
1290 // when the theme is changed.
1291
1292 // we should base the new palette on the default one
1293 // so theme colors will be correct
1294 QPalette newPalette = QApplication::palette(pageFrame);
1295
1296 QColor windowColor = newPalette.brush(QPalette::Window).color();
1297 windowColor.setAlpha(153);
1298 newPalette.setBrush(QPalette::Window, windowColor);
1299
1300 QColor baseColor = newPalette.brush(QPalette::Base).color();
1301 baseColor.setAlpha(153);
1302 newPalette.setBrush(QPalette::Base, baseColor);
1303
1304 pageFrame->setPalette(newPalette);
1305 }
1306}
1307
1309{
1310 Q_Q(QWizard);
1311
1312 int extraHeight = 0;
1313#if QT_CONFIG(style_windowsvista)
1314 if (isVistaThemeEnabled())
1315 extraHeight = vistaHelper->titleBarSize() + vistaHelper->topOffset(q);
1316#endif
1317 QSize minimumSize = mainLayout->totalMinimumSize() + QSize(0, extraHeight);
1318 QSize maximumSize = mainLayout->totalMaximumSize();
1319 if (info.header && headerWidget->maximumWidth() != QWIDGETSIZE_MAX) {
1320 minimumSize.setWidth(headerWidget->maximumWidth());
1321 maximumSize.setWidth(headerWidget->maximumWidth());
1322 }
1323 if (info.watermark && !info.sideWidget) {
1324 minimumSize.setHeight(mainLayout->totalSizeHint().height());
1325 }
1326 if (q->minimumWidth() == minimumWidth) {
1327 minimumWidth = minimumSize.width();
1328 q->setMinimumWidth(minimumWidth);
1329 }
1330 if (q->minimumHeight() == minimumHeight) {
1331 minimumHeight = minimumSize.height();
1332 q->setMinimumHeight(minimumHeight);
1333 }
1334 if (q->maximumWidth() == maximumWidth) {
1335 maximumWidth = maximumSize.width();
1336 q->setMaximumWidth(maximumWidth);
1337 }
1338 if (q->maximumHeight() == maximumHeight) {
1339 maximumHeight = maximumSize.height();
1340 q->setMaximumHeight(maximumHeight);
1341 }
1342}
1343
1345{
1346 Q_Q(QWizard);
1347 if (q->currentPage()) {
1348 canContinue = (q->nextId() != -1);
1349 canFinish = q->currentPage()->isFinalPage();
1350 } else {
1351 canContinue = false;
1352 canFinish = false;
1353 }
1356}
1357
1358static QString object_name_for_button(QWizard::WizardButton which)
1359{
1360 switch (which) {
1361 case QWizard::CommitButton:
1362 return u"qt_wizard_commit"_s;
1363 case QWizard::FinishButton:
1364 return u"qt_wizard_finish"_s;
1365 case QWizard::CancelButton:
1366 return u"qt_wizard_cancel"_s;
1367 case QWizard::BackButton:
1368 case QWizard::NextButton:
1369 case QWizard::HelpButton:
1370 case QWizard::CustomButton1:
1371 case QWizard::CustomButton2:
1372 case QWizard::CustomButton3:
1373 // Make navigation buttons detectable as passive interactor in designer
1374 return "__qt__passive_wizardbutton"_L1 + QString::number(which);
1375 case QWizard::Stretch:
1376 case QWizard::NoButton:
1377 //case QWizard::NStandardButtons:
1378 //case QWizard::NButtons:
1379 ;
1380 }
1381 Q_UNREACHABLE_RETURN(QString());
1382}
1383
1384bool QWizardPrivate::ensureButton(QWizard::WizardButton which) const
1385{
1386 Q_Q(const QWizard);
1387 if (uint(which) >= QWizard::NButtons)
1388 return false;
1389
1390 if (!btns[which]) {
1391 QPushButton *pushButton = new QPushButton(antiFlickerWidget);
1392 QStyle *style = q->style();
1393 if (style != QApplication::style()) // Propagate style
1394 pushButton->setStyle(style);
1395 pushButton->setObjectName(object_name_for_button(which));
1396#ifdef Q_OS_MACOS
1397 pushButton->setAutoDefault(false);
1398#endif
1399 pushButton->hide();
1400#ifdef Q_CC_HPACC
1401 const_cast<QWizardPrivate *>(this)->btns[which] = pushButton;
1402#else
1403 btns[which] = pushButton;
1404#endif
1405 if (which < QWizard::NStandardButtons)
1406 pushButton->setText(buttonDefaultText(wizStyle, which, this));
1407
1408 connectButton(which);
1409 }
1410 return true;
1411}
1412
1413void QWizardPrivate::connectButton(QWizard::WizardButton which) const
1414{
1415 Q_Q(const QWizard);
1416 if (which < QWizard::NStandardButtons) {
1417 QObject::connect(btns[which], SIGNAL(clicked()), q, buttonSlots(which));
1418 } else {
1419 QObject::connect(btns[which], SIGNAL(clicked()), q, SLOT(_q_emitCustomButtonClicked()));
1420 }
1421}
1422
1424{
1425 Q_Q(QWizard);
1426 for (int i = 0; i < QWizard::NButtons; ++i) {
1427 if (btns[i]) {
1428 if (q->currentPage() && (q->currentPage()->d_func()->buttonCustomTexts.contains(i)))
1429 btns[i]->setText(q->currentPage()->d_func()->buttonCustomTexts.value(i));
1430 else if (buttonCustomTexts.contains(i))
1431 btns[i]->setText(buttonCustomTexts.value(i));
1432 else if (i < QWizard::NStandardButtons)
1433 btns[i]->setText(buttonDefaultText(wizStyle, i, this));
1434 }
1435 }
1436 // Vista: Add shortcut for 'next'. Note: native dialogs use ALT-Right
1437 // even in RTL mode, so do the same, even if it might be counter-intuitive.
1438 // The shortcut for 'back' is set in class QVistaBackButton.
1439#if QT_CONFIG(shortcut) && QT_CONFIG(style_windowsvista)
1440 if (btns[QWizard::NextButton] && isVistaThemeEnabled()) {
1441 if (vistaNextShortcut.isNull()) {
1442 vistaNextShortcut =
1443 new QShortcut(QKeySequence(Qt::ALT | Qt::Key_Right),
1444 btns[QWizard::NextButton], SLOT(animateClick()));
1445 }
1446 } else {
1447 delete vistaNextShortcut;
1448 }
1449#endif // shortcut && style_windowsvista
1450}
1451
1453{
1455 QVarLengthArray<QWizard::WizardButton, QWizard::NButtons> array{
1456 buttonsCustomLayout.cbegin(), buttonsCustomLayout.cend()};
1457 setButtonLayout(array.constData(), int(array.size()));
1458 } else {
1459 // Positions:
1460 // Help Stretch Custom1 Custom2 Custom3 Cancel Back Next Commit Finish Cancel Help
1461
1462 const int ArraySize = 12;
1463 QWizard::WizardButton array[ArraySize];
1464 memset(array, -1, sizeof(array));
1465 Q_ASSERT(array[0] == QWizard::NoButton);
1466
1467 if (opts & QWizard::HaveHelpButton) {
1468 int i = (opts & QWizard::HelpButtonOnRight) ? 11 : 0;
1469 array[i] = QWizard::HelpButton;
1470 }
1471 array[1] = QWizard::Stretch;
1472 if (opts & QWizard::HaveCustomButton1)
1473 array[2] = QWizard::CustomButton1;
1474 if (opts & QWizard::HaveCustomButton2)
1475 array[3] = QWizard::CustomButton2;
1476 if (opts & QWizard::HaveCustomButton3)
1477 array[4] = QWizard::CustomButton3;
1478
1479 if (!(opts & QWizard::NoCancelButton)) {
1480 int i = (opts & QWizard::CancelButtonOnLeft) ? 5 : 10;
1481 array[i] = QWizard::CancelButton;
1482 }
1483 array[6] = QWizard::BackButton;
1484 array[7] = QWizard::NextButton;
1485 array[8] = QWizard::CommitButton;
1486 array[9] = QWizard::FinishButton;
1487
1488 setButtonLayout(array, ArraySize);
1489 }
1490}
1491
1492void QWizardPrivate::setButtonLayout(const QWizard::WizardButton *array, int size)
1493{
1494 QWidget *prev = pageFrame;
1495
1496 for (int i = buttonLayout->count() - 1; i >= 0; --i) {
1497 QLayoutItem *item = buttonLayout->takeAt(i);
1498 if (QWidget *widget = item->widget())
1499 widget->hide();
1500 delete item;
1501 }
1502
1503 for (int i = 0; i < size; ++i) {
1504 QWizard::WizardButton which = array[i];
1505 if (which == QWizard::Stretch) {
1506 buttonLayout->addStretch(1);
1507 } else if (which != QWizard::NoButton) {
1508 ensureButton(which);
1509 buttonLayout->addWidget(btns[which]);
1510
1511 // Back, Next, Commit, and Finish are handled in _q_updateButtonStates()
1512 if (which != QWizard::BackButton && which != QWizard::NextButton
1513 && which != QWizard::CommitButton && which != QWizard::FinishButton)
1514 btns[which]->show();
1515
1516 if (prev)
1517 QWidget::setTabOrder(prev, btns[which]);
1518 prev = btns[which];
1519 }
1520 }
1521
1523}
1524
1525bool QWizardPrivate::buttonLayoutContains(QWizard::WizardButton which)
1526{
1527 return !buttonsHaveCustomLayout || buttonsCustomLayout.contains(which);
1528}
1529
1530void QWizardPrivate::updatePixmap(QWizard::WizardPixmap which)
1531{
1532 Q_Q(QWizard);
1533 if (which == QWizard::BackgroundPixmap) {
1534 if (wizStyle == QWizard::MacStyle) {
1535 q->update();
1536 q->updateGeometry();
1537 }
1538 } else {
1540 }
1541}
1542
1543#if QT_CONFIG(style_windowsvista)
1544bool QWizardPrivate::vistaDisabled() const
1545{
1546 Q_Q(const QWizard);
1547 const QVariant v = q->property("_q_wizard_vista_off");
1548 return v.isValid() && v.toBool();
1549}
1550
1551bool QWizardPrivate::handleAeroStyleChange()
1552{
1553 Q_Q(QWizard);
1554
1555 if (inHandleAeroStyleChange)
1556 return false; // prevent recursion
1557 // For top-level wizards, we need the platform window handle for the
1558 // DWM changes. Delay aero initialization to the show event handling if
1559 // it does not exist. If we are a child, skip DWM and just make room by
1560 // moving the antiFlickerWidget.
1561 const bool isWindow = q->isWindow();
1562 if (isWindow && (!q->windowHandle() || !q->windowHandle()->handle()))
1563 return false;
1564 inHandleAeroStyleChange = true;
1565
1566 vistaHelper->disconnectBackButton();
1567 q->removeEventFilter(vistaHelper);
1568
1569 bool vistaMargins = false;
1570
1571 if (isVistaThemeEnabled()) {
1572 const int topOffset = vistaHelper->topOffset(q);
1573 const int topPadding = vistaHelper->topPadding(q);
1574 if (isWindow) {
1575 vistaHelper->setDWMTitleBar(QVistaHelper::ExtendedTitleBar);
1576 q->installEventFilter(vistaHelper);
1577 }
1578 q->setMouseTracking(true);
1579 antiFlickerWidget->move(0, vistaHelper->titleBarSize() + topOffset);
1580 vistaHelper->backButton()->move(
1581 0, topOffset // ### should ideally work without the '+ 1'
1582 - qMin(topOffset, topPadding + 1));
1583 vistaMargins = true;
1584 vistaHelper->backButton()->show();
1585 if (isWindow)
1586 vistaHelper->setTitleBarIconAndCaptionVisible(false);
1587 QObject::connect(
1588 vistaHelper->backButton(), SIGNAL(clicked()), q, buttonSlots(QWizard::BackButton));
1589 vistaHelper->backButton()->show();
1590 } else {
1591 q->setMouseTracking(true); // ### original value possibly different
1592#ifndef QT_NO_CURSOR
1593 q->unsetCursor(); // ### ditto
1594#endif
1595 antiFlickerWidget->move(0, 0);
1596 vistaHelper->hideBackButton();
1597 if (isWindow)
1598 vistaHelper->setTitleBarIconAndCaptionVisible(true);
1599 }
1600
1601 _q_updateButtonStates();
1602
1603 vistaHelper->updateCustomMargins(vistaMargins);
1604
1605 inHandleAeroStyleChange = false;
1606 return true;
1607}
1608#endif
1609
1611{
1612#if QT_CONFIG(style_windowsvista)
1613 return wizStyle == QWizard::AeroStyle && !vistaDisabled();
1614#else
1615 return false;
1616#endif
1617}
1618
1620{
1621 Q_Q(QWizard);
1622 if (disableUpdatesCount++ == 0) {
1623 q->setUpdatesEnabled(false);
1624 antiFlickerWidget->hide();
1625 }
1626}
1627
1629{
1630 Q_Q(QWizard);
1631 if (--disableUpdatesCount == 0) {
1632 antiFlickerWidget->show();
1633 q->setUpdatesEnabled(true);
1634 }
1635}
1636
1638{
1639 Q_Q(QWizard);
1640 QObject *button = q->sender();
1641 for (int i = QWizard::NStandardButtons; i < QWizard::NButtons; ++i) {
1642 if (btns[i] == button) {
1643 emit q->customButtonClicked(QWizard::WizardButton(i));
1644 break;
1645 }
1646 }
1647}
1648
1650{
1651 Q_Q(QWizard);
1652
1654
1655 const QWizardPage *page = q->currentPage();
1656 bool complete = page && page->isComplete();
1657
1658 btn.back->setEnabled(history.size() > 1
1659 && !q->page(history.at(history.size() - 2))->isCommitPage()
1660 && (!canFinish || !(opts & QWizard::DisabledBackButtonOnLastPage)));
1661 btn.next->setEnabled(canContinue && complete);
1662 btn.commit->setEnabled(canContinue && complete);
1663 btn.finish->setEnabled(canFinish && complete);
1664
1665 const bool backButtonVisible = buttonLayoutContains(QWizard::BackButton)
1666 && (history.size() > 1 || !(opts & QWizard::NoBackButtonOnStartPage))
1667 && (canContinue || !(opts & QWizard::NoBackButtonOnLastPage));
1668 bool commitPage = page && page->isCommitPage();
1669 btn.back->setVisible(backButtonVisible);
1670 btn.next->setVisible(buttonLayoutContains(QWizard::NextButton) && !commitPage
1671 && (canContinue || (opts & QWizard::HaveNextButtonOnLastPage)));
1672 btn.commit->setVisible(buttonLayoutContains(QWizard::CommitButton) && commitPage
1673 && canContinue);
1674 btn.finish->setVisible(buttonLayoutContains(QWizard::FinishButton)
1675 && (canFinish || (opts & QWizard::HaveFinishButtonOnEarlyPages)));
1676
1677 if (!(opts & QWizard::NoCancelButton))
1678 btn.cancel->setVisible(buttonLayoutContains(QWizard::CancelButton)
1679 && (canContinue || !(opts & QWizard::NoCancelButtonOnLastPage)));
1680
1681 bool useDefault = !(opts & QWizard::NoDefaultButton);
1682 if (QPushButton *nextPush = qobject_cast<QPushButton *>(btn.next))
1683 nextPush->setDefault(canContinue && useDefault && !commitPage);
1684 if (QPushButton *commitPush = qobject_cast<QPushButton *>(btn.commit))
1685 commitPush->setDefault(canContinue && useDefault && commitPage);
1686 if (QPushButton *finishPush = qobject_cast<QPushButton *>(btn.finish))
1687 finishPush->setDefault(!canContinue && useDefault);
1688
1689#if QT_CONFIG(style_windowsvista)
1690 if (isVistaThemeEnabled()) {
1691 vistaHelper->backButton()->setEnabled(btn.back->isEnabled());
1692 vistaHelper->backButton()->setVisible(backButtonVisible);
1693 btn.back->setVisible(false);
1694 }
1695#endif
1696
1698}
1699
1701{
1702 int destroyed_index = -1;
1703 QList<QWizardField>::iterator it = fields.begin();
1704 while (it != fields.end()) {
1705 const QWizardField &field = *it;
1706 if (field.object == object) {
1707 destroyed_index = fieldIndexMap.value(field.name, -1);
1708 fieldIndexMap.remove(field.name);
1709 it = fields.erase(it);
1710 } else {
1711 ++it;
1712 }
1713 }
1714 if (destroyed_index != -1) {
1715 QMap<QString, int>::iterator it2 = fieldIndexMap.begin();
1716 while (it2 != fieldIndexMap.end()) {
1717 int index = it2.value();
1718 if (index > destroyed_index) {
1719 QString field_name = it2.key();
1720 fieldIndexMap.insert(field_name, index-1);
1721 }
1722 ++it2;
1723 }
1724 }
1725}
1726
1727void QWizardPrivate::setStyle(QStyle *style)
1728{
1729 for (int i = 0; i < QWizard::NButtons; i++)
1730 if (btns[i])
1731 btns[i]->setStyle(style);
1732 const PageMap::const_iterator pcend = pageMap.constEnd();
1733 for (PageMap::const_iterator it = pageMap.constBegin(); it != pcend; ++it)
1734 it.value()->setStyle(style);
1735}
1736
1737#ifdef Q_OS_MACOS
1738QPixmap QWizardPrivate::findDefaultBackgroundPixmap()
1739{
1740 auto *keyboardAssistantURL = [NSWorkspace.sharedWorkspace
1741 URLForApplicationWithBundleIdentifier:@"com.apple.KeyboardSetupAssistant"];
1742 auto *keyboardAssistantBundle = [NSBundle bundleWithURL:keyboardAssistantURL];
1743 auto *assistantBackground = [keyboardAssistantBundle imageForResource:@"Background"];
1744 auto size = QSizeF::fromCGSize(assistantBackground.size);
1745 static const QSizeF expectedSize(242, 414);
1746 if (size == expectedSize)
1747 return qt_mac_toQPixmap(assistantBackground, size);
1748
1749 return QPixmap();
1750}
1751#endif
1752
1753#if QT_CONFIG(style_windowsvista)
1754void QWizardAntiFlickerWidget::paintEvent(QPaintEvent *)
1755{
1756 if (wizardPrivate->isVistaThemeEnabled()) {
1757 int leftMargin, topMargin, rightMargin, bottomMargin;
1758 wizardPrivate->buttonLayout->getContentsMargins(
1759 &leftMargin, &topMargin, &rightMargin, &bottomMargin);
1760 const int buttonLayoutTop = wizardPrivate->buttonLayout->contentsRect().top() - topMargin;
1761 QPainter painter(this);
1762 const QBrush brush(QColor(240, 240, 240)); // ### hardcoded for now
1763 painter.fillRect(0, buttonLayoutTop, width(), height() - buttonLayoutTop, brush);
1764 painter.setPen(QPen(QBrush(QColor(223, 223, 223)), 0)); // ### hardcoded for now
1765 painter.drawLine(0, buttonLayoutTop, width(), buttonLayoutTop);
1766 }
1767}
1768#endif
1769
1770/*!
1771 \class QWizard
1772 \brief The QWizard class provides a framework for wizards.
1773
1774 \inmodule QtWidgets
1775
1776 A wizard (also called an assistant on \macos) is a special type
1777 of input dialog that consists of a sequence of pages. A wizard's
1778 purpose is to guide the user through a process step by step.
1779 Wizards are useful for complex or infrequent tasks that users may
1780 find difficult to learn.
1781
1782 QWizard inherits QDialog and represents a wizard. Each page is a
1783 QWizardPage (a QWidget subclass). To create your own wizards, you
1784 can use these classes directly, or you can subclass them for more
1785 control.
1786
1787 \section1 A Trivial Example
1788
1789 The following example illustrates how to create wizard pages and
1790 add them to a wizard. For more advanced examples, see the
1791 \l{dialogs/licensewizard}{License Wizard}.
1792
1793 \snippet dialogs/trivialwizard/trivialwizard.cpp 1
1794 \snippet dialogs/trivialwizard/trivialwizard.cpp 3
1795 \dots
1796 \snippet dialogs/trivialwizard/trivialwizard.cpp 4
1797 \codeline
1798 \snippet dialogs/trivialwizard/trivialwizard.cpp 5
1799 \snippet dialogs/trivialwizard/trivialwizard.cpp 7
1800 \dots
1801 \snippet dialogs/trivialwizard/trivialwizard.cpp 8
1802 \codeline
1803 \snippet dialogs/trivialwizard/trivialwizard.cpp 10
1804
1805 \section1 Wizard Look and Feel
1806
1807 QWizard supports four wizard looks:
1808
1809 \list
1810 \li ClassicStyle
1811 \li ModernStyle
1812 \li MacStyle
1813 \li AeroStyle
1814 \endlist
1815
1816 You can explicitly set the look to use using setWizardStyle()
1817 (e.g., if you want the same look on all platforms).
1818
1819 \table
1820 \header \li ClassicStyle
1821 \li ModernStyle
1822 \li MacStyle
1823 \li AeroStyle
1824 \row \li \inlineimage qtwizard-classic1.png {Wizard with ClassicStyle}
1825 \li \inlineimage qtwizard-modern1.png {Wizard with ModernStyle}
1826 \li \inlineimage qtwizard-mac1.png {Wizard with MacStyle}
1827 \li \inlineimage qtwizard-aero1.png {Wizard with AeroStyle}
1828 \row \li \inlineimage qtwizard-classic2.png {Wizard with ClassicStyle}
1829 \li \inlineimage qtwizard-modern2.png {Wizard with ModernStyle}
1830 \li \inlineimage qtwizard-mac2.png {Wizard with MacStyle}
1831 \li \inlineimage qtwizard-aero2.png {Wizard with AeroStyle}
1832 \endtable
1833
1834 Note: AeroStyle has effect only on a Windows Vista system with alpha compositing enabled.
1835 ModernStyle is used as a fallback when this condition is not met.
1836
1837 In addition to the wizard style, there are several options that
1838 control the look and feel of the wizard. These can be set using
1839 setOption() or setOptions(). For example, HaveHelpButton makes
1840 QWizard show a \uicontrol Help button along with the other wizard
1841 buttons.
1842
1843 You can even change the order of the wizard buttons to any
1844 arbitrary order using setButtonLayout(), and you can add up to
1845 three custom buttons (e.g., a \uicontrol Print button) to the button
1846 row. This is achieved by calling setButton() or setButtonText()
1847 with CustomButton1, CustomButton2, or CustomButton3 to set up the
1848 button, and by enabling the HaveCustomButton1, HaveCustomButton2,
1849 or HaveCustomButton3 options. Whenever the user clicks a custom
1850 button, customButtonClicked() is emitted. For example:
1851
1852 \snippet dialogs/licensewizard/licensewizard.cpp 29
1853
1854 \section1 Elements of a Wizard Page
1855
1856 Wizards consist of a sequence of \l{QWizardPage}s. At any time,
1857 only one page is shown. A page has the following attributes:
1858
1859 \list
1860 \li A \l{QWizardPage::}{title}.
1861 \li A \l{QWizardPage::}{subTitle}.
1862 \li A set of pixmaps, which may or may not be honored, depending
1863 on the wizard's style:
1864 \list
1865 \li WatermarkPixmap (used by ClassicStyle and ModernStyle)
1866 \li BannerPixmap (used by ModernStyle)
1867 \li LogoPixmap (used by ClassicStyle and ModernStyle)
1868 \li BackgroundPixmap (used by MacStyle)
1869 \endlist
1870 \endlist
1871
1872 The diagram belows shows how QWizard renders these attributes,
1873 assuming they are all present and ModernStyle is used:
1874
1875 \image qtwizard-nonmacpage.png {Attributes on a wizard page}
1876
1877 When a \l{QWizardPage::}{subTitle} is set, QWizard displays it
1878 in a header, in which case it also uses the BannerPixmap and the
1879 LogoPixmap to decorate the header. The WatermarkPixmap is
1880 displayed on the left side, below the header. At the bottom,
1881 there is a row of buttons allowing the user to navigate through
1882 the pages.
1883
1884 The page itself (the \l{QWizardPage} widget) occupies the area
1885 between the header, the watermark, and the button row. Typically,
1886 the page is a QWizardPage on which a QGridLayout is installed,
1887 with standard child widgets (\l{QLabel}s, \l{QLineEdit}s, etc.).
1888
1889 If the wizard's style is MacStyle, the page looks radically
1890 different:
1891
1892 \image qtwizard-macpage.png {Attributes on a wizard page using MacStyle}
1893
1894 The watermark, banner, and logo pixmaps are ignored by the
1895 MacStyle. If the BackgroundPixmap is set, it is used as the
1896 background for the wizard; otherwise, a default "assistant" image
1897 is used.
1898
1899 The title and subtitle are set by calling
1900 QWizardPage::setTitle() and QWizardPage::setSubTitle() on the
1901 individual pages. They may be plain text or HTML (see titleFormat
1902 and subTitleFormat). The pixmaps can be set globally for the
1903 entire wizard using setPixmap(), or on a per-page basis using
1904 QWizardPage::setPixmap().
1905
1906 \target field mechanism
1907 \section1 Registering and Using Fields
1908
1909 In many wizards, the contents of a page may affect the default
1910 values of the fields of a later page. To make it easy to
1911 communicate between pages, QWizard supports a "field" mechanism
1912 that allows you to register a field (e.g., a QLineEdit) on a page
1913 and to access its value from any page. It is also possible to
1914 specify mandatory fields (i.e., fields that must be filled before
1915 the user can advance to the next page).
1916
1917 To register a field, call QWizardPage::registerField() field.
1918 For example:
1919
1920 \snippet dialogs/licensewizard/licensewizard.cpp 21
1921
1922 The above code registers three fields, \c className, \c
1923 baseClass, and \c qobjectMacro, which are associated with three
1924 child widgets. The asterisk (\c *) next to \c className denotes a
1925 mandatory field.
1926
1927 \target initialize page
1928 The fields of any page are accessible from any other page. For
1929 example:
1930
1931 \snippet dialogs/licensewizard/licensewizard.cpp 27
1932
1933 Here, we call QWizardPage::field() to access the contents of the
1934 \c details.email field (which was defined in the \c DetailsPage)
1935 and use it to initialize the \c ConclusionPage. The field's
1936 contents is returned as a QVariant.
1937
1938 When we create a field using QWizardPage::registerField(), we
1939 pass a unique field name and a widget. We can also provide a Qt
1940 property name and a "changed" signal (a signal that is emitted
1941 when the property changes) as third and fourth arguments;
1942 however, this is not necessary for the most common Qt widgets,
1943 such as QLineEdit, QCheckBox, and QComboBox, because QWizard
1944 knows which properties to look for.
1945
1946 \target mandatory fields
1947
1948 If an asterisk (\c *) is appended to the name when the property
1949 is registered, the field is a \e{mandatory field}. When a page has
1950 mandatory fields, the \uicontrol Next and/or \uicontrol Finish buttons are
1951 enabled only when all mandatory fields are filled.
1952
1953 To consider a field "filled", QWizard simply checks that the
1954 field's current value doesn't equal the original value (the value
1955 it had when initializePage() was called). For QLineEdit and
1956 QAbstractSpinBox subclasses, QWizard also checks that
1957 \l{QLineEdit::hasAcceptableInput()}{hasAcceptableInput()} returns
1958 true, to honor any validator or mask.
1959
1960 QWizard's mandatory field mechanism is provided for convenience.
1961 A more powerful (but also more cumbersome) alternative is to
1962 reimplement QWizardPage::isComplete() and to emit the
1963 QWizardPage::completeChanged() signal whenever the page becomes
1964 complete or incomplete.
1965
1966 The enabled/disabled state of the \uicontrol Next and/or \uicontrol Finish
1967 buttons is one way to perform validation on the user input.
1968 Another way is to reimplement validateCurrentPage() (or
1969 QWizardPage::validatePage()) to perform some last-minute
1970 validation (and show an error message if the user has entered
1971 incomplete or invalid information). If the function returns \c true,
1972 the next page is shown (or the wizard finishes); otherwise, the
1973 current page stays up.
1974
1975 \section1 Creating Linear Wizards
1976
1977 Most wizards have a linear structure, with page 1 followed by
1978 page 2 and so on until the last page. The \l{dialogs/trivialwizard}
1979 {Trivial Wizard} example is such a wizard. With QWizard, linear wizards
1980 are created by instantiating the \l{QWizardPage}s and inserting
1981 them using addPage(). By default, the pages are shown in the
1982 order in which they were added. For example:
1983
1984 \snippet dialogs/trivialwizard/trivialwizard.cpp linearAddPage
1985
1986 When a page is about to be shown, QWizard calls initializePage()
1987 (which in turn calls QWizardPage::initializePage()) to fill the
1988 page with default values. By default, this function does nothing,
1989 but it can be reimplemented to initialize the page's contents
1990 based on other pages' fields (see the \l{initialize page}{example
1991 above}).
1992
1993 If the user presses \uicontrol Back, cleanupPage() is called (which in
1994 turn calls QWizardPage::cleanupPage()). The default
1995 implementation resets the page's fields to their original values
1996 (the values they had before initializePage() was called). If you
1997 want the \uicontrol Back button to be non-destructive and keep the
1998 values entered by the user, simply enable the IndependentPages
1999 option.
2000
2001 \section1 Creating Non-Linear Wizards
2002
2003 Some wizards are more complex in that they allow different
2004 traversal paths based on the information provided by the user.
2005 The \l{dialogs/licensewizard}{License Wizard} example illustrates this.
2006 It provides several wizard pages; depending on which options are
2007 selected, the user can reach different pages.
2008
2009 \image licensewizard-flow.png {Complex wizard page flow chart}
2010
2011 In complex wizards, pages are identified by IDs. These IDs are
2012 typically defined using an enum. For example:
2013
2014 \snippet dialogs/licensewizard/licensewizard.h 0
2015 \dots
2016 \snippet dialogs/licensewizard/licensewizard.h 2
2017 \dots
2018 \snippet dialogs/licensewizard/licensewizard.h 3
2019
2020 The pages are inserted using setPage(), which takes an ID and an
2021 instance of QWizardPage (or of a subclass):
2022
2023 \snippet dialogs/licensewizard/licensewizard.cpp 1
2024 \dots
2025 \snippet dialogs/licensewizard/licensewizard.cpp 8
2026
2027 By default, the pages are shown in increasing ID order. To
2028 provide a dynamic order that depends on the options chosen by the
2029 user, we must reimplement QWizardPage::nextId(). For example:
2030
2031 \snippet dialogs/licensewizard/licensewizard.cpp 18
2032 \codeline
2033 \snippet dialogs/licensewizard/licensewizard.cpp 23
2034 \codeline
2035 \snippet dialogs/licensewizard/licensewizard.cpp 24
2036 \codeline
2037 \snippet dialogs/licensewizard/licensewizard.cpp 25
2038 \codeline
2039 \snippet dialogs/licensewizard/licensewizard.cpp 26
2040
2041 It would also be possible to put all the logic in one place, in a
2042 QWizard::nextId() reimplementation. For example:
2043
2044 \snippet code/src_gui_dialogs_qwizard.cpp 0
2045
2046 To start at another page than the page with the lowest ID, call
2047 setStartId().
2048
2049 To test whether a page has been visited or not, call
2050 hasVisitedPage(). For example:
2051
2052 \snippet dialogs/licensewizard/licensewizard.cpp 27
2053
2054 \sa QWizardPage, {Trivial Wizard Example}, {License Wizard Example}
2055*/
2056
2057/*!
2058 \enum QWizard::WizardButton
2059
2060 This enum specifies the buttons in a wizard.
2061
2062 \value BackButton The \uicontrol Back button (\uicontrol {Go Back} on \macos)
2063 \value NextButton The \uicontrol Next button (\uicontrol Continue on \macos)
2064 \value CommitButton The \uicontrol Commit button
2065 \value FinishButton The \uicontrol Finish button (\uicontrol Done on \macos)
2066 \value CancelButton The \uicontrol Cancel button (see also NoCancelButton)
2067 \value HelpButton The \uicontrol Help button (see also HaveHelpButton)
2068 \value CustomButton1 The first user-defined button (see also HaveCustomButton1)
2069 \value CustomButton2 The second user-defined button (see also HaveCustomButton2)
2070 \value CustomButton3 The third user-defined button (see also HaveCustomButton3)
2071
2072 The following value is only useful when calling setButtonLayout():
2073
2074 \value Stretch A horizontal stretch in the button layout
2075
2076 \omitvalue NoButton
2077 \omitvalue NStandardButtons
2078 \omitvalue NButtons
2079
2080 \sa setButton(), setButtonText(), setButtonLayout(), customButtonClicked()
2081*/
2082
2083/*!
2084 \enum QWizard::WizardPixmap
2085
2086 This enum specifies the pixmaps that can be associated with a page.
2087
2088 \value WatermarkPixmap The tall pixmap on the left side of a ClassicStyle or ModernStyle page
2089 \value LogoPixmap The small pixmap on the right side of a ClassicStyle or ModernStyle page header
2090 \value BannerPixmap The pixmap that occupies the background of a ModernStyle page header
2091 \value BackgroundPixmap The pixmap that occupies the background of a MacStyle wizard
2092
2093 \omitvalue NPixmaps
2094
2095 \sa setPixmap(), QWizardPage::setPixmap(), {Elements of a Wizard Page}
2096*/
2097
2098/*!
2099 \enum QWizard::WizardStyle
2100
2101 This enum specifies the different looks supported by QWizard.
2102
2103 \value ClassicStyle Classic Windows look
2104 \value ModernStyle Modern Windows look
2105 \value MacStyle \macos look
2106 \value AeroStyle Windows Aero look
2107
2108 \omitvalue NStyles
2109
2110 \sa setWizardStyle(), WizardOption, {Wizard Look and Feel}
2111*/
2112
2113/*!
2114 \enum QWizard::WizardOption
2115
2116 This enum specifies various options that affect the look and feel
2117 of a wizard.
2118
2119 \value IndependentPages The pages are independent of each other
2120 (i.e., they don't derive values from each
2121 other).
2122 \value IgnoreSubTitles Don't show any subtitles, even if they are set.
2123 \value ExtendedWatermarkPixmap Extend any WatermarkPixmap all the
2124 way down to the window's edge.
2125 \value NoDefaultButton Don't make the \uicontrol Next or \uicontrol Finish button the
2126 dialog's \l{QPushButton::setDefault()}{default button}.
2127 \value NoBackButtonOnStartPage Don't show the \uicontrol Back button on the start page.
2128 \value NoBackButtonOnLastPage Don't show the \uicontrol Back button on the last page.
2129 \value DisabledBackButtonOnLastPage Disable the \uicontrol Back button on the last page.
2130 \value HaveNextButtonOnLastPage Show the (disabled) \uicontrol Next button on the last page.
2131 \value HaveFinishButtonOnEarlyPages Show the (disabled) \uicontrol Finish button on non-final pages.
2132 \value NoCancelButton Don't show the \uicontrol Cancel button.
2133 \value CancelButtonOnLeft Put the \uicontrol Cancel button on the left of \uicontrol Back (rather than on
2134 the right of \uicontrol Finish or \uicontrol Next).
2135 \value HaveHelpButton Show the \uicontrol Help button.
2136 \value HelpButtonOnRight Put the \uicontrol Help button on the far right of the button layout
2137 (rather than on the far left).
2138 \value HaveCustomButton1 Show the first user-defined button (CustomButton1).
2139 \value HaveCustomButton2 Show the second user-defined button (CustomButton2).
2140 \value HaveCustomButton3 Show the third user-defined button (CustomButton3).
2141 \value NoCancelButtonOnLastPage Don't show the \uicontrol Cancel button on the last page.
2142 \value StretchBanner If there is a \l{QWizard::WizardPixmap}{banner}, stretch it across
2143 the entire width of the wizard.
2144
2145 \sa setOptions(), setOption(), testOption()
2146*/
2147
2148/*!
2149 Constructs a wizard with the given \a parent and window \a flags.
2150
2151 \sa parent(), windowFlags()
2152*/
2153QWizard::QWizard(QWidget *parent, Qt::WindowFlags flags)
2154 : QDialog(*new QWizardPrivate, parent, flags)
2155{
2156 Q_D(QWizard);
2157 d->init();
2158}
2159
2160/*!
2161 Destroys the wizard and its pages, releasing any allocated resources.
2162*/
2163QWizard::~QWizard()
2164{
2165 Q_D(QWizard);
2166 delete d->buttonLayout;
2167}
2168
2169/*!
2170 Adds the given \a page to the wizard, and returns the page's ID.
2171
2172 The ID is guaranteed to be larger than any other ID in the
2173 QWizard so far.
2174
2175 \sa setPage(), page(), pageAdded()
2176*/
2177int QWizard::addPage(QWizardPage *page)
2178{
2179 Q_D(QWizard);
2180 int theid = 0;
2181 if (!d->pageMap.isEmpty())
2182 theid = d->pageMap.lastKey() + 1;
2183 setPage(theid, page);
2184 return theid;
2185}
2186
2187/*!
2188 \fn void QWizard::setPage(int id, QWizardPage *page)
2189
2190 Adds the given \a page to the wizard with the given \a id.
2191
2192 \note Adding a page may influence the value of the startId property
2193 in case it was not set explicitly.
2194
2195 \sa addPage(), page(), pageAdded()
2196*/
2197void QWizard::setPage(int theid, QWizardPage *page)
2198{
2199 Q_D(QWizard);
2200
2201 if (Q_UNLIKELY(!page)) {
2202 qWarning("QWizard::setPage: Cannot insert null page");
2203 return;
2204 }
2205
2206 if (Q_UNLIKELY(theid == -1)) {
2207 qWarning("QWizard::setPage: Cannot insert page with ID -1");
2208 return;
2209 }
2210
2211 if (Q_UNLIKELY(d->pageMap.contains(theid))) {
2212 qWarning("QWizard::setPage: Page with duplicate ID %d ignored", theid);
2213 return;
2214 }
2215
2216 page->setParent(d->pageFrame);
2217
2218 QList<QWizardField> &pendingFields = page->d_func()->pendingFields;
2219 for (const auto &field : std::as_const(pendingFields))
2220 d->addField(field);
2221 pendingFields.clear();
2222
2223 connect(page, SIGNAL(completeChanged()), this, SLOT(_q_updateButtonStates()));
2224
2225 d->pageMap.insert(theid, page);
2226 page->d_func()->wizard = this;
2227
2228 int n = d->pageVBoxLayout->count();
2229
2230 // disable layout to prevent layout updates while adding
2231 bool pageVBoxLayoutEnabled = d->pageVBoxLayout->isEnabled();
2232 d->pageVBoxLayout->setEnabled(false);
2233
2234 d->pageVBoxLayout->insertWidget(n - 1, page);
2235
2236 // hide new page and reset layout to old status
2237 page->hide();
2238 d->pageVBoxLayout->setEnabled(pageVBoxLayoutEnabled);
2239
2240 if (!d->startSetByUser && d->pageMap.constBegin().key() == theid)
2241 d->start = theid;
2242 emit pageAdded(theid);
2243}
2244
2245/*!
2246 Removes the page with the given \a id. cleanupPage() will be called if necessary.
2247
2248 \note Removing a page may influence the value of the startId property.
2249
2250 \sa addPage(), setPage(), pageRemoved(), startId()
2251*/
2252void QWizard::removePage(int id)
2253{
2254 Q_D(QWizard);
2255
2256 QWizardPage *removedPage = nullptr;
2257
2258 // update startItem accordingly
2259 if (d->pageMap.size() > 0) { // only if we have any pages
2260 if (d->start == id) {
2261 const int firstId = d->pageMap.constBegin().key();
2262 if (firstId == id) {
2263 if (d->pageMap.size() > 1)
2264 d->start = (++d->pageMap.constBegin()).key(); // secondId
2265 else
2266 d->start = -1; // removing the last page
2267 } else { // startSetByUser has to be "true" here
2268 d->start = firstId;
2269 }
2270 d->startSetByUser = false;
2271 }
2272 }
2273
2274 if (d->pageMap.contains(id))
2275 emit pageRemoved(id);
2276
2277 if (!d->history.contains(id)) {
2278 // Case 1: removing a page not in the history
2279 removedPage = d->pageMap.take(id);
2280 d->updateCurrentPage();
2281 } else if (id != d->current) {
2282 // Case 2: removing a page in the history before the current page
2283 removedPage = d->pageMap.take(id);
2284 d->history.removeOne(id);
2285 d->_q_updateButtonStates();
2286 } else if (d->history.size() == 1) {
2287 // Case 3: removing the current page which is the first (and only) one in the history
2288 d->reset();
2289 removedPage = d->pageMap.take(id);
2290 if (d->pageMap.isEmpty())
2291 d->updateCurrentPage();
2292 else
2293 restart();
2294 } else {
2295 // Case 4: removing the current page which is not the first one in the history
2296 back();
2297 removedPage = d->pageMap.take(id);
2298 d->updateCurrentPage();
2299 }
2300
2301 if (removedPage) {
2302 if (removedPage->d_func()->initialized) {
2303 cleanupPage(id);
2304 removedPage->d_func()->initialized = false;
2305 }
2306
2307 d->pageVBoxLayout->removeWidget(removedPage);
2308
2309 for (int i = d->fields.size() - 1; i >= 0; --i) {
2310 if (d->fields.at(i).page == removedPage) {
2311 removedPage->d_func()->pendingFields += d->fields.at(i);
2312 d->removeFieldAt(i);
2313 }
2314 }
2315 }
2316}
2317
2318/*!
2319 \fn QWizardPage *QWizard::page(int id) const
2320
2321 Returns the page with the given \a id, or \nullptr if there is no
2322 such page.
2323
2324 \sa addPage(), setPage()
2325*/
2326QWizardPage *QWizard::page(int theid) const
2327{
2328 Q_D(const QWizard);
2329 return d->pageMap.value(theid);
2330}
2331
2332/*!
2333 \fn bool QWizard::hasVisitedPage(int id) const
2334
2335 Returns \c true if the page history contains page \a id; otherwise,
2336 returns \c false.
2337
2338 Pressing \uicontrol Back marks the current page as "unvisited" again.
2339
2340 \sa visitedIds()
2341*/
2342bool QWizard::hasVisitedPage(int theid) const
2343{
2344 Q_D(const QWizard);
2345 return d->history.contains(theid);
2346}
2347
2348/*!
2349 \since 5.15
2350
2351 Returns the list of IDs of visited pages, in the order in which the pages
2352 were visited.
2353
2354 \sa hasVisitedPage()
2355*/
2356QList<int> QWizard::visitedIds() const
2357{
2358 Q_D(const QWizard);
2359 return d->history;
2360}
2361
2362/*!
2363 Returns the list of page IDs.
2364*/
2365QList<int> QWizard::pageIds() const
2366{
2367 Q_D(const QWizard);
2368 return d->pageMap.keys();
2369}
2370
2371/*!
2372 \property QWizard::startId
2373 \brief the ID of the first page
2374
2375 If this property isn't explicitly set, this property defaults to
2376 the lowest page ID in this wizard, or -1 if no page has been
2377 inserted yet.
2378
2379 \sa restart(), nextId()
2380*/
2381void QWizard::setStartId(int theid)
2382{
2383 Q_D(QWizard);
2384 int newStart = theid;
2385 if (theid == -1)
2386 newStart = d->pageMap.size() ? d->pageMap.constBegin().key() : -1;
2387
2388 if (d->start == newStart) {
2389 d->startSetByUser = theid != -1;
2390 return;
2391 }
2392
2393 if (Q_UNLIKELY(!d->pageMap.contains(newStart))) {
2394 qWarning("QWizard::setStartId: Invalid page ID %d", newStart);
2395 return;
2396 }
2397 d->start = newStart;
2398 d->startSetByUser = theid != -1;
2399}
2400
2401int QWizard::startId() const
2402{
2403 Q_D(const QWizard);
2404 return d->start;
2405}
2406
2407/*!
2408 Returns a pointer to the current page, or \nullptr if there is no
2409 current page (e.g., before the wizard is shown).
2410
2411 This is equivalent to calling page(currentId()).
2412
2413 \sa page(), currentId(), restart()
2414*/
2415QWizardPage *QWizard::currentPage() const
2416{
2417 Q_D(const QWizard);
2418 return page(d->current);
2419}
2420
2421/*!
2422 \property QWizard::currentId
2423 \brief the ID of the current page
2424
2425 By default, this property has a value of -1, indicating that no page is
2426 currently shown.
2427
2428 \sa currentPage()
2429*/
2430int QWizard::currentId() const
2431{
2432 Q_D(const QWizard);
2433 return d->current;
2434}
2435
2436/*!
2437 Sets the value of the field called \a name to \a value.
2438
2439 This function can be used to set fields on any page of the wizard.
2440
2441 \sa QWizardPage::registerField(), QWizardPage::setField(), field()
2442*/
2443void QWizard::setField(const QString &name, const QVariant &value)
2444{
2445 Q_D(QWizard);
2446
2447 int index = d->fieldIndexMap.value(name, -1);
2448 if (Q_UNLIKELY(index == -1)) {
2449 qWarning("QWizard::setField: No such field '%ls'", qUtf16Printable(name));
2450 return;
2451 }
2452
2453 const QWizardField &field = d->fields.at(index);
2454 if (Q_UNLIKELY(!field.object->setProperty(field.property, value)))
2455 qWarning("QWizard::setField: Couldn't write to property '%s'",
2456 field.property.constData());
2457}
2458
2459/*!
2460 Returns the value of the field called \a name.
2461
2462 This function can be used to access fields on any page of the wizard.
2463
2464 \sa QWizardPage::registerField(), QWizardPage::field(), setField()
2465*/
2466QVariant QWizard::field(const QString &name) const
2467{
2468 Q_D(const QWizard);
2469
2470 int index = d->fieldIndexMap.value(name, -1);
2471 if (Q_UNLIKELY(index == -1)) {
2472 qWarning("QWizard::field: No such field '%ls'", qUtf16Printable(name));
2473 return QVariant();
2474 }
2475
2476 const QWizardField &field = d->fields.at(index);
2477 return field.object->property(field.property);
2478}
2479
2480/*!
2481 \property QWizard::wizardStyle
2482 \brief the look and feel of the wizard
2483
2484 By default, QWizard uses the AeroStyle on a Windows Vista system with alpha compositing
2485 enabled, regardless of the current widget style. If this is not the case, the default
2486 wizard style depends on the current widget style as follows: MacStyle is the default if
2487 the current widget style is QMacStyle, ModernStyle is the default if the current widget
2488 style is QWindowsStyle, and ClassicStyle is the default in all other cases.
2489
2490 \sa {Wizard Look and Feel}, options
2491*/
2492void QWizard::setWizardStyle(WizardStyle style)
2493{
2494 Q_D(QWizard);
2495
2496 const bool styleChange = style != d->wizStyle;
2497
2498#if QT_CONFIG(style_windowsvista)
2499 const bool aeroStyleChange =
2500 d->vistaInitPending || d->vistaStateChanged || (styleChange && (style == AeroStyle || d->wizStyle == AeroStyle));
2501 d->vistaStateChanged = false;
2502 d->vistaInitPending = false;
2503#endif
2504
2505 if (styleChange
2506#if QT_CONFIG(style_windowsvista)
2507 || aeroStyleChange
2508#endif
2509 ) {
2510 d->disableUpdates();
2511 d->wizStyle = style;
2512 d->updateButtonTexts();
2513#if QT_CONFIG(style_windowsvista)
2514 if (aeroStyleChange) {
2515 //Send a resizeevent since the antiflicker widget probably needs a new size
2516 //because of the backbutton in the window title
2517 QResizeEvent ev(geometry().size(), geometry().size());
2518 QCoreApplication::sendEvent(this, &ev);
2519 }
2520#endif
2521 d->updateLayout();
2522 updateGeometry();
2523 d->enableUpdates();
2524#if QT_CONFIG(style_windowsvista)
2525 // Delay initialization when activating Aero style fails due to missing native window.
2526 if (aeroStyleChange && !d->handleAeroStyleChange() && d->wizStyle == AeroStyle)
2527 d->vistaInitPending = true;
2528#endif
2529 }
2530}
2531
2532QWizard::WizardStyle QWizard::wizardStyle() const
2533{
2534 Q_D(const QWizard);
2535 return d->wizStyle;
2536}
2537
2538/*!
2539 Sets the given \a option to be enabled if \a on is true;
2540 otherwise, clears the given \a option.
2541
2542 \sa options, testOption(), setWizardStyle()
2543*/
2544void QWizard::setOption(WizardOption option, bool on)
2545{
2546 Q_D(QWizard);
2547 if (!(d->opts & option) != !on)
2548 setOptions(d->opts ^ option);
2549}
2550
2551/*!
2552 Returns \c true if the given \a option is enabled; otherwise, returns
2553 false.
2554
2555 \sa options, setOption(), setWizardStyle()
2556*/
2557bool QWizard::testOption(WizardOption option) const
2558{
2559 Q_D(const QWizard);
2560 return (d->opts & option) != 0;
2561}
2562
2563/*!
2564 \property QWizard::options
2565 \brief the various options that affect the look and feel of the wizard
2566
2567 By default, the following options are set (depending on the platform):
2568
2569 \list
2570 \li Windows: HelpButtonOnRight.
2571 \li \macos: NoDefaultButton and NoCancelButton.
2572 \li X11 and QWS (Qt for Embedded Linux): none.
2573 \endlist
2574
2575 \sa wizardStyle
2576*/
2577void QWizard::setOptions(WizardOptions options)
2578{
2579 Q_D(QWizard);
2580
2581 WizardOptions changed = (options ^ d->opts);
2582 if (!changed)
2583 return;
2584
2585 d->disableUpdates();
2586
2587 d->opts = options;
2588 if ((changed & IndependentPages) && !(d->opts & IndependentPages))
2589 d->cleanupPagesNotInHistory();
2590
2591 if (changed & (NoDefaultButton | HaveHelpButton | HelpButtonOnRight | NoCancelButton
2592 | CancelButtonOnLeft | HaveCustomButton1 | HaveCustomButton2
2593 | HaveCustomButton3)) {
2594 d->updateButtonLayout();
2595 } else if (changed & (NoBackButtonOnStartPage | NoBackButtonOnLastPage
2596 | HaveNextButtonOnLastPage | HaveFinishButtonOnEarlyPages
2597 | DisabledBackButtonOnLastPage | NoCancelButtonOnLastPage)) {
2598 d->_q_updateButtonStates();
2599 }
2600
2601 d->enableUpdates();
2602 d->updateLayout();
2603}
2604
2605QWizard::WizardOptions QWizard::options() const
2606{
2607 Q_D(const QWizard);
2608 return d->opts;
2609}
2610
2611/*!
2612 Sets the text on button \a which to be \a text.
2613
2614 By default, the text on buttons depends on the wizardStyle. For
2615 example, on \macos, the \uicontrol Next button is called \uicontrol
2616 Continue.
2617
2618 To add extra buttons to the wizard (e.g., a \uicontrol Print button),
2619 one way is to call setButtonText() with CustomButton1,
2620 CustomButton2, or CustomButton3 to set their text, and make the
2621 buttons visible using the HaveCustomButton1, HaveCustomButton2,
2622 and/or HaveCustomButton3 options.
2623
2624 Button texts may also be set on a per-page basis using QWizardPage::setButtonText().
2625
2626 \sa setButton(), button(), setButtonLayout(), setOptions(), QWizardPage::setButtonText()
2627*/
2628void QWizard::setButtonText(WizardButton which, const QString &text)
2629{
2630 Q_D(QWizard);
2631
2632 if (!d->ensureButton(which))
2633 return;
2634
2635 d->buttonCustomTexts.insert(which, text);
2636
2637 if (!currentPage() || !currentPage()->d_func()->buttonCustomTexts.contains(which))
2638 d->btns[which]->setText(text);
2639}
2640
2641/*!
2642 Returns the text on button \a which.
2643
2644 If a text has ben set using setButtonText(), this text is returned.
2645
2646 By default, the text on buttons depends on the wizardStyle. For
2647 example, on \macos, the \uicontrol Next button is called \uicontrol
2648 Continue.
2649
2650 \sa button(), setButton(), setButtonText(), QWizardPage::buttonText(),
2651 QWizardPage::setButtonText()
2652*/
2653QString QWizard::buttonText(WizardButton which) const
2654{
2655 Q_D(const QWizard);
2656
2657 if (!d->ensureButton(which))
2658 return QString();
2659
2660 if (d->buttonCustomTexts.contains(which))
2661 return d->buttonCustomTexts.value(which);
2662
2663 const QString defText = buttonDefaultText(d->wizStyle, which, d);
2664 if (!defText.isNull())
2665 return defText;
2666
2667 return d->btns[which]->text();
2668}
2669
2670/*!
2671 Sets the order in which buttons are displayed to \a layout, where
2672 \a layout is a list of \l{WizardButton}s.
2673
2674 The default layout depends on the options (e.g., whether
2675 HelpButtonOnRight) that are set. You can call this function if
2676 you need more control over the buttons' layout than what \l
2677 options already provides.
2678
2679 You can specify horizontal stretches in the layout using \l
2680 Stretch.
2681
2682 Example:
2683
2684 \snippet code/src_gui_dialogs_qwizard.cpp 1
2685
2686 \sa setButton(), setButtonText(), setOptions()
2687*/
2688void QWizard::setButtonLayout(const QList<WizardButton> &layout)
2689{
2690 Q_D(QWizard);
2691
2692 for (int i = 0; i < layout.size(); ++i) {
2693 WizardButton button1 = layout.at(i);
2694
2695 if (button1 == NoButton || button1 == Stretch)
2696 continue;
2697 if (!d->ensureButton(button1))
2698 return;
2699
2700 // O(n^2), but n is very small
2701 for (int j = 0; j < i; ++j) {
2702 WizardButton button2 = layout.at(j);
2703 if (Q_UNLIKELY(button2 == button1)) {
2704 qWarning("QWizard::setButtonLayout: Duplicate button in layout");
2705 return;
2706 }
2707 }
2708 }
2709
2710 d->buttonsHaveCustomLayout = true;
2711 d->buttonsCustomLayout = layout;
2712 d->updateButtonLayout();
2713}
2714
2715/*!
2716 Sets the button corresponding to role \a which to \a button.
2717
2718 To add extra buttons to the wizard (e.g., a \uicontrol Print button),
2719 one way is to call setButton() with CustomButton1 to
2720 CustomButton3, and make the buttons visible using the
2721 HaveCustomButton1 to HaveCustomButton3 options.
2722
2723 \sa setButtonText(), setButtonLayout(), options
2724*/
2725void QWizard::setButton(WizardButton which, QAbstractButton *button)
2726{
2727 Q_D(QWizard);
2728
2729 if (uint(which) >= NButtons || d->btns[which] == button)
2730 return;
2731
2732 if (QAbstractButton *oldButton = d->btns[which]) {
2733 d->buttonLayout->removeWidget(oldButton);
2734 delete oldButton;
2735 }
2736
2737 d->btns[which] = button;
2738 if (button) {
2739 button->setParent(d->antiFlickerWidget);
2740 d->buttonCustomTexts.insert(which, button->text());
2741 d->connectButton(which);
2742 } else {
2743 d->buttonCustomTexts.remove(which); // ### what about page-specific texts set for 'which'
2744 d->ensureButton(which); // (QWizardPage::setButtonText())? Clear them as well?
2745 }
2746
2747 d->updateButtonLayout();
2748}
2749
2750/*!
2751 Returns the button corresponding to role \a which.
2752
2753 \sa setButton(), setButtonText()
2754*/
2755QAbstractButton *QWizard::button(WizardButton which) const
2756{
2757 Q_D(const QWizard);
2758#if QT_CONFIG(style_windowsvista)
2759 if (d->wizStyle == AeroStyle && which == BackButton)
2760 return d->vistaHelper->backButton();
2761#endif
2762 if (!d->ensureButton(which))
2763 return nullptr;
2764 return d->btns[which];
2765}
2766
2767/*!
2768 \property QWizard::titleFormat
2769 \brief the text format used by page titles
2770
2771 The default format is Qt::AutoText.
2772
2773 \sa QWizardPage::title, subTitleFormat
2774*/
2775void QWizard::setTitleFormat(Qt::TextFormat format)
2776{
2777 Q_D(QWizard);
2778 d->titleFmt = format;
2779 d->updateLayout();
2780}
2781
2782Qt::TextFormat QWizard::titleFormat() const
2783{
2784 Q_D(const QWizard);
2785 return d->titleFmt;
2786}
2787
2788/*!
2789 \property QWizard::subTitleFormat
2790 \brief the text format used by page subtitles
2791
2792 The default format is Qt::AutoText.
2793
2794 \sa QWizardPage::title, titleFormat
2795*/
2796void QWizard::setSubTitleFormat(Qt::TextFormat format)
2797{
2798 Q_D(QWizard);
2799 d->subTitleFmt = format;
2800 d->updateLayout();
2801}
2802
2803Qt::TextFormat QWizard::subTitleFormat() const
2804{
2805 Q_D(const QWizard);
2806 return d->subTitleFmt;
2807}
2808
2809/*!
2810 Sets the pixmap for role \a which to \a pixmap.
2811
2812 The pixmaps are used by QWizard when displaying a page. Which
2813 pixmaps are actually used depend on the \l{Wizard Look and
2814 Feel}{wizard style}.
2815
2816 Pixmaps can also be set for a specific page using
2817 QWizardPage::setPixmap().
2818
2819 \sa QWizardPage::setPixmap(), {Elements of a Wizard Page}
2820*/
2821void QWizard::setPixmap(WizardPixmap which, const QPixmap &pixmap)
2822{
2823 Q_D(QWizard);
2824 Q_ASSERT(uint(which) < NPixmaps);
2825 d->defaultPixmaps[which] = pixmap;
2826 d->updatePixmap(which);
2827}
2828
2829/*!
2830 Returns the pixmap set for role \a which.
2831
2832 By default, the only pixmap that is set is the BackgroundPixmap on
2833 \macos.
2834
2835 \sa QWizardPage::pixmap(), {Elements of a Wizard Page}
2836*/
2837QPixmap QWizard::pixmap(WizardPixmap which) const
2838{
2839 Q_D(const QWizard);
2840 Q_ASSERT(uint(which) < NPixmaps);
2841#ifdef Q_OS_MACOS
2842 if (which == BackgroundPixmap && d->defaultPixmaps[BackgroundPixmap].isNull())
2843 d->defaultPixmaps[BackgroundPixmap] = d->findDefaultBackgroundPixmap();
2844#endif
2845 return d->defaultPixmaps[which];
2846}
2847
2848/*!
2849 Sets the default property for \a className to be \a property,
2850 and the associated change signal to be \a changedSignal.
2851
2852 The default property is used when an instance of \a className (or
2853 of one of its subclasses) is passed to
2854 QWizardPage::registerField() and no property is specified.
2855
2856 QWizard knows the most common Qt widgets. For these (or their
2857 subclasses), you don't need to specify a \a property or a \a
2858 changedSignal. The table below lists these widgets:
2859
2860 \table
2861 \header \li Widget \li Property \li Change Notification Signal
2862 \row \li QAbstractButton \li bool \l{QAbstractButton::}{checked} \li \l{QAbstractButton::}{toggled()}
2863 \row \li QAbstractSlider \li int \l{QAbstractSlider::}{value} \li \l{QAbstractSlider::}{valueChanged()}
2864 \row \li QComboBox \li int \l{QComboBox::}{currentIndex} \li \l{QComboBox::}{currentIndexChanged()}
2865 \row \li QDateTimeEdit \li QDateTime \l{QDateTimeEdit::}{dateTime} \li \l{QDateTimeEdit::}{dateTimeChanged()}
2866 \row \li QLineEdit \li QString \l{QLineEdit::}{text} \li \l{QLineEdit::}{textChanged()}
2867 \row \li QListWidget \li int \l{QListWidget::}{currentRow} \li \l{QListWidget::}{currentRowChanged()}
2868 \row \li QSpinBox \li int \l{QSpinBox::}{value} \li \l{QSpinBox::}{valueChanged()}
2869 \endtable
2870
2871 \sa QWizardPage::registerField()
2872*/
2873void QWizard::setDefaultProperty(const char *className, const char *property,
2874 const char *changedSignal)
2875{
2876 Q_D(QWizard);
2877 for (int i = d->defaultPropertyTable.size() - 1; i >= 0; --i) {
2878 if (qstrcmp(d->defaultPropertyTable.at(i).className, className) == 0) {
2879 d->defaultPropertyTable.remove(i);
2880 break;
2881 }
2882 }
2883 d->defaultPropertyTable.append(QWizardDefaultProperty(className, property, changedSignal));
2884}
2885
2886/*!
2887 Sets the given \a widget to be shown on the left side of the wizard.
2888 For styles which use the WatermarkPixmap (ClassicStyle and ModernStyle)
2889 the side widget is displayed on top of the watermark, for other styles
2890 or when the watermark is not provided the side widget is displayed
2891 on the left side of the wizard.
2892
2893 Passing \nullptr shows no side widget.
2894
2895 When the \a widget is not \nullptr the wizard reparents it.
2896
2897 Any previous side widget is hidden.
2898
2899 You may call setSideWidget() with the same widget at different
2900 times.
2901
2902 All widgets set here will be deleted by the wizard when it is
2903 destroyed unless you separately reparent the widget after setting
2904 some other side widget (or \nullptr).
2905
2906 By default, no side widget is present.
2907*/
2908void QWizard::setSideWidget(QWidget *widget)
2909{
2910 Q_D(QWizard);
2911
2912 d->sideWidget = widget;
2913 if (d->watermarkLabel) {
2914 d->watermarkLabel->setSideWidget(widget);
2915 d->updateLayout();
2916 }
2917}
2918
2919/*!
2920 Returns the widget on the left side of the wizard or \nullptr.
2921
2922 By default, no side widget is present.
2923*/
2924QWidget *QWizard::sideWidget() const
2925{
2926 Q_D(const QWizard);
2927
2928 return d->sideWidget;
2929}
2930
2931/*!
2932 \reimp
2933*/
2934void QWizard::setVisible(bool visible)
2935{
2936 Q_D(QWizard);
2937 if (visible) {
2938 if (d->current == -1)
2939 restart();
2940 }
2941 QDialog::setVisible(visible);
2942}
2943
2944/*!
2945 \reimp
2946*/
2947QSize QWizard::sizeHint() const
2948{
2949 Q_D(const QWizard);
2950 QSize result = d->mainLayout->totalSizeHint();
2951 QSize extra(500, 360);
2952 if (d->wizStyle == MacStyle && d->current != -1) {
2953 QSize pixmap(currentPage()->pixmap(BackgroundPixmap).size());
2954 extra.setWidth(616);
2955 if (!pixmap.isNull()) {
2956 extra.setHeight(pixmap.height());
2957
2958 /*
2959 The width isn't always reliable as a size hint, as
2960 some wizard backgrounds just cover the leftmost area.
2961 Use a rule of thumb to determine if the width is
2962 reliable or not.
2963 */
2964 if (pixmap.width() >= pixmap.height())
2965 extra.setWidth(pixmap.width());
2966 }
2967 }
2968 return result.expandedTo(extra);
2969}
2970
2971/*!
2972 \fn void QWizard::currentIdChanged(int id)
2973
2974 This signal is emitted when the current page changes, with the new
2975 current \a id.
2976
2977 \sa currentId(), currentPage()
2978*/
2979
2980/*!
2981 \fn void QWizard::pageAdded(int id)
2982
2983 This signal is emitted whenever a page is added to the
2984 wizard. The page's \a id is passed as parameter.
2985
2986 \sa addPage(), setPage(), startId()
2987*/
2988
2989/*!
2990 \fn void QWizard::pageRemoved(int id)
2991
2992 This signal is emitted whenever a page is removed from the
2993 wizard. The page's \a id is passed as parameter.
2994
2995 \sa removePage(), startId()
2996*/
2997
2998/*!
2999 \fn void QWizard::helpRequested()
3000
3001 This signal is emitted when the user clicks the \uicontrol Help button.
3002
3003 By default, no \uicontrol Help button is shown. Call
3004 setOption(HaveHelpButton, true) to have one.
3005
3006 Example:
3007
3008 \snippet dialogs/licensewizard/licensewizard.cpp 0
3009 \dots
3010 \snippet dialogs/licensewizard/licensewizard.cpp 5
3011 \snippet dialogs/licensewizard/licensewizard.cpp 7
3012 \dots
3013 \snippet dialogs/licensewizard/licensewizard.cpp 8
3014 \codeline
3015 \snippet dialogs/licensewizard/licensewizard.cpp 10
3016 \dots
3017 \snippet dialogs/licensewizard/licensewizard.cpp 12
3018 \codeline
3019 \snippet dialogs/licensewizard/licensewizard.cpp 14
3020 \codeline
3021 \snippet dialogs/licensewizard/licensewizard.cpp 15
3022
3023 \sa customButtonClicked()
3024*/
3025
3026/*!
3027 \fn void QWizard::customButtonClicked(int which)
3028
3029 This signal is emitted when the user clicks a custom button. \a
3030 which can be CustomButton1, CustomButton2, or CustomButton3.
3031
3032 By default, no custom button is shown. Call setOption() with
3033 HaveCustomButton1, HaveCustomButton2, or HaveCustomButton3 to have
3034 one, and use setButtonText() or setButton() to configure it.
3035
3036 \sa helpRequested()
3037*/
3038
3039/*!
3040 Goes back to the previous page.
3041
3042 This is equivalent to pressing the \uicontrol Back button.
3043
3044 \sa next(), accept(), reject(), restart()
3045*/
3046void QWizard::back()
3047{
3048 Q_D(QWizard);
3049 int n = d->history.size() - 2;
3050 if (n < 0)
3051 return;
3052 d->switchToPage(d->history.at(n), QWizardPrivate::Backward);
3053}
3054
3055/*!
3056 Advances to the next page.
3057
3058 This is equivalent to pressing the \uicontrol Next or \uicontrol Commit button.
3059
3060 \sa nextId(), back(), accept(), reject(), restart()
3061*/
3062void QWizard::next()
3063{
3064 Q_D(QWizard);
3065
3066 if (d->current == -1)
3067 return;
3068
3069 if (validateCurrentPage()) {
3070 int next = nextId();
3071 if (next != -1) {
3072 if (Q_UNLIKELY(d->history.contains(next))) {
3073 qWarning("QWizard::next: Page %d already met", next);
3074 return;
3075 }
3076 if (Q_UNLIKELY(!d->pageMap.contains(next))) {
3077 qWarning("QWizard::next: No such page %d", next);
3078 return;
3079 }
3080 d->switchToPage(next, QWizardPrivate::Forward);
3081 }
3082 }
3083}
3084
3085/*!
3086 Sets currentId to \a id, without visiting the pages between currentId and \a id.
3087
3088 Returns without page change, if
3089 \list
3090 \li wizard holds no pages
3091 \li current page is invalid
3092 \li given page equals currentId()
3093 \li given page is out of range
3094 \endlist
3095
3096 Note: If pages have been forward skipped and \a id is 0, page visiting history
3097 will be deleted
3098*/
3099
3100void QWizard::setCurrentId(int id)
3101{
3102 Q_D(QWizard);
3103
3104 if (d->current == -1)
3105 return;
3106
3107 if (currentId() == id)
3108 return;
3109
3110 if (!validateCurrentPage())
3111 return;
3112
3113 if (id < 0 || Q_UNLIKELY(!d->pageMap.contains(id))) {
3114 qWarning("QWizard::setCurrentId: No such page: %d", id);
3115 return;
3116 }
3117
3118 d->switchToPage(id, (id < currentId()) ? QWizardPrivate::Backward : QWizardPrivate::Forward);
3119}
3120
3121/*!
3122 Restarts the wizard at the start page. This function is called automatically when the
3123 wizard is shown.
3124
3125 \sa startId()
3126*/
3127void QWizard::restart()
3128{
3129 Q_D(QWizard);
3130 d->disableUpdates();
3131 d->reset();
3132 d->switchToPage(startId(), QWizardPrivate::Forward);
3133 d->enableUpdates();
3134}
3135
3136/*!
3137 \reimp
3138*/
3139bool QWizard::event(QEvent *event)
3140{
3141 Q_D(QWizard);
3142 if (event->type() == QEvent::StyleChange) { // Propagate style
3143 d->setStyle(style());
3144 d->updateLayout();
3145 } else if (event->type() == QEvent::PaletteChange) { // Emitted on theme change
3146 d->updatePalette();
3147 }
3148#if QT_CONFIG(style_windowsvista)
3149 else if (event->type() == QEvent::Show && d->vistaInitPending) {
3150 d->vistaInitPending = false;
3151 d->wizStyle = AeroStyle;
3152 d->handleAeroStyleChange();
3153 }
3154 else if (d->isVistaThemeEnabled()) {
3155 if (event->type() == QEvent::Resize
3156 || event->type() == QEvent::LayoutDirectionChange) {
3157 const int buttonLeft = (layoutDirection() == Qt::RightToLeft
3158 ? width() - d->vistaHelper->backButton()->sizeHint().width()
3159 : 0);
3160
3161 d->vistaHelper->backButton()->move(buttonLeft,
3162 d->vistaHelper->backButton()->y());
3163 }
3164
3165 d->vistaHelper->mouseEvent(event);
3166 }
3167#endif
3168 return QDialog::event(event);
3169}
3170
3171/*!
3172 \reimp
3173*/
3174void QWizard::resizeEvent(QResizeEvent *event)
3175{
3176 Q_D(QWizard);
3177 int heightOffset = 0;
3178#if QT_CONFIG(style_windowsvista)
3179 if (d->isVistaThemeEnabled()) {
3180 heightOffset = d->vistaHelper->topOffset(this);
3181 heightOffset += d->vistaHelper->titleBarSize();
3182 }
3183#endif
3184 d->antiFlickerWidget->resize(event->size().width(), event->size().height() - heightOffset);
3185#if QT_CONFIG(style_windowsvista)
3186 if (d->isVistaThemeEnabled())
3187 d->vistaHelper->resizeEvent(event);
3188#endif
3189 QDialog::resizeEvent(event);
3190}
3191
3192/*!
3193 \reimp
3194*/
3195void QWizard::paintEvent(QPaintEvent * event)
3196{
3197 Q_D(QWizard);
3198 if (d->wizStyle == MacStyle && currentPage()) {
3199 QPixmap backgroundPixmap = currentPage()->pixmap(BackgroundPixmap);
3200 if (backgroundPixmap.isNull())
3201 return;
3202
3203 QStylePainter painter(this);
3204 painter.drawPixmap(0, (height() - backgroundPixmap.height()) / 2, backgroundPixmap);
3205 }
3206#if QT_CONFIG(style_windowsvista)
3207 else if (d->isVistaThemeEnabled()) {
3208 d->vistaHelper->paintEvent(event);
3209 }
3210#else
3211 Q_UNUSED(event);
3212#endif
3213}
3214
3215#if defined(Q_OS_WIN) || defined(Q_QDOC)
3216/*!
3217 \reimp
3218*/
3219bool QWizard::nativeEvent(const QByteArray &eventType, void *message, qintptr *result)
3220{
3221#if QT_CONFIG(style_windowsvista)
3222 Q_D(QWizard);
3223 if (d->isVistaThemeEnabled() && eventType == "windows_generic_MSG") {
3224 MSG *windowsMessage = static_cast<MSG *>(message);
3225 const bool winEventResult = d->vistaHelper->handleWinEvent(windowsMessage, result);
3226 if (d->vistaDirty) {
3227 // QTBUG-78300: When Qt::AA_NativeWindows is set, delay further
3228 // window creation until after the platform window creation events.
3229 if (windowsMessage->message == WM_GETICON) {
3230 d->vistaStateChanged = true;
3231 d->vistaDirty = false;
3232 setWizardStyle(AeroStyle);
3233 }
3234 }
3235 return winEventResult;
3236 } else {
3237 return QDialog::nativeEvent(eventType, message, result);
3238 }
3239#else
3240 return QDialog::nativeEvent(eventType, message, result);
3241#endif
3242}
3243#endif
3244
3245/*!
3246 \reimp
3247*/
3248void QWizard::done(int result)
3249{
3250 Q_D(QWizard);
3251 // canceling leaves the wizard in a known state
3252 if (result == Rejected) {
3253 d->reset();
3254 } else {
3255 if (!validateCurrentPage())
3256 return;
3257 }
3258 QDialog::done(result);
3259}
3260
3261/*!
3262 \fn void QWizard::initializePage(int id)
3263
3264 This virtual function is called by QWizard to prepare page \a id
3265 just before it is shown either as a result of QWizard::restart()
3266 being called, or as a result of the user clicking \uicontrol Next. (However, if the \l
3267 QWizard::IndependentPages option is set, this function is only
3268 called the first time the page is shown.)
3269
3270 By reimplementing this function, you can ensure that the page's
3271 fields are properly initialized based on fields from previous
3272 pages.
3273
3274 The default implementation calls QWizardPage::initializePage() on
3275 page(\a id).
3276
3277 \sa QWizardPage::initializePage(), cleanupPage()
3278*/
3279void QWizard::initializePage(int theid)
3280{
3281 QWizardPage *page = this->page(theid);
3282 if (page)
3283 page->initializePage();
3284}
3285
3286/*!
3287 \fn void QWizard::cleanupPage(int id)
3288
3289 This virtual function is called by QWizard to clean up page \a id just before the
3290 user leaves it by clicking \uicontrol Back (unless the \l QWizard::IndependentPages option is set).
3291
3292 The default implementation calls QWizardPage::cleanupPage() on
3293 page(\a id).
3294
3295 \sa QWizardPage::cleanupPage(), initializePage()
3296*/
3297void QWizard::cleanupPage(int theid)
3298{
3299 QWizardPage *page = this->page(theid);
3300 if (page)
3301 page->cleanupPage();
3302}
3303
3304/*!
3305 This virtual function is called by QWizard when the user clicks
3306 \uicontrol Next or \uicontrol Finish to perform some last-minute validation.
3307 If it returns \c true, the next page is shown (or the wizard
3308 finishes); otherwise, the current page stays up.
3309
3310 The default implementation calls QWizardPage::validatePage() on
3311 the currentPage().
3312
3313 When possible, it is usually better style to disable the \uicontrol
3314 Next or \uicontrol Finish button (by specifying \l{mandatory fields} or
3315 by reimplementing QWizardPage::isComplete()) than to reimplement
3316 validateCurrentPage().
3317
3318 \sa QWizardPage::validatePage(), currentPage()
3319*/
3320bool QWizard::validateCurrentPage()
3321{
3322 QWizardPage *page = currentPage();
3323 if (!page)
3324 return true;
3325
3326 return page->validatePage();
3327}
3328
3329/*!
3330 This virtual function is called by QWizard to find out which page
3331 to show when the user clicks the \uicontrol Next button.
3332
3333 The return value is the ID of the next page, or -1 if no page follows.
3334
3335 The default implementation calls QWizardPage::nextId() on the
3336 currentPage().
3337
3338 By reimplementing this function, you can specify a dynamic page
3339 order.
3340
3341 \sa QWizardPage::nextId(), currentPage()
3342*/
3343int QWizard::nextId() const
3344{
3345 const QWizardPage *page = currentPage();
3346 if (!page)
3347 return -1;
3348
3349 return page->nextId();
3350}
3351
3352/*!
3353 \class QWizardPage
3354 \brief The QWizardPage class is the base class for wizard pages.
3355
3356 \inmodule QtWidgets
3357
3358 QWizard represents a wizard. Each page is a QWizardPage. When
3359 you create your own wizards, you can use QWizardPage directly,
3360 or you can subclass it for more control.
3361
3362 A page has the following attributes, which are rendered by
3363 QWizard: a \l title, a \l subTitle, and a \l{setPixmap()}{set of
3364 pixmaps}. See \l{Elements of a Wizard Page} for details. Once a
3365 page is added to the wizard (using QWizard::addPage() or
3366 QWizard::setPage()), wizard() returns a pointer to the
3367 associated QWizard object.
3368
3369 Page provides five virtual functions that can be reimplemented to
3370 provide custom behavior:
3371
3372 \list
3373 \li initializePage() is called to initialize the page's contents
3374 when the user clicks the wizard's \uicontrol Next button. If you
3375 want to derive the page's default from what the user entered
3376 on previous pages, this is the function to reimplement.
3377 \li cleanupPage() is called to reset the page's contents when the
3378 user clicks the wizard's \uicontrol Back button.
3379 \li validatePage() validates the page when the user clicks \uicontrol
3380 Next or \uicontrol Finish. It is often used to show an error message
3381 if the user has entered incomplete or invalid information.
3382 \li nextId() returns the ID of the next page. It is useful when
3383 \l{creating non-linear wizards}, which allow different
3384 traversal paths based on the information provided by the user.
3385 \li isComplete() is called to determine whether the \uicontrol Next
3386 and/or \uicontrol Finish button should be enabled or disabled. If
3387 you reimplement isComplete(), also make sure that
3388 completeChanged() is emitted whenever the complete state
3389 changes.
3390 \endlist
3391
3392 Normally, the \uicontrol Next button and the \uicontrol Finish button of a
3393 wizard are mutually exclusive. If isFinalPage() returns \c true, \uicontrol
3394 Finish is available; otherwise, \uicontrol Next is available. By
3395 default, isFinalPage() is true only when nextId() returns -1. If
3396 you want to show \uicontrol Next and \uicontrol Final simultaneously for a
3397 page (letting the user perform an "early finish"), call
3398 setFinalPage(true) on that page. For wizards that support early
3399 finishes, you might also want to set the
3400 \l{QWizard::}{HaveNextButtonOnLastPage} and
3401 \l{QWizard::}{HaveFinishButtonOnEarlyPages} options on the
3402 wizard.
3403
3404 In many wizards, the contents of a page may affect the default
3405 values of the fields of a later page. To make it easy to
3406 communicate between pages, QWizard supports a \l{Registering and
3407 Using Fields}{"field" mechanism} that allows you to register a
3408 field (e.g., a QLineEdit) on a page and to access its value from
3409 any page. Fields are global to the entire wizard and make it easy
3410 for any single page to access information stored by another page,
3411 without having to put all the logic in QWizard or having the
3412 pages know explicitly about each other. Fields are registered
3413 using registerField() and can be accessed at any time using
3414 field() and setField().
3415
3416 \sa QWizard, {Trivial Wizard Example}, {License Wizard Example}
3417*/
3418
3419/*!
3420 Constructs a wizard page with the given \a parent.
3421
3422 When the page is inserted into a wizard using QWizard::addPage()
3423 or QWizard::setPage(), the parent is automatically set to be the
3424 wizard.
3425
3426 \sa wizard()
3427*/
3428QWizardPage::QWizardPage(QWidget *parent)
3429 : QWidget(*new QWizardPagePrivate, parent, { })
3430{
3431 connect(this, SIGNAL(completeChanged()), this, SLOT(_q_updateCachedCompleteState()));
3432}
3433
3434/*!
3435 Destructor.
3436*/
3437QWizardPage::~QWizardPage()
3438{
3439}
3440
3441/*!
3442 \property QWizardPage::title
3443 \brief the title of the page
3444
3445 The title is shown by the QWizard, above the actual page. All
3446 pages should have a title.
3447
3448 The title may be plain text or HTML, depending on the value of the
3449 \l{QWizard::titleFormat} property.
3450
3451 By default, this property contains an empty string.
3452
3453 \sa subTitle, {Elements of a Wizard Page}
3454*/
3455void QWizardPage::setTitle(const QString &title)
3456{
3457 Q_D(QWizardPage);
3458 d->title = title;
3459 if (d->wizard && d->wizard->currentPage() == this)
3460 d->wizard->d_func()->updateLayout();
3461}
3462
3463QString QWizardPage::title() const
3464{
3465 Q_D(const QWizardPage);
3466 return d->title;
3467}
3468
3469/*!
3470 \property QWizardPage::subTitle
3471 \brief the subtitle of the page
3472
3473 The subtitle is shown by the QWizard, between the title and the
3474 actual page. Subtitles are optional. In
3475 \l{QWizard::ClassicStyle}{ClassicStyle} and
3476 \l{QWizard::ModernStyle}{ModernStyle}, using subtitles is
3477 necessary to make the header appear. In
3478 \l{QWizard::MacStyle}{MacStyle}, the subtitle is shown as a text
3479 label just above the actual page.
3480
3481 The subtitle may be plain text or HTML, depending on the value of
3482 the \l{QWizard::subTitleFormat} property.
3483
3484 By default, this property contains an empty string.
3485
3486 \sa title, QWizard::IgnoreSubTitles, {Elements of a Wizard Page}
3487*/
3488void QWizardPage::setSubTitle(const QString &subTitle)
3489{
3490 Q_D(QWizardPage);
3491 d->subTitle = subTitle;
3492 if (d->wizard && d->wizard->currentPage() == this)
3493 d->wizard->d_func()->updateLayout();
3494}
3495
3496QString QWizardPage::subTitle() const
3497{
3498 Q_D(const QWizardPage);
3499 return d->subTitle;
3500}
3501
3502/*!
3503 Sets the pixmap for role \a which to \a pixmap.
3504
3505 The pixmaps are used by QWizard when displaying a page. Which
3506 pixmaps are actually used depend on the \l{Wizard Look and
3507 Feel}{wizard style}.
3508
3509 Pixmaps can also be set for the entire wizard using
3510 QWizard::setPixmap(), in which case they apply for all pages that
3511 don't specify a pixmap.
3512
3513 \sa QWizard::setPixmap(), {Elements of a Wizard Page}
3514*/
3515void QWizardPage::setPixmap(QWizard::WizardPixmap which, const QPixmap &pixmap)
3516{
3517 Q_D(QWizardPage);
3518 Q_ASSERT(uint(which) < QWizard::NPixmaps);
3519 d->pixmaps[which] = pixmap;
3520 if (d->wizard && d->wizard->currentPage() == this)
3521 d->wizard->d_func()->updatePixmap(which);
3522}
3523
3524/*!
3525 Returns the pixmap set for role \a which.
3526
3527 Pixmaps can also be set for the entire wizard using
3528 QWizard::setPixmap(), in which case they apply for all pages that
3529 don't specify a pixmap.
3530
3531 \sa QWizard::pixmap(), {Elements of a Wizard Page}
3532*/
3533QPixmap QWizardPage::pixmap(QWizard::WizardPixmap which) const
3534{
3535 Q_D(const QWizardPage);
3536 Q_ASSERT(uint(which) < QWizard::NPixmaps);
3537
3538 const QPixmap &pixmap = d->pixmaps[which];
3539 if (!pixmap.isNull())
3540 return pixmap;
3541
3542 if (wizard())
3543 return wizard()->pixmap(which);
3544
3545 return pixmap;
3546}
3547
3548/*!
3549 This virtual function is called by QWizard::initializePage() to
3550 prepare the page just before it is shown either as a result of QWizard::restart()
3551 being called, or as a result of the user clicking \uicontrol Next.
3552 (However, if the \l QWizard::IndependentPages option is set, this function is only
3553 called the first time the page is shown.)
3554
3555 By reimplementing this function, you can ensure that the page's
3556 fields are properly initialized based on fields from previous
3557 pages. For example:
3558
3559 \snippet dialogs/licensewizard/licensewizard.cpp 27
3560
3561 The default implementation does nothing.
3562
3563 \sa QWizard::initializePage(), cleanupPage(), QWizard::IndependentPages
3564*/
3565void QWizardPage::initializePage()
3566{
3567}
3568
3569/*!
3570 This virtual function is called by QWizard::cleanupPage() when
3571 the user leaves the page by clicking \uicontrol Back (unless the \l QWizard::IndependentPages
3572 option is set).
3573
3574 The default implementation resets the page's fields to their
3575 original values (the values they had before initializePage() was
3576 called).
3577
3578 \sa QWizard::cleanupPage(), initializePage(), QWizard::IndependentPages
3579*/
3580void QWizardPage::cleanupPage()
3581{
3582 Q_D(QWizardPage);
3583 if (d->wizard) {
3584 const QList<QWizardField> &fields = d->wizard->d_func()->fields;
3585 for (const auto &field : fields) {
3586 if (field.page == this)
3587 field.object->setProperty(field.property, field.initialValue);
3588 }
3589 }
3590}
3591
3592/*!
3593 This virtual function is called by QWizard::validateCurrentPage()
3594 when the user clicks \uicontrol Next or \uicontrol Finish to perform some
3595 last-minute validation. If it returns \c true, the next page is shown
3596 (or the wizard finishes); otherwise, the current page stays up.
3597
3598 The default implementation returns \c true.
3599
3600 When possible, it is usually better style to disable the \uicontrol
3601 Next or \uicontrol Finish button (by specifying \l{mandatory fields} or
3602 reimplementing isComplete()) than to reimplement validatePage().
3603
3604 \sa QWizard::validateCurrentPage(), isComplete()
3605*/
3606bool QWizardPage::validatePage()
3607{
3608 return true;
3609}
3610
3611/*!
3612 This virtual function is called by QWizard to determine whether
3613 the \uicontrol Next or \uicontrol Finish button should be enabled or
3614 disabled.
3615
3616 The default implementation returns \c true if all \l{mandatory
3617 fields} are filled; otherwise, it returns \c false.
3618
3619 If you reimplement this function, make sure to emit completeChanged(),
3620 from the rest of your implementation, whenever the value of isComplete()
3621 changes. This ensures that QWizard updates the enabled or disabled state of
3622 its buttons. An example of the reimplementation is
3623 available \l{http://doc.qt.io/archives/qq/qq22-qwizard.html#validatebeforeitstoolate}
3624 {here}.
3625
3626 \sa completeChanged(), isFinalPage()
3627*/
3628bool QWizardPage::isComplete() const
3629{
3630 Q_D(const QWizardPage);
3631
3632 if (!d->wizard)
3633 return true;
3634
3635 const QList<QWizardField> &wizardFields = d->wizard->d_func()->fields;
3636 const auto end = wizardFields.crend();
3637 for (auto it = wizardFields.crbegin(); it != end; ++it) {
3638 const QWizardField &field = *it;
3639 if (field.page == this && field.mandatory) {
3640 QVariant value = field.object->property(field.property);
3641 if (value == field.initialValue)
3642 return false;
3643
3644#if QT_CONFIG(lineedit)
3645 if (QLineEdit *lineEdit = qobject_cast<QLineEdit *>(field.object)) {
3646 if (!lineEdit->hasAcceptableInput())
3647 return false;
3648 }
3649#endif
3650#if QT_CONFIG(spinbox)
3651 if (QAbstractSpinBox *spinBox = qobject_cast<QAbstractSpinBox *>(field.object)) {
3652 if (!spinBox->hasAcceptableInput())
3653 return false;
3654 }
3655#endif
3656 }
3657 }
3658 return true;
3659}
3660
3661/*!
3662 Explicitly sets this page to be final if \a finalPage is true.
3663
3664 After calling setFinalPage(true), isFinalPage() returns \c true and the \uicontrol
3665 Finish button is visible (and enabled if isComplete() returns
3666 true).
3667
3668 After calling setFinalPage(false), isFinalPage() returns \c true if
3669 nextId() returns -1; otherwise, it returns \c false.
3670
3671 \sa isComplete(), QWizard::HaveFinishButtonOnEarlyPages
3672*/
3673void QWizardPage::setFinalPage(bool finalPage)
3674{
3675 Q_D(QWizardPage);
3676 d->explicitlyFinal = finalPage;
3677 QWizard *wizard = this->wizard();
3678 if (wizard && wizard->currentPage() == this)
3679 wizard->d_func()->updateCurrentPage();
3680}
3681
3682/*!
3683 This function is called by QWizard to determine whether the \uicontrol
3684 Finish button should be shown for this page or not.
3685
3686 By default, it returns \c true if there is no next page
3687 (i.e., nextId() returns -1); otherwise, it returns \c false.
3688
3689 By explicitly calling setFinalPage(true), you can let the user perform an
3690 "early finish".
3691
3692 \sa isComplete(), QWizard::HaveFinishButtonOnEarlyPages
3693*/
3694bool QWizardPage::isFinalPage() const
3695{
3696 Q_D(const QWizardPage);
3697 if (d->explicitlyFinal)
3698 return true;
3699
3700 QWizard *wizard = this->wizard();
3701 if (wizard && wizard->currentPage() == this) {
3702 // try to use the QWizard implementation if possible
3703 return wizard->nextId() == -1;
3704 } else {
3705 return nextId() == -1;
3706 }
3707}
3708
3709/*!
3710 Sets this page to be a commit page if \a commitPage is true; otherwise,
3711 sets it to be a normal page.
3712
3713 A commit page is a page that represents an action which cannot be undone
3714 by clicking \uicontrol Back or \uicontrol Cancel.
3715
3716 A \uicontrol Commit button replaces the \uicontrol Next button on a commit page. Clicking this
3717 button simply calls QWizard::next() just like clicking \uicontrol Next does.
3718
3719 A page entered directly from a commit page has its \uicontrol Back button disabled.
3720
3721 \sa isCommitPage()
3722*/
3723void QWizardPage::setCommitPage(bool commitPage)
3724{
3725 Q_D(QWizardPage);
3726 d->commit = commitPage;
3727 QWizard *wizard = this->wizard();
3728 if (wizard && wizard->currentPage() == this)
3729 wizard->d_func()->updateCurrentPage();
3730}
3731
3732/*!
3733 Returns \c true if this page is a commit page; otherwise returns \c false.
3734
3735 \sa setCommitPage()
3736*/
3737bool QWizardPage::isCommitPage() const
3738{
3739 Q_D(const QWizardPage);
3740 return d->commit;
3741}
3742
3743/*!
3744 Sets the text on button \a which to be \a text on this page.
3745
3746 By default, the text on buttons depends on the QWizard::wizardStyle,
3747 but may be redefined for the wizard as a whole using QWizard::setButtonText().
3748
3749 \sa buttonText(), QWizard::setButtonText(), QWizard::buttonText()
3750*/
3751void QWizardPage::setButtonText(QWizard::WizardButton which, const QString &text)
3752{
3753 Q_D(QWizardPage);
3754 d->buttonCustomTexts.insert(which, text);
3755 if (wizard() && wizard()->currentPage() == this && wizard()->d_func()->btns[which])
3756 wizard()->d_func()->btns[which]->setText(text);
3757}
3758
3759/*!
3760 Returns the text on button \a which on this page.
3761
3762 If a text has ben set using setButtonText(), this text is returned.
3763 Otherwise, if a text has been set using QWizard::setButtonText(),
3764 this text is returned.
3765
3766 By default, the text on buttons depends on the QWizard::wizardStyle.
3767 For example, on \macos, the \uicontrol Next button is called \uicontrol
3768 Continue.
3769
3770 \sa setButtonText(), QWizard::buttonText(), QWizard::setButtonText()
3771*/
3772QString QWizardPage::buttonText(QWizard::WizardButton which) const
3773{
3774 Q_D(const QWizardPage);
3775
3776 if (d->buttonCustomTexts.contains(which))
3777 return d->buttonCustomTexts.value(which);
3778
3779 if (wizard())
3780 return wizard()->buttonText(which);
3781
3782 return QString();
3783}
3784
3785/*!
3786 This virtual function is called by QWizard::nextId() to find
3787 out which page to show when the user clicks the \uicontrol Next button.
3788
3789 The return value is the ID of the next page, or -1 if no page follows.
3790
3791 By default, this function returns the lowest ID greater than the ID
3792 of the current page, or -1 if there is no such ID.
3793
3794 By reimplementing this function, you can specify a dynamic page
3795 order. For example:
3796
3797 \snippet dialogs/licensewizard/licensewizard.cpp 18
3798
3799 \sa QWizard::nextId()
3800*/
3801int QWizardPage::nextId() const
3802{
3803 Q_D(const QWizardPage);
3804
3805 if (!d->wizard)
3806 return -1;
3807
3808 bool foundCurrentPage = false;
3809
3810 const QWizardPrivate::PageMap &pageMap = d->wizard->d_func()->pageMap;
3811 QWizardPrivate::PageMap::const_iterator i = pageMap.constBegin();
3812 QWizardPrivate::PageMap::const_iterator end = pageMap.constEnd();
3813
3814 for (; i != end; ++i) {
3815 if (i.value() == this) {
3816 foundCurrentPage = true;
3817 } else if (foundCurrentPage) {
3818 return i.key();
3819 }
3820 }
3821 return -1;
3822}
3823
3824/*!
3825 \fn void QWizardPage::completeChanged()
3826
3827 This signal is emitted whenever the complete state of the page
3828 (i.e., the value of isComplete()) changes.
3829
3830 If you reimplement isComplete(), make sure to emit
3831 completeChanged() whenever the value of isComplete() changes, to
3832 ensure that QWizard updates the enabled or disabled state of its
3833 buttons.
3834
3835 \sa isComplete()
3836*/
3837
3838/*!
3839 Sets the value of the field called \a name to \a value.
3840
3841 This function can be used to set fields on any page of the wizard.
3842 It is equivalent to calling
3843 wizard()->\l{QWizard::setField()}{setField(\a name, \a value)}.
3844
3845 \sa QWizard::setField(), field(), registerField()
3846*/
3847void QWizardPage::setField(const QString &name, const QVariant &value)
3848{
3849 Q_D(QWizardPage);
3850 if (!d->wizard)
3851 return;
3852 d->wizard->setField(name, value);
3853}
3854
3855/*!
3856 Returns the value of the field called \a name.
3857
3858 This function can be used to access fields on any page of the
3859 wizard. It is equivalent to calling
3860 wizard()->\l{QWizard::field()}{field(\a name)}.
3861
3862 Example:
3863
3864 \snippet dialogs/licensewizard/licensewizard.cpp accessField
3865
3866 \sa QWizard::field(), setField(), registerField()
3867*/
3868QVariant QWizardPage::field(const QString &name) const
3869{
3870 Q_D(const QWizardPage);
3871 if (!d->wizard)
3872 return QVariant();
3873 return d->wizard->field(name);
3874}
3875
3876/*!
3877 Creates a field called \a name associated with the given \a
3878 property of the given \a widget. From then on, that property
3879 becomes accessible using field() and setField().
3880
3881 Fields are global to the entire wizard and make it easy for any
3882 single page to access information stored by another page, without
3883 having to put all the logic in QWizard or having the pages know
3884 explicitly about each other.
3885
3886 If \a name ends with an asterisk (\c *), the field is a mandatory
3887 field. When a page has mandatory fields, the \uicontrol Next and/or
3888 \uicontrol Finish buttons are enabled only when all mandatory fields
3889 are filled. This requires a \a changedSignal to be specified, to
3890 tell QWizard to recheck the value stored by the mandatory field.
3891
3892 QWizard knows the most common Qt widgets. For these (or their
3893 subclasses), you don't need to specify a \a property or a \a
3894 changedSignal. The table below lists these widgets:
3895
3896 \table
3897 \header \li Widget \li Property \li Change Notification Signal
3898 \row \li QAbstractButton \li bool \l{QAbstractButton::}{checked} \li \l{QAbstractButton::}{toggled()}
3899 \row \li QAbstractSlider \li int \l{QAbstractSlider::}{value} \li \l{QAbstractSlider::}{valueChanged()}
3900 \row \li QComboBox \li int \l{QComboBox::}{currentIndex} \li \l{QComboBox::}{currentIndexChanged()}
3901 \row \li QDateTimeEdit \li QDateTime \l{QDateTimeEdit::}{dateTime} \li \l{QDateTimeEdit::}{dateTimeChanged()}
3902 \row \li QLineEdit \li QString \l{QLineEdit::}{text} \li \l{QLineEdit::}{textChanged()}
3903 \row \li QListWidget \li int \l{QListWidget::}{currentRow} \li \l{QListWidget::}{currentRowChanged()}
3904 \row \li QSpinBox \li int \l{QSpinBox::}{value} \li \l{QSpinBox::}{valueChanged()}
3905 \endtable
3906
3907 You can use QWizard::setDefaultProperty() to add entries to this
3908 table or to override existing entries.
3909
3910 To consider a field "filled", QWizard simply checks that their
3911 current value doesn't equal their original value (the value they
3912 had before initializePage() was called). For QLineEdit, it also
3913 checks that
3914 \l{QLineEdit::hasAcceptableInput()}{hasAcceptableInput()} returns
3915 true, to honor any validator or mask.
3916
3917 QWizard's mandatory field mechanism is provided for convenience.
3918 It can be bypassed by reimplementing QWizardPage::isComplete().
3919
3920 \sa field(), setField(), QWizard::setDefaultProperty()
3921*/
3922void QWizardPage::registerField(const QString &name, QWidget *widget, const char *property,
3923 const char *changedSignal)
3924{
3925 Q_D(QWizardPage);
3926 QWizardField field(this, name, widget, property, changedSignal);
3927 if (d->wizard) {
3928 d->wizard->d_func()->addField(field);
3929 } else {
3930 d->pendingFields += field;
3931 }
3932}
3933
3934/*!
3935 Returns the wizard associated with this page, or \nullptr if this page
3936 hasn't been inserted into a QWizard yet.
3937
3938 \sa QWizard::addPage(), QWizard::setPage()
3939*/
3940QWizard *QWizardPage::wizard() const
3941{
3942 Q_D(const QWizardPage);
3943 return d->wizard;
3944}
3945
3946QT_END_NAMESPACE
3947
3948#include "moc_qwizard.cpp"
friend class QWidget
Definition qpainter.h:432
The QStylePainter class is a convenience class for drawing QStyle elements inside a widget.
QSize minimumSizeHint() const override
\reimp
Definition qwizard.cpp:438
void setSideWidget(QWidget *widget)
Definition qwizard.cpp:444
QWatermarkLabel(QWidget *parent, QWidget *sideWidget)
Definition qwizard.cpp:432
QWidget * sideWidget() const
Definition qwizard.cpp:455
QWizardAntiFlickerWidget(QWizard *wizard, QWizardPrivate *)
Definition qwizard.cpp:519
QWizardDefaultProperty(const char *className, const char *property, const char *changedSignal)
Definition qwizard.cpp:142
QByteArray changedSignal
Definition qwizard.cpp:139
QString name
Definition qwizard.cpp:159
void resolve(const QList< QWizardDefaultProperty > &defaultPropertyTable)
Definition qwizard.cpp:179
QWizardField(QWizardPage *page, const QString &spec, QObject *object, const char *property, const char *changedSignal)
Definition qwizard.cpp:168
void findProperty(const QWizardDefaultProperty *properties, int propertyCount)
Definition qwizard.cpp:186
QByteArray property
Definition qwizard.cpp:162
QByteArray changedSignal
Definition qwizard.cpp:163
QVariant initialValue
Definition qwizard.cpp:164
QWizardPage * page
Definition qwizard.cpp:158
QObject * object
Definition qwizard.cpp:161
void paintEvent(QPaintEvent *event) override
This event handler can be reimplemented in a subclass to receive paint events passed in event.
Definition qwizard.cpp:390
QWizardHeader(RulerType, QWidget *parent=nullptr)
Definition qwizard.cpp:253
QWizardHeader(QWidget *parent=nullptr)
Definition qwizard.cpp:279
void setup(const QWizardLayoutInfo &info, const QString &title, const QString &subTitle, const QPixmap &logo, const QPixmap &banner, Qt::TextFormat titleFormat, Qt::TextFormat subTitleFormat, QWizard::WizardOptions wizardOptions)
Definition qwizard.cpp:329
bool operator!=(const QWizardLayoutInfo &other) const
Definition qwizard.cpp:222
bool operator==(const QWizardLayoutInfo &other) const
Definition qwizard.cpp:225
TriState completeState
Definition qwizard.cpp:479
void _q_maybeEmitCompleteChanged()
Definition qwizard.cpp:494
QMap< int, QString > buttonCustomTexts
Definition qwizard.cpp:483
void _q_updateCachedCompleteState()
Definition qwizard.cpp:502
bool cachedIsComplete() const
Definition qwizard.cpp:486
QPixmap pixmaps[QWizard::NPixmaps]
Definition qwizard.cpp:477
QList< QWizardField > pendingFields
Definition qwizard.cpp:478
QMap< int, QString > buttonCustomTexts
Definition qwizard.cpp:586
QList< int > history
Definition qwizard.cpp:575
QMap< QString, int > fieldIndexMap
Definition qwizard.cpp:573
void setStyle(QStyle *style)
Definition qwizard.cpp:1727
PageMap pageMap
Definition qwizard.cpp:571
QGridLayout * mainLayout
Definition qwizard.cpp:618
QList< QWizardDefaultProperty > defaultPropertyTable
Definition qwizard.cpp:574
QAbstractButton * commit
Definition qwizard.cpp:598
bool buttonLayoutContains(QWizard::WizardButton which)
Definition qwizard.cpp:1525
void updateCurrentPage()
Definition qwizard.cpp:1344
void _q_updateButtonStates()
Definition qwizard.cpp:1649
QVBoxLayout * pageVBoxLayout
Definition qwizard.cpp:616
QWatermarkLabel * watermarkLabel
Definition qwizard.cpp:609
QAbstractButton * cancel
Definition qwizard.cpp:600
QWizardLayoutInfo layoutInfoForCurrentPage()
Definition qwizard.cpp:888
bool startSetByUser
Definition qwizard.cpp:577
void connectButton(QWizard::WizardButton which) const
Definition qwizard.cpp:1413
void removeFieldAt(int index)
Definition qwizard.cpp:773
QAbstractButton * next
Definition qwizard.cpp:597
QAbstractButton * help
Definition qwizard.cpp:601
QAbstractButton * back
Definition qwizard.cpp:596
QLabel * subTitleLabel
Definition qwizard.cpp:613
QFrame * pageFrame
Definition qwizard.cpp:611
QLabel * titleLabel
Definition qwizard.cpp:612
void recreateLayout(const QWizardLayoutInfo &info)
Definition qwizard.cpp:949
QWizardAntiFlickerWidget * antiFlickerWidget
Definition qwizard.cpp:605
QAbstractButton * finish
Definition qwizard.cpp:599
QWizardHeader * headerWidget
Definition qwizard.cpp:608
void updateLayout()
Definition qwizard.cpp:1223
QHBoxLayout * buttonLayout
Definition qwizard.cpp:617
void updateMinMaxSizes(const QWizardLayoutInfo &info)
Definition qwizard.cpp:1308
void _q_emitCustomButtonClicked()
Definition qwizard.cpp:1637
void setButtonLayout(const QWizard::WizardButton *array, int size)
Definition qwizard.cpp:1492
bool isVistaThemeEnabled() const
Definition qwizard.cpp:1610
void updatePixmap(QWizard::WizardPixmap which)
Definition qwizard.cpp:1530
QWidget * sideWidget
Definition qwizard.cpp:610
void _q_handleFieldObjectDestroyed(QObject *)
Definition qwizard.cpp:1700
void switchToPage(int newId, Direction direction)
Definition qwizard.cpp:788
QList< QWizard::WizardButton > buttonsCustomLayout
Definition qwizard.cpp:588
void enableUpdates()
Definition qwizard.cpp:1628
int disableUpdatesCount
Definition qwizard.cpp:582
QPixmap defaultPixmaps[QWizard::NPixmaps]
Definition qwizard.cpp:591
QWidget * placeholderWidget2
Definition qwizard.cpp:607
QWizardRuler * bottomRuler
Definition qwizard.cpp:614
Qt::TextFormat subTitleFmt
Definition qwizard.cpp:590
void updateButtonTexts()
Definition qwizard.cpp:1423
void updateButtonLayout()
Definition qwizard.cpp:1452
QList< QWizardField > fields
Definition qwizard.cpp:572
bool ensureButton(QWizard::WizardButton which) const
Definition qwizard.cpp:1384
void updatePalette()
Definition qwizard.cpp:1284
bool buttonsHaveCustomLayout
Definition qwizard.cpp:587
void cleanupPagesNotInHistory()
Definition qwizard.cpp:737
QAbstractButton * btns[QWizard::NButtons]
Definition qwizard.cpp:603
Qt::TextFormat titleFmt
Definition qwizard.cpp:589
void disableUpdates()
Definition qwizard.cpp:1619
QWidget * placeholderWidget1
Definition qwizard.cpp:606
void addField(const QWizardField &field)
Definition qwizard.cpp:751
QWizardLayoutInfo layoutInfo
Definition qwizard.cpp:581
QWizardRuler(QWidget *parent=nullptr)
Definition qwizard.cpp:425
Combined button and popup list for selecting options.
static const char * buttonSlots(QWizard::WizardButton which)
Definition qwizard.cpp:864
static QString buttonDefaultText(int wstyle, int which, const QWizardPrivate *wizardPrivate)
Definition qwizard.cpp:636
const char className[16]
Definition qwizard.cpp:100
static QString object_name_for_button(QWizard::WizardButton which)
Definition qwizard.cpp:1358
Q_DECLARE_TYPEINFO(QWizardDefaultProperty, Q_RELOCATABLE_TYPE)
const int ModernHeaderTopMargin
Definition qwizard.cpp:51
static void changeSpacerSize(QLayout *layout, int index, int width, int height)
Definition qwizard.cpp:59
const int MacLayoutLeftMargin
Definition qwizard.cpp:54
const int GapBetweenLogoAndRightEdge
Definition qwizard.cpp:50
const char property[13]
Definition qwizard.cpp:101
static bool objectInheritsXAndXIsCloserThanY(const QObject *object, const QByteArray &classX, const QByteArray &classY)
Definition qwizard.cpp:85
static QWidget * iWantTheFocus(QWidget *ancestor)
Definition qwizard.cpp:67
Q_DECLARE_TYPEINFO(QWizardField, Q_RELOCATABLE_TYPE)
const int MacLayoutBottomMargin
Definition qwizard.cpp:57
const int MacLayoutRightMargin
Definition qwizard.cpp:56
static const char * changed_signal(int which)
Definition qwizard.cpp:114
const size_t NFallbackDefaultProperties
Definition qwizard.cpp:112
const int ClassicHMargin
Definition qwizard.cpp:52
const int MacButtonTopMargin
Definition qwizard.cpp:53