Don't loop indefinitely while trying to teach manners to Qt
[quassel.git] / src / qtui / coreconfigwizard.cpp
1 /***************************************************************************
2  *   Copyright (C) 2005-09 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  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
19  ***************************************************************************/
20
21 #include <QDebug>
22 #include <QAbstractButton>
23 #include <QFormLayout>
24 #include <QSpinBox>
25
26 #include "coreconfigwizard.h"
27 #include "iconloader.h"
28
29 CoreConfigWizard::CoreConfigWizard(const QList<QVariant> &backends, QWidget *parent) : QWizard(parent) {
30   foreach(QVariant v, backends) _backends[v.toMap()["DisplayName"].toString()] = v;
31   setPage(IntroPage, new CoreConfigWizardPages::IntroPage(this));
32   setPage(AdminUserPage, new CoreConfigWizardPages::AdminUserPage(this));
33   setPage(StorageSelectionPage, new CoreConfigWizardPages::StorageSelectionPage(_backends, this));
34   syncPage = new CoreConfigWizardPages::SyncPage(this);
35   connect(syncPage, SIGNAL(setupCore(const QString &, const QVariantMap &)), this, SLOT(prepareCoreSetup(const QString &, const QVariantMap &)));
36   setPage(SyncPage, syncPage);
37   syncRelayPage = new CoreConfigWizardPages::SyncRelayPage(this);
38   connect(syncRelayPage, SIGNAL(startOver()), this, SLOT(startOver()));
39   setPage(SyncRelayPage, syncRelayPage);
40   //setPage(Page_StorageDetails, new StorageDetailsPage());
41   //setPage(Page_Conclusion, new ConclusionPage(storageProviders));
42
43   setStartId(IntroPage);
44   //setStartId(StorageSelectionPage);
45
46 #ifndef Q_WS_MAC
47   setWizardStyle(ModernStyle);
48 #endif
49
50   setOption(HaveHelpButton, false);
51   setOption(NoBackButtonOnStartPage, true);
52   setOption(HaveNextButtonOnLastPage, false);
53   setOption(HaveFinishButtonOnEarlyPages, false);
54   setOption(NoCancelButton, true);
55   setOption(IndependentPages, true);
56   //setOption(ExtendedWatermarkPixmap, true);
57
58   setModal(true);
59
60   setWindowTitle(tr("Core Configuration Wizard"));
61   setPixmap(QWizard::LogoPixmap, DesktopIcon("quassel"));
62 }
63
64 QHash<QString, QVariant> CoreConfigWizard::backends() const {
65   return _backends;
66 }
67
68 void CoreConfigWizard::prepareCoreSetup(const QString &backend, const QVariantMap &properties) {
69   // Prevent the user from changing any settings he already specified...
70   foreach(int idx, visitedPages())
71     page(idx)->setEnabled(false);
72
73   QVariantMap foo;
74   foo["AdminUser"] = field("adminUser.user").toString();
75   foo["AdminPasswd"] = field("adminUser.password").toString();
76   foo["Backend"] = backend;
77   foo["ConnectionProperties"] = properties;
78   emit setupCore(foo);
79 }
80
81 void CoreConfigWizard::coreSetupSuccess() {
82   syncPage->setStatus(tr("Your core has been successfully configured. Logging you in..."));
83   syncPage->setError(false);
84   syncRelayPage->setMode(CoreConfigWizardPages::SyncRelayPage::Error);
85   QVariantMap loginData;
86   loginData["User"] = field("adminUser.user");
87   loginData["Password"] = field("adminUser.password");
88   loginData["RememberPasswd"] = field("adminUser.rememberPasswd");
89   emit loginToCore(loginData);
90 }
91
92 void CoreConfigWizard::coreSetupFailed(const QString &error) {
93   syncPage->setStatus(tr("Core configuration failed:<br><b>%1</b><br>Press <em>Next</em> to start over.").arg(error));
94   syncPage->setError(true);
95   syncRelayPage->setMode(CoreConfigWizardPages::SyncRelayPage::Error);
96   //foreach(int idx, visitedPages()) page(idx)->setEnabled(true);
97   //setStartId(SyncPage);
98   //restart();
99 }
100
101 void CoreConfigWizard::startOver() {
102   foreach(int idx, visitedPages()) page(idx)->setEnabled(true);
103   setStartId(CoreConfigWizard::AdminUserPage);
104   restart();
105 }
106
107 void CoreConfigWizard::loginSuccess() {
108   syncPage->setStatus(tr("Your are now logged into your freshly configured Quassel Core!<br>"
109                          "Please remember to configure your identities and networks now."));
110   syncPage->setComplete(true);
111   syncPage->setFinalPage(true);
112 }
113
114 void CoreConfigWizard::syncFinished() {
115   // TODO: display identities and networks settings if appropriate!
116   // accept();
117 }
118
119 namespace CoreConfigWizardPages {
120
121 /*** Intro Page ***/
122
123 IntroPage::IntroPage(QWidget *parent) : QWizardPage(parent) {
124   ui.setupUi(this);
125   setTitle(tr("Introduction"));
126   //setSubTitle(tr("foobar"));
127   //setPixmap(QWizard::WatermarkPixmap, QPixmap(":icons/quassel-icon.png"));
128
129 }
130
131 int IntroPage::nextId() const {
132   return CoreConfigWizard::AdminUserPage;
133
134 }
135
136 /*** Admin User Page ***/
137
138 AdminUserPage::AdminUserPage(QWidget *parent) : QWizardPage(parent) {
139   ui.setupUi(this);
140   setTitle(tr("Create Admin User"));
141   setSubTitle(tr("First, we will create a user on the core. This first user will have administrator privileges."));
142
143   registerField("adminUser.user*", ui.user);
144   registerField("adminUser.password*", ui.password);
145   registerField("adminUser.password2*", ui.password2);
146   registerField("adminUser.rememberPasswd", ui.rememberPasswd);
147
148   //ui.user->setText("foo");
149   //ui.password->setText("foo");
150   //ui.password2->setText("foo");
151 }
152
153 int AdminUserPage::nextId() const {
154   return CoreConfigWizard::StorageSelectionPage;
155
156 }
157
158 bool AdminUserPage::isComplete() const {
159   bool ok = !ui.user->text().isEmpty() && !ui.password->text().isEmpty() && ui.password->text() == ui.password2->text();
160   return ok;
161 }
162
163 /*** Storage Selection Page ***/
164
165 StorageSelectionPage::StorageSelectionPage(const QHash<QString, QVariant> &backends, QWidget *parent)
166   : QWizardPage(parent),
167     _connectionBox(0),
168     _backends(backends)
169 {
170   ui.setupUi(this);
171
172   setTitle(tr("Select Storage Backend"));
173   setSubTitle(tr("Please select a database backend for the Quassel Core storage to store the backlog and other data in."));
174   setCommitPage(true);
175
176   registerField("storage.backend", ui.backendList);
177
178   foreach(QString key, _backends.keys()) {
179     ui.backendList->addItem(_backends[key].toMap()["DisplayName"].toString(), key);
180   }
181
182   on_backendList_currentIndexChanged();
183 }
184
185 int StorageSelectionPage::nextId() const {
186   return CoreConfigWizard::SyncPage;
187 }
188
189 QString StorageSelectionPage::selectedBackend() const {
190   return ui.backendList->currentText();
191 }
192
193 QVariantMap StorageSelectionPage::connectionProperties() const {
194   QString backend = ui.backendList->itemData(ui.backendList->currentIndex()).toString();
195
196   QVariantMap properties;
197   QStringList setupKeys = _backends[backend].toMap()["SetupKeys"].toStringList();
198   if(!setupKeys.isEmpty()) {
199     QVariantMap defaults = _backends[backend].toMap()["SetupDefaults"].toMap();
200     foreach(QString key, setupKeys) {
201       QWidget *widget = _connectionBox->findChild<QWidget *>(key);
202       QVariant def;
203       if(defaults.contains(key)) {
204         def = defaults[key];
205       }
206       switch(def.type()) {
207       case QVariant::Int:
208         {
209           QSpinBox *spinbox = qobject_cast<QSpinBox *>(widget);
210           Q_ASSERT(spinbox);
211           def = QVariant(spinbox->value());
212         }
213         break;
214       default:
215         {
216           QLineEdit *lineEdit = qobject_cast<QLineEdit *>(widget);
217           Q_ASSERT(lineEdit);
218           def = QVariant(lineEdit->text());
219         }
220       }
221       properties[key] = def;
222     }
223   }
224   qDebug() << properties;
225
226
227 //   QVariantMap properties = _backends[backend].toMap()["ConnectionProperties"].toMap();
228 //   if(!properties.isEmpty() && _connectionBox) {
229 //     QVariantMap::iterator propertyIter = properties.begin();
230 //     while(propertyIter != properties.constEnd()) {
231 //       QWidget *widget = _connectionBox->findChild<QWidget *>(propertyIter.key());
232 //       switch(propertyIter.value().type()) {
233 //       case QVariant::Int:
234 //      {
235 //        QSpinBox *spinbox = qobject_cast<QSpinBox *>(widget);
236 //        Q_ASSERT(spinbox);
237 //        propertyIter.value() = QVariant(spinbox->value());
238 //      }
239 //      break;
240 //       default:
241 //      {
242 //        QLineEdit *lineEdit = qobject_cast<QLineEdit *>(widget);
243 //        Q_ASSERT(lineEdit);
244 //        propertyIter.value() = QVariant(lineEdit->text());
245 //      }
246 //       }
247 //       propertyIter++;
248 //     }
249 //   }
250   return properties;
251 }
252
253 void StorageSelectionPage::on_backendList_currentIndexChanged() {
254   QString backend = ui.backendList->itemData(ui.backendList->currentIndex()).toString();
255   ui.description->setText(_backends[backend].toMap()["Description"].toString());
256
257   if(_connectionBox) {
258     layout()->removeWidget(_connectionBox);
259     _connectionBox->deleteLater();
260     _connectionBox = 0;
261   }
262
263   QStringList setupKeys = _backends[backend].toMap()["SetupKeys"].toStringList();
264   if(!setupKeys.isEmpty()) {
265     QVariantMap defaults = _backends[backend].toMap()["SetupDefaults"].toMap();
266     QGroupBox *propertyBox = new QGroupBox(this);
267     propertyBox->setTitle(tr("Connection Properties"));
268     QFormLayout *formlayout = new QFormLayout;
269
270     foreach(QString key, setupKeys) {
271       QWidget *widget = 0;
272       QVariant def;
273       if(defaults.contains(key)) {
274         def = defaults[key];
275       }
276       switch(def.type()) {
277       case QVariant::Int:
278         {
279           QSpinBox *spinbox = new QSpinBox(propertyBox);
280           spinbox->setMaximum(64000);
281           spinbox->setValue(def.toInt());
282           widget = spinbox;
283         }
284         break;
285       default:
286         {
287           QLineEdit *lineEdit = new QLineEdit(def.toString(), propertyBox);
288           if(key.toLower().contains("password")) {
289             lineEdit->setEchoMode(QLineEdit::Password);
290           }
291           widget = lineEdit;
292         }
293       }
294       widget->setObjectName(key);
295       formlayout->addRow(key + ":", widget);
296     }
297     propertyBox->setLayout(formlayout);
298     static_cast<QVBoxLayout *>(layout())->insertWidget(layout()->indexOf(ui.descriptionBox) + 1, propertyBox);
299     _connectionBox = propertyBox;
300   }
301 }
302
303 /*** Sync Page ***/
304
305 SyncPage::SyncPage(QWidget *parent) : QWizardPage(parent) {
306   ui.setupUi(this);
307   setTitle(tr("Storing Your Settings"));
308   setSubTitle(tr("Your settings are now stored in the core, and you will be logged in automatically."));
309 }
310
311 void SyncPage::initializePage() {
312   complete = false;
313   hasError = false;
314
315   StorageSelectionPage *storagePage = qobject_cast<StorageSelectionPage *>(wizard()->page(CoreConfigWizard::StorageSelectionPage));
316   QString backend = storagePage->selectedBackend();
317   QVariantMap properties = storagePage->connectionProperties();
318   Q_ASSERT(!backend.isEmpty());
319   ui.user->setText(wizard()->field("adminUser.user").toString());
320   ui.backend->setText(backend);
321   emit setupCore(backend, properties);
322 }
323
324 int SyncPage::nextId() const {
325   if(!hasError) return -1;
326   return CoreConfigWizard::SyncRelayPage;
327 }
328
329 bool SyncPage::isComplete() const {
330   return complete;
331 }
332
333 void SyncPage::setStatus(const QString &status) {
334   ui.status->setText(status);
335 }
336
337 void SyncPage::setError(bool e) {
338   hasError = e;
339 }
340
341 void SyncPage::setComplete(bool c) {
342   complete = c;
343   completeChanged();
344 }
345
346 /*** Sync Relay Page ***/
347
348 SyncRelayPage::SyncRelayPage(QWidget *parent) : QWizardPage(parent) {
349   mode = Success;
350 }
351
352 void SyncRelayPage::setMode(Mode m) {
353   mode = m;
354 }
355
356 /*
357 void SyncRelayPage::initializePage() {
358   return;
359   if(mode == Success) {
360     wizard()->accept();
361   } else {
362     emit startOver();
363   }
364 }
365 */
366
367 int SyncRelayPage::nextId() const {
368   emit startOver();
369   return 0;
370 }
371
372 };  /* namespace CoreConfigWizardPages */