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