1 | /* |
2 | This file is part of the KDE libraries |
3 | SPDX-FileCopyrightText: 2006 Olivier Goffart <ogoffart at kde.org> |
4 | |
5 | SPDX-License-Identifier: LGPL-2.0-only |
6 | */ |
7 | |
8 | #include "kassistantdialog.h" |
9 | |
10 | #include "kpagedialog_p.h" |
11 | #include <QApplication> |
12 | #include <QDialogButtonBox> |
13 | #include <QIcon> |
14 | #include <QPushButton> |
15 | |
16 | #include <QHash> |
17 | |
18 | class KAssistantDialogPrivate : public KPageDialogPrivate |
19 | { |
20 | Q_DECLARE_PUBLIC(KAssistantDialog) |
21 | Q_DECLARE_TR_FUNCTIONS(KAssistantDialog) |
22 | |
23 | public: |
24 | KAssistantDialogPrivate(KAssistantDialog *qq) |
25 | : KPageDialogPrivate(qq) |
26 | { |
27 | } |
28 | |
29 | QHash<KPageWidgetItem *, bool> valid; |
30 | QHash<KPageWidgetItem *, bool> appropriate; |
31 | KPageWidgetModel *pageModel = nullptr; |
32 | QPushButton *backButton = nullptr; |
33 | QPushButton *nextButton = nullptr; |
34 | QPushButton *finishButton = nullptr; |
35 | |
36 | void init(); |
37 | void slotUpdateButtons(); |
38 | |
39 | QModelIndex getNext(QModelIndex nextIndex) |
40 | { |
41 | QModelIndex currentIndex; |
42 | do { |
43 | currentIndex = nextIndex; |
44 | nextIndex = pageModel->index(row: 0, column: 0, parent: currentIndex); |
45 | if (!nextIndex.isValid()) { |
46 | nextIndex = currentIndex.sibling(arow: currentIndex.row() + 1, acolumn: 0); |
47 | } |
48 | } while (nextIndex.isValid() && !appropriate.value(key: pageModel->item(index: nextIndex), defaultValue: true)); |
49 | return nextIndex; |
50 | } |
51 | |
52 | QModelIndex getPrevious(QModelIndex nextIndex) |
53 | { |
54 | QModelIndex currentIndex; |
55 | do { |
56 | currentIndex = nextIndex; |
57 | nextIndex = currentIndex.sibling(arow: currentIndex.row() - 1, acolumn: 0); |
58 | if (!nextIndex.isValid()) { |
59 | nextIndex = currentIndex.parent(); |
60 | } |
61 | } while (nextIndex.isValid() && !appropriate.value(key: pageModel->item(index: nextIndex), defaultValue: true)); |
62 | return nextIndex; |
63 | } |
64 | }; |
65 | |
66 | KAssistantDialog::KAssistantDialog(QWidget *parent, Qt::WindowFlags flags) |
67 | : KPageDialog(*new KAssistantDialogPrivate(this), nullptr, parent, flags) |
68 | { |
69 | Q_D(KAssistantDialog); |
70 | |
71 | d->init(); |
72 | // workaround to get the page model |
73 | KPageWidget *pagewidget = findChild<KPageWidget *>(); |
74 | Q_ASSERT(pagewidget); |
75 | d->pageModel = static_cast<KPageWidgetModel *>(pagewidget->model()); |
76 | } |
77 | |
78 | KAssistantDialog::KAssistantDialog(KPageWidget *widget, QWidget *parent, Qt::WindowFlags flags) |
79 | : KPageDialog(*new KAssistantDialogPrivate(this), widget, parent, flags) |
80 | { |
81 | Q_D(KAssistantDialog); |
82 | |
83 | d->init(); |
84 | d->pageModel = static_cast<KPageWidgetModel *>(widget->model()); |
85 | } |
86 | |
87 | KAssistantDialog::~KAssistantDialog() = default; |
88 | |
89 | void KAssistantDialogPrivate::init() |
90 | { |
91 | Q_Q(KAssistantDialog); |
92 | |
93 | QDialogButtonBox *buttonBox = q->buttonBox(); |
94 | |
95 | buttonBox->setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::Help); |
96 | backButton = new QPushButton; |
97 | |
98 | const QString iconBack = QApplication::isRightToLeft() ? QStringLiteral("go-next" ) : QStringLiteral("go-previous" ); |
99 | const QString iconNext = QApplication::isRightToLeft() ? QStringLiteral("go-previous" ) : QStringLiteral("go-next" ); |
100 | backButton->setText(tr(sourceText: "&Back" , disambiguation: "@action:button go back" )); |
101 | backButton->setIcon(QIcon::fromTheme(name: iconBack)); |
102 | backButton->setToolTip(tr(sourceText: "Go back one step" , disambiguation: "@info:tooltip" )); |
103 | q->connect(sender: backButton, signal: &QAbstractButton::clicked, context: q, slot: &KAssistantDialog::back); |
104 | buttonBox->addButton(button: backButton, role: QDialogButtonBox::ActionRole); |
105 | |
106 | nextButton = new QPushButton; |
107 | nextButton->setText(tr(sourceText: "Next" , disambiguation: "@action:button Opposite to Back" )); |
108 | nextButton->setIcon(QIcon::fromTheme(name: iconNext)); |
109 | nextButton->setDefault(true); |
110 | q->connect(sender: nextButton, signal: &QAbstractButton::clicked, context: q, slot: &KAssistantDialog::next); |
111 | buttonBox->addButton(button: nextButton, role: QDialogButtonBox::ActionRole); |
112 | |
113 | finishButton = new QPushButton; |
114 | finishButton->setText(tr(sourceText: "Finish" , disambiguation: "@action:button" )); |
115 | finishButton->setIcon(QIcon::fromTheme(QStringLiteral("dialog-ok-apply" ))); |
116 | buttonBox->addButton(button: finishButton, role: QDialogButtonBox::AcceptRole); |
117 | |
118 | q->setFaceType(KPageDialog::Plain); |
119 | |
120 | q->connect(sender: q, signal: &KAssistantDialog::currentPageChanged, context: q, slot: [this]() { |
121 | slotUpdateButtons(); |
122 | }); |
123 | } |
124 | |
125 | void KAssistantDialog::back() |
126 | { |
127 | Q_D(KAssistantDialog); |
128 | |
129 | QModelIndex nextIndex = d->getPrevious(nextIndex: d->pageModel->index(item: currentPage())); |
130 | if (nextIndex.isValid()) { |
131 | setCurrentPage(d->pageModel->item(index: nextIndex)); |
132 | } |
133 | } |
134 | |
135 | void KAssistantDialog::next() |
136 | { |
137 | Q_D(KAssistantDialog); |
138 | |
139 | QModelIndex nextIndex = d->getNext(nextIndex: d->pageModel->index(item: currentPage())); |
140 | if (nextIndex.isValid()) { |
141 | setCurrentPage(d->pageModel->item(index: nextIndex)); |
142 | } else if (isValid(page: currentPage())) { |
143 | accept(); |
144 | } |
145 | } |
146 | |
147 | void KAssistantDialog::setValid(KPageWidgetItem *page, bool enable) |
148 | { |
149 | Q_D(KAssistantDialog); |
150 | |
151 | d->valid[page] = enable; |
152 | if (page == currentPage()) { |
153 | d->slotUpdateButtons(); |
154 | } |
155 | } |
156 | |
157 | bool KAssistantDialog::isValid(KPageWidgetItem *page) const |
158 | { |
159 | Q_D(const KAssistantDialog); |
160 | |
161 | return d->valid.value(key: page, defaultValue: true); |
162 | } |
163 | |
164 | void KAssistantDialogPrivate::slotUpdateButtons() |
165 | { |
166 | Q_Q(KAssistantDialog); |
167 | |
168 | QModelIndex currentIndex = pageModel->index(item: q->currentPage()); |
169 | // change the title of the next/finish button |
170 | QModelIndex nextIndex = getNext(nextIndex: currentIndex); |
171 | finishButton->setEnabled(!nextIndex.isValid() && q->isValid(page: q->currentPage())); |
172 | nextButton->setEnabled(nextIndex.isValid() && q->isValid(page: q->currentPage())); |
173 | finishButton->setDefault(!nextIndex.isValid()); |
174 | nextButton->setDefault(nextIndex.isValid()); |
175 | // enable or disable the back button; |
176 | nextIndex = getPrevious(nextIndex: currentIndex); |
177 | backButton->setEnabled(nextIndex.isValid()); |
178 | } |
179 | |
180 | void KAssistantDialog::showEvent(QShowEvent *event) |
181 | { |
182 | Q_D(KAssistantDialog); |
183 | |
184 | d->slotUpdateButtons(); // called because last time that function was called is when the first page was added, so the next button show "finish" |
185 | KPageDialog::showEvent(event); |
186 | } |
187 | |
188 | void KAssistantDialog::setAppropriate(KPageWidgetItem *page, bool appropriate) |
189 | { |
190 | Q_D(KAssistantDialog); |
191 | |
192 | d->appropriate[page] = appropriate; |
193 | d->slotUpdateButtons(); |
194 | } |
195 | |
196 | bool KAssistantDialog::isAppropriate(KPageWidgetItem *page) const |
197 | { |
198 | Q_D(const KAssistantDialog); |
199 | |
200 | return d->appropriate.value(key: page, defaultValue: true); |
201 | } |
202 | |
203 | QPushButton *KAssistantDialog::backButton() const |
204 | { |
205 | Q_D(const KAssistantDialog); |
206 | |
207 | return d->backButton; |
208 | } |
209 | |
210 | QPushButton *KAssistantDialog::nextButton() const |
211 | { |
212 | Q_D(const KAssistantDialog); |
213 | |
214 | return d->nextButton; |
215 | } |
216 | |
217 | QPushButton *KAssistantDialog::finishButton() const |
218 | { |
219 | Q_D(const KAssistantDialog); |
220 | |
221 | return d->finishButton; |
222 | } |
223 | |
224 | #include "moc_kassistantdialog.cpp" |
225 | |