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