68735287f559aee837d652d9283bd28151a43818
[quassel.git] / src / qtui / coreconfigwizard.cpp
1 /***************************************************************************
2  *   Copyright (C) 2005-2016 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 <QIcon>
25 #include <QSpinBox>
26
27 #include "coreconfigwizard.h"
28 #include "coreconnection.h"
29
30 CoreConfigWizard::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, QIcon::fromTheme("quassel", QIcon(":/icons/quassel.png")).pixmap(48));
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
80 QHash<QString, QVariant> CoreConfigWizard::backends() const
81 {
82     return _backends;
83 }
84
85
86 void 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
96 void 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
105 void 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
116 void CoreConfigWizard::startOver()
117 {
118     foreach(int idx, visitedPages()) page(idx)->setEnabled(true);
119     setStartId(CoreConfigWizard::AdminUserPage);
120     restart();
121 }
122
123
124 void 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
133 void CoreConfigWizard::syncFinished()
134 {
135     accept();
136 }
137
138
139 namespace CoreConfigWizardPages {
140 /*** Intro Page ***/
141
142 IntroPage::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
151 int IntroPage::nextId() const
152 {
153     return CoreConfigWizard::AdminUserPage;
154 }
155
156
157 /*** Admin User Page ***/
158
159 AdminUserPage::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
176 int AdminUserPage::nextId() const
177 {
178     return CoreConfigWizard::StorageSelectionPage;
179 }
180
181
182 bool 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
191 StorageSelectionPage::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     int defaultIndex = 0;
205     foreach(QString key, _backends.keys()) {
206         ui.backendList->addItem(_backends[key].toMap()["DisplayName"].toString(), key);
207         if (_backends[key].toMap()["IsDefault"].toBool()) {
208             defaultIndex = ui.backendList->count() - 1;
209         }
210     }
211
212     ui.backendList->setCurrentIndex(defaultIndex);
213
214     on_backendList_currentIndexChanged();
215 }
216
217
218 int StorageSelectionPage::nextId() const
219 {
220     return CoreConfigWizard::SyncPage;
221 }
222
223
224 QString StorageSelectionPage::selectedBackend() const
225 {
226     return ui.backendList->currentText();
227 }
228
229
230 QVariantMap StorageSelectionPage::connectionProperties() const
231 {
232     QString backend = ui.backendList->itemData(ui.backendList->currentIndex()).toString();
233
234     QVariantMap properties;
235     QStringList setupKeys = _backends[backend].toMap()["SetupKeys"].toStringList();
236     if (!setupKeys.isEmpty()) {
237         QVariantMap defaults = _backends[backend].toMap()["SetupDefaults"].toMap();
238         foreach(QString key, setupKeys) {
239             QWidget *widget = _connectionBox->findChild<QWidget *>(key);
240             QVariant def;
241             if (defaults.contains(key)) {
242                 def = defaults[key];
243             }
244             switch (def.type()) {
245             case QVariant::Int:
246             {
247                 QSpinBox *spinbox = qobject_cast<QSpinBox *>(widget);
248                 Q_ASSERT(spinbox);
249                 def = QVariant(spinbox->value());
250             }
251             break;
252             default:
253             {
254                 QLineEdit *lineEdit = qobject_cast<QLineEdit *>(widget);
255                 Q_ASSERT(lineEdit);
256                 def = QVariant(lineEdit->text());
257             }
258             }
259             properties[key] = def;
260         }
261     }
262     qDebug() << properties;
263
264 //   QVariantMap properties = _backends[backend].toMap()["ConnectionProperties"].toMap();
265 //   if(!properties.isEmpty() && _connectionBox) {
266 //     QVariantMap::iterator propertyIter = properties.begin();
267 //     while(propertyIter != properties.constEnd()) {
268 //       QWidget *widget = _connectionBox->findChild<QWidget *>(propertyIter.key());
269 //       switch(propertyIter.value().type()) {
270 //       case QVariant::Int:
271 //      {
272 //        QSpinBox *spinbox = qobject_cast<QSpinBox *>(widget);
273 //        Q_ASSERT(spinbox);
274 //        propertyIter.value() = QVariant(spinbox->value());
275 //      }
276 //      break;
277 //       default:
278 //      {
279 //        QLineEdit *lineEdit = qobject_cast<QLineEdit *>(widget);
280 //        Q_ASSERT(lineEdit);
281 //        propertyIter.value() = QVariant(lineEdit->text());
282 //      }
283 //       }
284 //       propertyIter++;
285 //     }
286 //   }
287     return properties;
288 }
289
290
291 void StorageSelectionPage::on_backendList_currentIndexChanged()
292 {
293     QString backend = ui.backendList->itemData(ui.backendList->currentIndex()).toString();
294     ui.description->setText(_backends[backend].toMap()["Description"].toString());
295
296     if (_connectionBox) {
297         layout()->removeWidget(_connectionBox);
298         _connectionBox->deleteLater();
299         _connectionBox = 0;
300     }
301
302     QStringList setupKeys = _backends[backend].toMap()["SetupKeys"].toStringList();
303     if (!setupKeys.isEmpty()) {
304         QVariantMap defaults = _backends[backend].toMap()["SetupDefaults"].toMap();
305         QGroupBox *propertyBox = new QGroupBox(this);
306         propertyBox->setTitle(tr("Connection Properties"));
307         QFormLayout *formlayout = new QFormLayout;
308
309         foreach(QString key, setupKeys) {
310             QWidget *widget = 0;
311             QVariant def;
312             if (defaults.contains(key)) {
313                 def = defaults[key];
314             }
315             switch (def.type()) {
316             case QVariant::Int:
317             {
318                 QSpinBox *spinbox = new QSpinBox(propertyBox);
319                 spinbox->setMaximum(64000);
320                 spinbox->setValue(def.toInt());
321                 widget = spinbox;
322             }
323             break;
324             default:
325             {
326                 QLineEdit *lineEdit = new QLineEdit(def.toString(), propertyBox);
327                 if (key.toLower().contains("password")) {
328                     lineEdit->setEchoMode(QLineEdit::Password);
329                 }
330                 widget = lineEdit;
331             }
332             }
333             widget->setObjectName(key);
334             formlayout->addRow(key + ":", widget);
335         }
336         propertyBox->setLayout(formlayout);
337         static_cast<QVBoxLayout *>(layout())->insertWidget(layout()->indexOf(ui.descriptionBox) + 1, propertyBox);
338         _connectionBox = propertyBox;
339     }
340 }
341
342
343 /*** Sync Page ***/
344
345 SyncPage::SyncPage(QWidget *parent) : QWizardPage(parent)
346 {
347     ui.setupUi(this);
348     setTitle(tr("Storing Your Settings"));
349     setSubTitle(tr("Your settings are now stored in the core, and you will be logged in automatically."));
350 }
351
352
353 void SyncPage::initializePage()
354 {
355     complete = false;
356     hasError = false;
357
358     StorageSelectionPage *storagePage = qobject_cast<StorageSelectionPage *>(wizard()->page(CoreConfigWizard::StorageSelectionPage));
359     QString backend = storagePage->selectedBackend();
360     QVariantMap properties = storagePage->connectionProperties();
361     Q_ASSERT(!backend.isEmpty());
362     ui.user->setText(wizard()->field("adminUser.user").toString());
363     ui.backend->setText(backend);
364     emit setupCore(backend, properties);
365 }
366
367
368 int SyncPage::nextId() const
369 {
370     if (!hasError) return -1;
371     return CoreConfigWizard::SyncRelayPage;
372 }
373
374
375 bool SyncPage::isComplete() const
376 {
377     return complete;
378 }
379
380
381 void SyncPage::setStatus(const QString &status)
382 {
383     ui.status->setText(status);
384 }
385
386
387 void SyncPage::setError(bool e)
388 {
389     hasError = e;
390 }
391
392
393 void SyncPage::setComplete(bool c)
394 {
395     complete = c;
396     completeChanged();
397 }
398
399
400 /*** Sync Relay Page ***/
401
402 SyncRelayPage::SyncRelayPage(QWidget *parent) : QWizardPage(parent)
403 {
404     mode = Success;
405 }
406
407
408 void SyncRelayPage::setMode(Mode m)
409 {
410     mode = m;
411 }
412
413
414 /*
415 void SyncRelayPage::initializePage() {
416   return;
417   if(mode == Success) {
418     wizard()->accept();
419   } else {
420     emit startOver();
421   }
422 }
423 */
424
425 int SyncRelayPage::nextId() const
426 {
427     emit startOver();
428     return 0;
429 }
430 };  /* namespace CoreConfigWizardPages */