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