1 /***************************************************************************
2 * Copyright (C) 2005-2016 by the Quassel Project *
3 * devel@quassel-irc.org *
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. *
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. *
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 ***************************************************************************/
22 #include <QAbstractButton>
23 #include <QFormLayout>
27 #include "coreconfigwizard.h"
28 #include "coreconnection.h"
32 CoreConfigWizard::CoreConfigWizard(CoreConnection *connection, const QList<QVariant> &backends, const QList<QVariant> &authenticators, QWidget *parent)
34 _connection(connection)
37 setAttribute(Qt::WA_DeleteOnClose);
39 foreach(const QVariant &v, backends)
40 _backends[v.toMap()["DisplayName"].toString()] = v;
42 foreach(const QVariant &v, authenticators)
43 _authenticators[v.toMap()["DisplayName"].toString()] = v;
45 setPage(IntroPage, new CoreConfigWizardPages::IntroPage(this));
46 setPage(AdminUserPage, new CoreConfigWizardPages::AdminUserPage(this));
47 setPage(AuthenticationSelectionPage, new CoreConfigWizardPages::AuthenticationSelectionPage(_authenticators, this));
48 setPage(StorageSelectionPage, new CoreConfigWizardPages::StorageSelectionPage(_backends, this));
49 syncPage = new CoreConfigWizardPages::SyncPage(this);
50 connect(syncPage, SIGNAL(setupCore(const QString &, const QVariantMap &, const QString &, const QVariantMap &)),
51 SLOT(prepareCoreSetup(const QString &, const QVariantMap &, const QString &, const QVariantMap &)));
52 setPage(SyncPage, syncPage);
53 syncRelayPage = new CoreConfigWizardPages::SyncRelayPage(this);
54 connect(syncRelayPage, SIGNAL(startOver()), this, SLOT(startOver()));
55 setPage(SyncRelayPage, syncRelayPage);
56 //setPage(Page_StorageDetails, new StorageDetailsPage());
57 //setPage(Page_Conclusion, new ConclusionPage(storageProviders));
59 setStartId(IntroPage);
60 //setStartId(StorageSelectionPage);
63 setWizardStyle(ModernStyle);
66 setOption(HaveHelpButton, false);
67 setOption(NoBackButtonOnStartPage, true);
68 setOption(HaveNextButtonOnLastPage, false);
69 setOption(HaveFinishButtonOnEarlyPages, false);
70 setOption(NoCancelButton, true);
71 setOption(IndependentPages, true);
72 //setOption(ExtendedWatermarkPixmap, true);
76 setWindowTitle(tr("Core Configuration Wizard"));
77 setPixmap(QWizard::LogoPixmap, QIcon::fromTheme("quassel", QIcon(":/icons/quassel.png")).pixmap(48));
79 connect(connection, SIGNAL(coreSetupSuccess()), SLOT(coreSetupSuccess()));
80 connect(connection, SIGNAL(coreSetupFailed(QString)), SLOT(coreSetupFailed(QString)));
81 //connect(connection, SIGNAL(loginSuccess()), SLOT(loginSuccess()));
82 connect(connection, SIGNAL(synchronized()), SLOT(syncFinished()));
83 connect(this, SIGNAL(rejected()), connection, SLOT(disconnectFromCore()));
87 QHash<QString, QVariant> CoreConfigWizard::backends() const
92 QHash<QString, QVariant> CoreConfigWizard::authenticators() const
94 return _authenticators;
97 void CoreConfigWizard::prepareCoreSetup(const QString &backend, const QVariantMap &properties, const QString &authBackend, const QVariantMap &authProperties)
99 // Prevent the user from changing any settings he already specified...
100 foreach(int idx, visitedPages())
101 page(idx)->setEnabled(false);
103 // FIXME? We need to be able to set up older cores that don't have auth backend support.
104 // So if the core doesn't support that feature, don't pass those parameters.
105 if (!(Client::coreFeatures() & Quassel::AuthBackends))
107 coreConnection()->setupCore(Protocol::SetupData(field("adminUser.user").toString(), field("adminUser.password").toString(), backend, properties));
109 coreConnection()->setupCore(Protocol::SetupData(field("adminUser.user").toString(), field("adminUser.password").toString(), backend, properties, authBackend, authProperties));
114 void CoreConfigWizard::coreSetupSuccess()
116 syncPage->setStatus(tr("Your core has been successfully configured. Logging you in..."));
117 syncPage->setError(false);
118 syncRelayPage->setMode(CoreConfigWizardPages::SyncRelayPage::Error);
119 coreConnection()->loginToCore(field("adminUser.user").toString(), field("adminUser.password").toString(), field("adminUser.rememberPasswd").toBool());
123 void CoreConfigWizard::coreSetupFailed(const QString &error)
125 syncPage->setStatus(tr("Core configuration failed:<br><b>%1</b><br>Press <em>Next</em> to start over.").arg(error));
126 syncPage->setError(true);
127 syncRelayPage->setMode(CoreConfigWizardPages::SyncRelayPage::Error);
128 //foreach(int idx, visitedPages()) page(idx)->setEnabled(true);
129 //setStartId(SyncPage);
134 void CoreConfigWizard::startOver()
136 foreach(int idx, visitedPages()) page(idx)->setEnabled(true);
137 setStartId(CoreConfigWizard::AdminUserPage);
142 void CoreConfigWizard::loginSuccess()
144 syncPage->setStatus(tr("Your are now logged into your freshly configured Quassel Core!<br>"
145 "Please remember to configure your identities and networks now."));
146 syncPage->setComplete(true);
147 syncPage->setFinalPage(true);
151 void CoreConfigWizard::syncFinished()
157 namespace CoreConfigWizardPages {
160 IntroPage::IntroPage(QWidget *parent) : QWizardPage(parent)
163 setTitle(tr("Introduction"));
164 //setSubTitle(tr("foobar"));
165 //setPixmap(QWizard::WatermarkPixmap, QPixmap(":icons/quassel-icon.png"));
169 int IntroPage::nextId() const
171 return CoreConfigWizard::AdminUserPage;
175 /*** Admin User Page ***/
177 AdminUserPage::AdminUserPage(QWidget *parent) : QWizardPage(parent)
180 setTitle(tr("Create Admin User"));
181 setSubTitle(tr("First, we will create a user on the core. This first user will have administrator privileges."));
183 registerField("adminUser.user*", ui.user);
184 registerField("adminUser.password*", ui.password);
185 registerField("adminUser.password2*", ui.password2);
186 registerField("adminUser.rememberPasswd", ui.rememberPasswd);
188 //ui.user->setText("foo");
189 //ui.password->setText("foo");
190 //ui.password2->setText("foo");
194 int AdminUserPage::nextId() const
196 // If the core doesn't support auth backends, skip that page!
197 if (!(Client::coreFeatures() & Quassel::AuthBackends))
199 return CoreConfigWizard::StorageSelectionPage;
201 return CoreConfigWizard::AuthenticationSelectionPage;
206 bool AdminUserPage::isComplete() const
208 bool ok = !ui.user->text().isEmpty() && !ui.password->text().isEmpty() && ui.password->text() == ui.password2->text();
212 /*** Authentication Selection Page ***/
214 AuthenticationSelectionPage::AuthenticationSelectionPage(const QHash<QString, QVariant> &backends, QWidget *parent)
215 : QWizardPage(parent),
221 setTitle(tr("Select Authentication Backend"));
222 setSubTitle(tr("Please select a backend for Quassel Core to use for authenticating users."));
225 registerField("authentication.backend", ui.backendList);
227 foreach(QString key, _backends.keys()) {
228 ui.backendList->addItem(_backends[key].toMap()["DisplayName"].toString(), key);
231 on_backendList_currentIndexChanged();
235 int AuthenticationSelectionPage::nextId() const
237 return CoreConfigWizard::StorageSelectionPage;
241 QString AuthenticationSelectionPage::selectedBackend() const
243 return ui.backendList->currentText();
247 QVariantMap AuthenticationSelectionPage::connectionProperties() const
249 QString backend = ui.backendList->itemData(ui.backendList->currentIndex()).toString();
251 QVariantMap properties;
252 QStringList setupKeys = _backends[backend].toMap()["SetupKeys"].toStringList();
253 if (!setupKeys.isEmpty()) {
254 QVariantMap defaults = _backends[backend].toMap()["SetupDefaults"].toMap();
255 foreach(QString key, setupKeys) {
256 QWidget *widget = _connectionBox->findChild<QWidget *>(key);
258 if (defaults.contains(key)) {
261 switch (def.type()) {
264 QSpinBox *spinbox = qobject_cast<QSpinBox *>(widget);
266 def = QVariant(spinbox->value());
271 QLineEdit *lineEdit = qobject_cast<QLineEdit *>(widget);
273 def = QVariant(lineEdit->text());
276 properties[key] = def;
279 qDebug() << properties;
281 // QVariantMap properties = _backends[backend].toMap()["ConnectionProperties"].toMap();
282 // if(!properties.isEmpty() && _connectionBox) {
283 // QVariantMap::iterator propertyIter = properties.begin();
284 // while(propertyIter != properties.constEnd()) {
285 // QWidget *widget = _connectionBox->findChild<QWidget *>(propertyIter.key());
286 // switch(propertyIter.value().type()) {
287 // case QVariant::Int:
289 // QSpinBox *spinbox = qobject_cast<QSpinBox *>(widget);
290 // Q_ASSERT(spinbox);
291 // propertyIter.value() = QVariant(spinbox->value());
296 // QLineEdit *lineEdit = qobject_cast<QLineEdit *>(widget);
297 // Q_ASSERT(lineEdit);
298 // propertyIter.value() = QVariant(lineEdit->text());
308 void AuthenticationSelectionPage::on_backendList_currentIndexChanged()
310 QString backend = ui.backendList->itemData(ui.backendList->currentIndex()).toString();
311 ui.description->setText(_backends[backend].toMap()["Description"].toString());
313 if (_connectionBox) {
314 layout()->removeWidget(_connectionBox);
315 _connectionBox->deleteLater();
319 QStringList setupKeys = _backends[backend].toMap()["SetupKeys"].toStringList();
320 if (!setupKeys.isEmpty()) {
321 QVariantMap defaults = _backends[backend].toMap()["SetupDefaults"].toMap();
322 QGroupBox *propertyBox = new QGroupBox(this);
323 propertyBox->setTitle(tr("Connection Properties"));
324 QFormLayout *formlayout = new QFormLayout;
326 foreach(QString key, setupKeys) {
329 if (defaults.contains(key)) {
332 switch (def.type()) {
335 QSpinBox *spinbox = new QSpinBox(propertyBox);
336 spinbox->setMaximum(64000);
337 spinbox->setValue(def.toInt());
343 QLineEdit *lineEdit = new QLineEdit(def.toString(), propertyBox);
344 if (key.toLower().contains("password")) {
345 lineEdit->setEchoMode(QLineEdit::Password);
350 widget->setObjectName(key);
351 formlayout->addRow(key + ":", widget);
353 propertyBox->setLayout(formlayout);
354 static_cast<QVBoxLayout *>(layout())->insertWidget(layout()->indexOf(ui.descriptionBox) + 1, propertyBox);
355 _connectionBox = propertyBox;
359 /*** Storage Selection Page ***/
361 StorageSelectionPage::StorageSelectionPage(const QHash<QString, QVariant> &backends, QWidget *parent)
362 : QWizardPage(parent),
368 setTitle(tr("Select Storage Backend"));
369 setSubTitle(tr("Please select a database backend for the Quassel Core storage to store the backlog and other data in."));
372 registerField("storage.backend", ui.backendList);
374 int defaultIndex = 0;
375 foreach(QString key, _backends.keys()) {
376 ui.backendList->addItem(_backends[key].toMap()["DisplayName"].toString(), key);
377 if (_backends[key].toMap()["IsDefault"].toBool()) {
378 defaultIndex = ui.backendList->count() - 1;
382 ui.backendList->setCurrentIndex(defaultIndex);
384 on_backendList_currentIndexChanged();
388 int StorageSelectionPage::nextId() const
390 return CoreConfigWizard::SyncPage;
394 QString StorageSelectionPage::selectedBackend() const
396 return ui.backendList->currentText();
400 QVariantMap StorageSelectionPage::connectionProperties() const
402 QString backend = ui.backendList->itemData(ui.backendList->currentIndex()).toString();
404 QVariantMap properties;
405 QStringList setupKeys = _backends[backend].toMap()["SetupKeys"].toStringList();
406 if (!setupKeys.isEmpty()) {
407 QVariantMap defaults = _backends[backend].toMap()["SetupDefaults"].toMap();
408 foreach(QString key, setupKeys) {
409 QWidget *widget = _connectionBox->findChild<QWidget *>(key);
411 if (defaults.contains(key)) {
414 switch (def.type()) {
417 QSpinBox *spinbox = qobject_cast<QSpinBox *>(widget);
419 def = QVariant(spinbox->value());
424 QLineEdit *lineEdit = qobject_cast<QLineEdit *>(widget);
426 def = QVariant(lineEdit->text());
429 properties[key] = def;
432 qDebug() << properties;
434 // QVariantMap properties = _backends[backend].toMap()["ConnectionProperties"].toMap();
435 // if(!properties.isEmpty() && _connectionBox) {
436 // QVariantMap::iterator propertyIter = properties.begin();
437 // while(propertyIter != properties.constEnd()) {
438 // QWidget *widget = _connectionBox->findChild<QWidget *>(propertyIter.key());
439 // switch(propertyIter.value().type()) {
440 // case QVariant::Int:
442 // QSpinBox *spinbox = qobject_cast<QSpinBox *>(widget);
443 // Q_ASSERT(spinbox);
444 // propertyIter.value() = QVariant(spinbox->value());
449 // QLineEdit *lineEdit = qobject_cast<QLineEdit *>(widget);
450 // Q_ASSERT(lineEdit);
451 // propertyIter.value() = QVariant(lineEdit->text());
461 void StorageSelectionPage::on_backendList_currentIndexChanged()
463 QString backend = ui.backendList->itemData(ui.backendList->currentIndex()).toString();
464 ui.description->setText(_backends[backend].toMap()["Description"].toString());
466 if (_connectionBox) {
467 layout()->removeWidget(_connectionBox);
468 _connectionBox->deleteLater();
472 QStringList setupKeys = _backends[backend].toMap()["SetupKeys"].toStringList();
473 if (!setupKeys.isEmpty()) {
474 QVariantMap defaults = _backends[backend].toMap()["SetupDefaults"].toMap();
475 QGroupBox *propertyBox = new QGroupBox(this);
476 propertyBox->setTitle(tr("Connection Properties"));
477 QFormLayout *formlayout = new QFormLayout;
479 foreach(QString key, setupKeys) {
482 if (defaults.contains(key)) {
485 switch (def.type()) {
488 QSpinBox *spinbox = new QSpinBox(propertyBox);
489 spinbox->setMaximum(64000);
490 spinbox->setValue(def.toInt());
496 QLineEdit *lineEdit = new QLineEdit(def.toString(), propertyBox);
497 if (key.toLower().contains("password")) {
498 lineEdit->setEchoMode(QLineEdit::Password);
503 widget->setObjectName(key);
504 formlayout->addRow(key + ":", widget);
506 propertyBox->setLayout(formlayout);
507 static_cast<QVBoxLayout *>(layout())->insertWidget(layout()->indexOf(ui.descriptionBox) + 1, propertyBox);
508 _connectionBox = propertyBox;
515 SyncPage::SyncPage(QWidget *parent) : QWizardPage(parent)
518 setTitle(tr("Storing Your Settings"));
519 setSubTitle(tr("Your settings are now stored in the core, and you will be logged in automatically."));
523 void SyncPage::initializePage()
528 // Fill in sync info about the storage layer.
529 StorageSelectionPage *storagePage = qobject_cast<StorageSelectionPage *>(wizard()->page(CoreConfigWizard::StorageSelectionPage));
530 QString backend = storagePage->selectedBackend();
531 QVariantMap properties = storagePage->connectionProperties();
532 Q_ASSERT(!backend.isEmpty());
533 ui.backend->setText(backend);
535 // Fill in sync info about the authentication layer.
536 AuthenticationSelectionPage *authPage = qobject_cast<AuthenticationSelectionPage *>(wizard()->page(CoreConfigWizard::AuthenticationSelectionPage));
537 QString authBackend = authPage->selectedBackend();
538 QVariantMap authProperties = authPage->connectionProperties();
539 Q_ASSERT(!authBackend.isEmpty());
540 ui.authBackend->setText(authBackend);
542 ui.user->setText(wizard()->field("adminUser.user").toString());
544 emit setupCore(backend, properties, authBackend, authProperties);
548 int SyncPage::nextId() const
550 if (!hasError) return -1;
551 return CoreConfigWizard::SyncRelayPage;
555 bool SyncPage::isComplete() const
561 void SyncPage::setStatus(const QString &status)
563 ui.status->setText(status);
567 void SyncPage::setError(bool e)
573 void SyncPage::setComplete(bool c)
580 /*** Sync Relay Page ***/
582 SyncRelayPage::SyncRelayPage(QWidget *parent) : QWizardPage(parent)
588 void SyncRelayPage::setMode(Mode m)
595 void SyncRelayPage::initializePage() {
597 if(mode == Success) {
605 int SyncRelayPage::nextId() const
610 }; /* namespace CoreConfigWizardPages */