1/***************************************************************************
2 * Copyright (C) 2005-2014 by the Quassel Project *
3 * devel@quassel-irc.org *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) version 3. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
19 ***************************************************************************/
20
21#include <QDebug>
22#include <QAbstractButton>
23#include <QFormLayout>
24#include <QSpinBox>
25
26#include "coreconfigwizard.h"
27#include "coreconnection.h"
28#include "iconloader.h"
29
30CoreConfigWizard::CoreConfigWizard(CoreConnection *connection, const QList<QVariant> &backends, QWidget *parent)
31 : QWizard(parent),
32 _connection(connection)
33{
34 setModal(true);
35 setAttribute(Qt::WA_DeleteOnClose);
36
37 foreach(const QVariant &v, backends)
38 _backends[v.toMap()["DisplayName"].toString()] = v;
39
40 setPage(IntroPage, new CoreConfigWizardPages::IntroPage(this));
41 setPage(AdminUserPage, new CoreConfigWizardPages::AdminUserPage(this));
42 setPage(StorageSelectionPage, new CoreConfigWizardPages::StorageSelectionPage(_backends, this));
43 syncPage = new CoreConfigWizardPages::SyncPage(this);
44 connect(syncPage, SIGNAL(setupCore(const QString &, const QVariantMap &)), SLOT(prepareCoreSetup(const QString &, const QVariantMap &)));
45 setPage(SyncPage, syncPage);
46 syncRelayPage = new CoreConfigWizardPages::SyncRelayPage(this);
47 connect(syncRelayPage, SIGNAL(startOver()), this, SLOT(startOver()));
48 setPage(SyncRelayPage, syncRelayPage);
49 //setPage(Page_StorageDetails, new StorageDetailsPage());
50 //setPage(Page_Conclusion, new ConclusionPage(storageProviders));
51
52 setStartId(IntroPage);
53 //setStartId(StorageSelectionPage);
54
55#ifndef Q_OS_MAC
56 setWizardStyle(ModernStyle);
57#endif
58
59 setOption(HaveHelpButton, false);
60 setOption(NoBackButtonOnStartPage, true);
61 setOption(HaveNextButtonOnLastPage, false);
62 setOption(HaveFinishButtonOnEarlyPages, false);
63 setOption(NoCancelButton, true);
64 setOption(IndependentPages, true);
65 //setOption(ExtendedWatermarkPixmap, true);
66
67 setModal(true);
68
69 setWindowTitle(tr("Core Configuration Wizard"));
70 setPixmap(QWizard::LogoPixmap, DesktopIcon("quassel"));
71
72 connect(connection, SIGNAL(coreSetupSuccess()), SLOT(coreSetupSuccess()));
73 connect(connection, SIGNAL(coreSetupFailed(QString)), SLOT(coreSetupFailed(QString)));
74 //connect(connection, SIGNAL(loginSuccess()), SLOT(loginSuccess()));
75 connect(connection, SIGNAL(synchronized()), SLOT(syncFinished()));
76 connect(this, SIGNAL(rejected()), connection, SLOT(disconnectFromCore()));
77}
78
79
80QHash<QString, QVariant> CoreConfigWizard::backends() const
81{
82 return _backends;
83}
84
85
86void CoreConfigWizard::prepareCoreSetup(const QString &backend, const QVariantMap &properties)
87{
88 // Prevent the user from changing any settings he already specified...
89 foreach(int idx, visitedPages())
90 page(idx)->setEnabled(false);
91
92 coreConnection()->setupCore(Protocol::SetupData(field("adminUser.user").toString(), field("adminUser.password").toString(), backend, properties));
93}
94
95
96void CoreConfigWizard::coreSetupSuccess()
97{
98 syncPage->setStatus(tr("Your core has been successfully configured. Logging you in..."));
99 syncPage->setError(false);
100 syncRelayPage->setMode(CoreConfigWizardPages::SyncRelayPage::Error);
101 coreConnection()->loginToCore(field("adminUser.user").toString(), field("adminUser.password").toString(), field("adminUser.rememberPasswd").toBool());
102}
103
104
105void CoreConfigWizard::coreSetupFailed(const QString &error)
106{
107 syncPage->setStatus(tr("Core configuration failed:<br><b>%1</b><br>Press <em>Next</em> to start over.").arg(error));
108 syncPage->setError(true);
109 syncRelayPage->setMode(CoreConfigWizardPages::SyncRelayPage::Error);
110 //foreach(int idx, visitedPages()) page(idx)->setEnabled(true);
111 //setStartId(SyncPage);
112 //restart();
113}
114
115
116void CoreConfigWizard::startOver()
117{
118 foreach(int idx, visitedPages()) page(idx)->setEnabled(true);
119 setStartId(CoreConfigWizard::AdminUserPage);
120 restart();
121}
122
123
124void CoreConfigWizard::loginSuccess()
125{
126 syncPage->setStatus(tr("Your are now logged into your freshly configured Quassel Core!<br>"
127 "Please remember to configure your identities and networks now."));
128 syncPage->setComplete(true);
129 syncPage->setFinalPage(true);
130}
131
132
133void CoreConfigWizard::syncFinished()
134{
135 accept();
136}
137
138
139namespace CoreConfigWizardPages {
140/*** Intro Page ***/
141
142IntroPage::IntroPage(QWidget *parent) : QWizardPage(parent)
143{
144 ui.setupUi(this);
145 setTitle(tr("Introduction"));
146 //setSubTitle(tr("foobar"));
147 //setPixmap(QWizard::WatermarkPixmap, QPixmap(":icons/quassel-icon.png"));
148}
149
150
151int IntroPage::nextId() const
152{
153 return CoreConfigWizard::AdminUserPage;
154}
155
156
157/*** Admin User Page ***/
158
159AdminUserPage::AdminUserPage(QWidget *parent) : QWizardPage(parent)
160{
161 ui.setupUi(this);
162 setTitle(tr("Create Admin User"));
163 setSubTitle(tr("First, we will create a user on the core. This first user will have administrator privileges."));
164
165 registerField("adminUser.user*", ui.user);
166 registerField("adminUser.password*", ui.password);
167 registerField("adminUser.password2*", ui.password2);
168 registerField("adminUser.rememberPasswd", ui.rememberPasswd);
169
170 //ui.user->setText("foo");
171 //ui.password->setText("foo");
172 //ui.password2->setText("foo");
173}
174
175
176int AdminUserPage::nextId() const
177{
178 return CoreConfigWizard::StorageSelectionPage;
179}
180
181
182bool AdminUserPage::isComplete() const
183{
184 bool ok = !ui.user->text().isEmpty() && !ui.password->text().isEmpty() && ui.password->text() == ui.password2->text();
185 return ok;
186}
187
188
189/*** Storage Selection Page ***/
190
191StorageSelectionPage::StorageSelectionPage(const QHash<QString, QVariant> &backends, QWidget *parent)
192 : QWizardPage(parent),
193 _connectionBox(0),
194 _backends(backends)
195{
196 ui.setupUi(this);
197
198 setTitle(tr("Select Storage Backend"));
199 setSubTitle(tr("Please select a database backend for the Quassel Core storage to store the backlog and other data in."));
200 setCommitPage(true);
201
202 registerField("storage.backend", ui.backendList);
203
204 foreach(QString key, _backends.keys()) {
205 ui.backendList->addItem(_backends[key].toMap()["DisplayName"].toString(), key);
206 }
207
208 on_backendList_currentIndexChanged();
209}
210
211
212int StorageSelectionPage::nextId() const
213{
214 return CoreConfigWizard::SyncPage;
215}
216
217
218QString StorageSelectionPage::selectedBackend() const
219{
220 return ui.backendList->currentText();
221}
222
223
224QVariantMap StorageSelectionPage::connectionProperties() const
225{
226 QString backend = ui.backendList->itemData(ui.backendList->currentIndex()).toString();
227
228 QVariantMap properties;
229 QStringList setupKeys = _backends[backend].toMap()["SetupKeys"].toStringList();
230 if (!setupKeys.isEmpty()) {
231 QVariantMap defaults = _backends[backend].toMap()["SetupDefaults"].toMap();
232 foreach(QString key, setupKeys) {
233 QWidget *widget = _connectionBox->findChild<QWidget *>(key);
234 QVariant def;
235 if (defaults.contains(key)) {
236 def = defaults[key];
237 }
238 switch (def.type()) {
239 case QVariant::Int:
240 {
241 QSpinBox *spinbox = qobject_cast<QSpinBox *>(widget);
242 Q_ASSERT(spinbox);
243 def = QVariant(spinbox->value());
244 }
245 break;
246 default:
247 {
248 QLineEdit *lineEdit = qobject_cast<QLineEdit *>(widget);
249 Q_ASSERT(lineEdit);
250 def = QVariant(lineEdit->text());
251 }
252 }
253 properties[key] = def;
254 }
255 }
256 qDebug() << properties;
257
258// QVariantMap properties = _backends[backend].toMap()["ConnectionProperties"].toMap();
259// if(!properties.isEmpty() && _connectionBox) {
260// QVariantMap::iterator propertyIter = properties.begin();
261// while(propertyIter != properties.constEnd()) {
262// QWidget *widget = _connectionBox->findChild<QWidget *>(propertyIter.key());
263// switch(propertyIter.value().type()) {
264// case QVariant::Int:
265// {
266// QSpinBox *spinbox = qobject_cast<QSpinBox *>(widget);
267// Q_ASSERT(spinbox);
268// propertyIter.value() = QVariant(spinbox->value());
269// }
270// break;
271// default:
272// {
273// QLineEdit *lineEdit = qobject_cast<QLineEdit *>(widget);
274// Q_ASSERT(lineEdit);
275// propertyIter.value() = QVariant(lineEdit->text());
276// }
277// }
278// propertyIter++;
279// }
280// }
281 return properties;
282}
283
284
285void StorageSelectionPage::on_backendList_currentIndexChanged()
286{
287 QString backend = ui.backendList->itemData(ui.backendList->currentIndex()).toString();
288 ui.description->setText(_backends[backend].toMap()["Description"].toString());
289
290 if (_connectionBox) {
291 layout()->removeWidget(_connectionBox);
292 _connectionBox->deleteLater();
293 _connectionBox = 0;
294 }
295
296 QStringList setupKeys = _backends[backend].toMap()["SetupKeys"].toStringList();
297 if (!setupKeys.isEmpty()) {
298 QVariantMap defaults = _backends[backend].toMap()["SetupDefaults"].toMap();
299 QGroupBox *propertyBox = new QGroupBox(this);
300 propertyBox->setTitle(tr("Connection Properties"));
301 QFormLayout *formlayout = new QFormLayout;
302
303 foreach(QString key, setupKeys) {
304 QWidget *widget = 0;
305 QVariant def;
306 if (defaults.contains(key)) {
307 def = defaults[key];
308 }
309 switch (def.type()) {
310 case QVariant::Int:
311 {
312 QSpinBox *spinbox = new QSpinBox(propertyBox);
313 spinbox->setMaximum(64000);
314 spinbox->setValue(def.toInt());
315 widget = spinbox;
316 }
317 break;
318 default:
319 {
320 QLineEdit *lineEdit = new QLineEdit(def.toString(), propertyBox);
321 if (key.toLower().contains("password")) {
322 lineEdit->setEchoMode(QLineEdit::Password);
323 }
324 widget = lineEdit;
325 }
326 }
327 widget->setObjectName(key);
328 formlayout->addRow(key + ":", widget);
329 }
330 propertyBox->setLayout(formlayout);
331 static_cast<QVBoxLayout *>(layout())->insertWidget(layout()->indexOf(ui.descriptionBox) + 1, propertyBox);
332 _connectionBox = propertyBox;
333 }
334}
335
336
337/*** Sync Page ***/
338
339SyncPage::SyncPage(QWidget *parent) : QWizardPage(parent)
340{
341 ui.setupUi(this);
342 setTitle(tr("Storing Your Settings"));
343 setSubTitle(tr("Your settings are now stored in the core, and you will be logged in automatically."));
344}
345
346
347void SyncPage::initializePage()
348{
349 complete = false;
350 hasError = false;
351
352 StorageSelectionPage *storagePage = qobject_cast<StorageSelectionPage *>(wizard()->page(CoreConfigWizard::StorageSelectionPage));
353 QString backend = storagePage->selectedBackend();
354 QVariantMap properties = storagePage->connectionProperties();
355 Q_ASSERT(!backend.isEmpty());
356 ui.user->setText(wizard()->field("adminUser.user").toString());
357 ui.backend->setText(backend);
358 emit setupCore(backend, properties);
359}
360
361
362int SyncPage::nextId() const
363{
364 if (!hasError) return -1;
365 return CoreConfigWizard::SyncRelayPage;
366}
367
368
369bool SyncPage::isComplete() const
370{
371 return complete;
372}
373
374
375void SyncPage::setStatus(const QString &status)
376{
377 ui.status->setText(status);
378}
379
380
381void SyncPage::setError(bool e)
382{
383 hasError = e;
384}
385
386
387void SyncPage::setComplete(bool c)
388{
389 complete = c;
390 completeChanged();
391}
392
393
394/*** Sync Relay Page ***/
395
396SyncRelayPage::SyncRelayPage(QWidget *parent) : QWizardPage(parent)
397{
398 mode = Success;
399}
400
401
402void SyncRelayPage::setMode(Mode m)
403{
404 mode = m;
405}
406
407
408/*
409void SyncRelayPage::initializePage() {
410 return;
411 if(mode == Success) {
412 wizard()->accept();
413 } else {
414 emit startOver();
415 }
416}
417*/
418
419int SyncRelayPage::nextId() const
420{
421 emit startOver();
422 return 0;
423}
424}; /* namespace CoreConfigWizardPages */
425