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