Ok, the long awaited config wizard is here (at least in a very basic state). There...
authorMarco Genise <kaffeedoktor@quassel-irc.org>
Mon, 5 Nov 2007 20:48:46 +0000 (20:48 +0000)
committerMarco Genise <kaffeedoktor@quassel-irc.org>
Mon, 5 Nov 2007 20:48:46 +0000 (20:48 +0000)
20 files changed:
src/client/client.cpp
src/client/client.h
src/common/global.cpp
src/common/global.h
src/common/main.cpp
src/core/core.cpp
src/core/core.h
src/core/core.pri
src/core/coresession.cpp
src/core/coresettings.cpp [new file with mode: 0644]
src/core/coresettings.h [new file with mode: 0644]
src/core/sqlitestorage.cpp
src/core/sqlitestorage.h
src/core/storage.cpp
src/core/storage.h
src/qtui/configwizard.cpp [new file with mode: 0644]
src/qtui/configwizard.h [new file with mode: 0644]
src/qtui/coreconnectdlg.cpp
src/qtui/coreconnectdlg.h
src/qtui/qtui.pri

index 2500b27..28df087 100644 (file)
@@ -247,6 +247,10 @@ void Client::disconnectFromCore() {
   }
 }
 
+void Client::setCoreConfiguration(const QVariantMap &settings) {
+  writeDataToDevice(socket, settings);
+}
+
 void Client::coreSocketConnected() {
   connect(this, SIGNAL(recvPartialItem(uint, uint)), this, SIGNAL(coreConnectionProgress(uint, uint)));
   emit coreConnectionMsg(tr("Synchronizing to core..."));
@@ -415,7 +419,14 @@ void Client::coreHasData() {
   QVariant item;
   if(readDataFromDevice(socket, blockSize, item)) {
     emit recvPartialItem(1,1);
-    recvCoreState(item);
+    QVariantMap msg = item.toMap();
+    if (!msg["StartWizard"].toBool()) {
+      recvCoreState(msg["Reply"]);
+    } else {
+      qWarning("Core not configured!");
+      qDebug() << "Available storage providers: " << msg["StorageProviders"].toStringList();
+      emit showConfigWizard(msg);
+    }
     blockSize = 0;
     return;
   }
index 349b5ab..f3ac138 100644 (file)
@@ -89,6 +89,8 @@ signals:
   void coreConnectionError(QString errorMsg);
   void coreConnectionMsg(const QString &msg);
   void coreConnectionProgress(uint part, uint total);
+    
+  void showConfigWizard(const QVariantMap &coredata);
 
   void connected();
   void disconnected();
@@ -102,6 +104,8 @@ public slots:
   //void connectToLocalCore();
   void connectToCore(const QVariantMap &);
   void disconnectFromCore();
+    
+  void setCoreConfiguration(const QVariantMap &settings);
 
 private slots:
   void recvCoreState(const QVariant &state);
index cdb3376..954e52b 100644 (file)
@@ -60,4 +60,3 @@ void Global::initIconMap() {
 //}
 
 Global::RunMode Global::runMode;
-QString Global::quasselDir;
index 6da6103..33d52f4 100644 (file)
@@ -44,7 +44,6 @@ typedef uint NetworkId;
 namespace Global {
   enum RunMode { Monolithic, ClientOnly, CoreOnly };
   extern RunMode runMode;
-  extern QString quasselDir;
 }
 
 struct Exception {
index fc5c0f7..3ca8e34 100644 (file)
@@ -85,7 +85,6 @@ int main(int argc, char **argv) {
   QCoreApplication::setApplicationName("Quassel IRC");
   QCoreApplication::setOrganizationName("Quassel IRC Development Team");
 
-  Global::quasselDir = QDir::homePath() + "/.quassel";
 #ifndef BUILD_QTUI
   Core::instance();  // create and init the core
 #endif
index 7b57661..9bd36fb 100644 (file)
 
 #include "core.h"
 #include "coresession.h"
+#include "coresettings.h"
 #include "sqlitestorage.h"
 #include "util.h"
 
+#include <QMetaObject>
+#include <QMetaMethod>
+
 Core *Core::instanceptr = 0;
 
 Core *Core::instance() {
@@ -38,22 +42,54 @@ void Core::destroy() {
 }
 
 Core::Core() {
+  storage = NULL;
 }
 
 void Core::init() {
-  if(!SqliteStorage::isAvailable()) {
-    qFatal("Sqlite is currently required! Please make sure your Qt library has sqlite support enabled.");
+  CoreSettings s;
+  configured = false;
+
+  QVariantMap dbSettings = s.databaseSettings().toMap();
+  QString hname = dbSettings["Type"].toString().toLower();
+  hname[0] = hname[0].toUpper();
+  hname = "initStorage" + hname;
+  if (!QMetaObject::invokeMethod(this, hname.toAscii(), Q_RETURN_ARG(bool, configured),  Q_ARG(QVariantMap, dbSettings), Q_ARG(bool, false))) {
+    qWarning("No database backend configured.");
   }
-  //SqliteStorage::init();
-  storage = new SqliteStorage();
+  
+  if (!configured) {
+    qWarning("Core is currently not configured!");
+  }
+    
   connect(&server, SIGNAL(newConnection()), this, SLOT(incomingConnection()));
-  startListening(); // FIXME make configurable
+  startListening(s.port());
   guiUser = 0;
 }
 
+bool Core::initStorageSqlite(QVariantMap dbSettings, bool setup) {
+  if (!SqliteStorage::isAvailable()) {
+    qFatal("Sqlite is currently required! Please make sure your Qt library has sqlite support enabled.");
+  }
+  if (storage) {
+    qDebug() << "Deleting old storage object.";
+    delete storage;
+    storage = NULL;
+  }
+  
+  storage = new SqliteStorage();
+  if (setup && !storage->setup(dbSettings)) {
+    return false;
+  }
+  
+  return storage->init(dbSettings);
+}
+
 Core::~Core() {
   qDeleteAll(sessions);
-  delete storage;
+  if (storage) {
+    delete storage;
+    storage = NULL;
+  }
 }
 
 CoreSession *Core::session(UserId uid) {
@@ -76,7 +112,6 @@ CoreSession *Core::createSession(UserId uid) {
   return sess;
 }
 
-
 bool Core::startListening(uint port) {
   if(!server.listen(QHostAddress::Any, port)) {
     qWarning(QString(QString("Could not open GUI client port %1: %2").arg(port).arg(server.errorString())).toAscii());
@@ -93,12 +128,18 @@ void Core::stopListening() {
 
 void Core::incomingConnection() {
   // TODO implement SSL
-  // TODO While
-  QTcpSocket *socket = server.nextPendingConnection();
-  connect(socket, SIGNAL(disconnected()), this, SLOT(clientDisconnected()));
-  connect(socket, SIGNAL(readyRead()), this, SLOT(clientHasData()));
-  blockSizes.insert(socket, (quint32)0);
-  qDebug() << "Client connected from " << socket->peerAddress().toString();
+  while (server.hasPendingConnections()) {
+    QTcpSocket *socket = server.nextPendingConnection();
+    connect(socket, SIGNAL(disconnected()), this, SLOT(clientDisconnected()));
+    connect(socket, SIGNAL(readyRead()), this, SLOT(clientHasData()));
+    blockSizes.insert(socket, (quint32)0);
+    qDebug() << "Client connected from " << socket->peerAddress().toString();
+    
+    if (!configured) {
+      server.close();
+      qDebug() << "Closing server for basic setup.";
+    }
+  }
 }
 
 void Core::clientHasData() {
@@ -109,7 +150,15 @@ void Core::clientHasData() {
   if(readDataFromDevice(socket, bsize, item)) {
     // we need to auth the client
     try {
-      processClientInit(socket, item);
+      QVariantMap msg = item.toMap();
+      if (msg["GuiProtocol"].toUInt() != GUI_PROTOCOL) {
+        throw Exception("GUI client version mismatch");
+      }
+      if (configured) {
+        processClientInit(socket, msg);
+      } else {
+        processCoreSetup(socket, msg);
+      }
     } catch(Storage::AuthError) {
       qWarning() << "Authentification error!";  // FIXME: send auth error to client
       socket->close();
@@ -124,10 +173,17 @@ void Core::clientHasData() {
 }
 
 // FIXME: no longer called, since connection handling is now in SignalProxy
+// No, it is called as long as core is not configured. (kaffeedoktor)
 void Core::clientDisconnected() {
   QTcpSocket *socket = dynamic_cast<QTcpSocket*>(sender());
   blockSizes.remove(socket);
   qDebug() << "Client disconnected.";
+  
+  // make server listen again if still not configured
+  if (!configured) {
+    startListening();
+  }
+  
   // TODO remove unneeded sessions - if necessary/possible...
 }
 
@@ -144,21 +200,58 @@ void Core::disconnectLocalClient() {
   instance()->guiUser = 0;
 }
 
-void Core::processClientInit(QTcpSocket *socket, const QVariant &v) {
-  QVariantMap msg = v.toMap();
-  if(msg["GuiProtocol"].toUInt() != GUI_PROTOCOL) {
-    //qWarning() << "Client version mismatch.";
-    throw Exception("GUI client version mismatch");
-  }
-    // Auth
-  UserId uid = storage->validateUser(msg["User"].toString(), msg["Password"].toString());  // throws exception if this failed
-  QVariant reply = initSession(uid);
+void Core::processClientInit(QTcpSocket *socket, const QVariantMap &msg) {
+  // Auth
+  QVariantMap reply;
+  UserId uid = storage->validateUser(msg["User"].toString(), msg["Password"].toString()); // throws exception if this failed
+  reply["StartWizard"] = false;
+  reply["Reply"] = initSession(uid);
   disconnect(socket, 0, this, 0);
   sessions[uid]->addClient(socket);
   qDebug() << "Client initialized successfully.";
   writeDataToDevice(socket, reply);
 }
 
+void Core::processCoreSetup(QTcpSocket *socket, QVariantMap &msg) {
+  if(msg["HasSettings"].toBool()) {
+    QVariantMap auth;
+    auth["User"] = msg["User"];
+    auth["Password"] = msg["Password"];
+    msg.remove("User");
+    msg.remove("Password");
+    qDebug() << "Initializing storage provider" << msg["Type"].toString();
+    QString hname = msg["Type"].toString().toLower();
+    hname[0] = hname[0].toUpper();
+    hname = "initStorage" + hname;
+    if (!QMetaObject::invokeMethod(this, hname.toAscii(), Q_RETURN_ARG(bool, configured),  Q_ARG(QVariantMap, msg), Q_ARG(bool, true))) {
+      qWarning("No database backend configured.");
+    }
+    if (!configured) {
+      // notify client to start wizard again
+      qWarning("Core is currently not configured!");
+      QVariantMap reply;
+      reply["StartWizard"] = true;
+      reply["StorageProviders"] = availableStorageProviders();
+      writeDataToDevice(socket, reply);
+    } else {
+      // write coresettings
+      CoreSettings s;
+      s.setDatabaseSettings(msg);
+      // write admin user to database & make the core listen again to connections
+      storage->addUser(auth["User"].toString(), auth["Password"].toString());
+      startListening();
+      // continue the normal procedure
+      processClientInit(socket, auth);
+    }
+  } else {
+    // notify client to start wizard
+    QVariantMap reply;
+    reply["StartWizard"] = true;
+    reply["StorageProviders"] = availableStorageProviders();
+    writeDataToDevice(socket, reply);
+  }
+}
+
 QVariant Core::initSession(UserId uid) {
   // Find or create session for validated user
   CoreSession *sess;
@@ -170,3 +263,14 @@ QVariant Core::initSession(UserId uid) {
   reply["SessionState"] = sess->sessionState();
   return reply;
 }
+
+QStringList Core::availableStorageProviders() {
+  QStringList storageProviders;
+  if (SqliteStorage::isAvailable()) {
+    storageProviders.append(SqliteStorage::displayName());
+  }
+  // TODO: temporary
+  storageProviders.append("MySQL");
+  
+  return storageProviders;
+}
index 5e73b7c..602f7bf 100644 (file)
@@ -52,12 +52,14 @@ class Core : public QObject {
     void clientHasData();
     void clientDisconnected();
 
+    bool initStorageSqlite(QVariantMap dbSettings, bool setup);
+
   private:
     Core();
     ~Core();
     void init();
     static Core *instanceptr;
-
+    
     //! Initiate a session for the user with the given credentials if one does not already exist.
     /** This function is called during the init process for a new client. If there is no session for the
      *  given user, one is created.
@@ -65,7 +67,10 @@ class Core : public QObject {
      * \return A QVariant containing the session data, e.g. global data and buffers
      */
     QVariant initSession(UserId userId);
-    void processClientInit(QTcpSocket *socket, const QVariant &v);
+    void processClientInit(QTcpSocket *socket, const QVariantMap &msg);
+    void processCoreSetup(QTcpSocket *socket, QVariantMap &msg);
+    
+    QStringList availableStorageProviders();
 
     UserId guiUser;
     QHash<UserId, CoreSession *> sessions;
@@ -73,6 +78,8 @@ class Core : public QObject {
 
     QTcpServer server; // TODO: implement SSL
     QHash<QTcpSocket *, quint32> blockSizes;
+    
+    bool configured;
 };
 
 #endif
index 7f6c68f..13e537d 100644 (file)
@@ -1,4 +1,4 @@
 DEPMOD = common
 QT_MOD = core network sql
-SRCS = core.cpp coresession.cpp server.cpp sqlitestorage.cpp storage.cpp basichandler.cpp ircserverhandler.cpp userinputhandler.cpp ctcphandler.cpp 
-HDRS = core.h coresession.h server.h sqlitestorage.h storage.h basichandler.h ircserverhandler.h userinputhandler.h ctcphandler.h 
+SRCS = core.cpp coresession.cpp coresettings.cpp server.cpp sqlitestorage.cpp storage.cpp basichandler.cpp ircserverhandler.cpp userinputhandler.cpp ctcphandler.cpp 
+HDRS = core.h coresession.h coresettings.h server.h sqlitestorage.h storage.h basichandler.h ircserverhandler.h userinputhandler.h ctcphandler.h 
index 0cec934..0accebb 100644 (file)
@@ -52,7 +52,6 @@ CoreSession::CoreSession(UserId uid, Storage *_storage, QObject *parent)
   p->attachSlot(SIGNAL(requestNetworkStates()), this, SLOT(serverStateRequested()));
   p->attachSlot(SIGNAL(requestConnect(QString)), this, SLOT(connectToNetwork(QString)));
   p->attachSlot(SIGNAL(sendInput(BufferInfo, QString)), this, SLOT(msgFromGui(BufferInfo, QString)));
-  p->attachSlot(SIGNAL(importOldBacklog()), storage, SLOT(importOldBacklog()));
   p->attachSlot(SIGNAL(requestBacklog(BufferInfo, QVariant, QVariant)), this, SLOT(sendBacklog(BufferInfo, QVariant, QVariant)));
   p->attachSignal(this, SIGNAL(displayMsg(Message)));
   p->attachSignal(this, SIGNAL(displayStatusMsg(QString, QString)));
diff --git a/src/core/coresettings.cpp b/src/core/coresettings.cpp
new file mode 100644 (file)
index 0000000..579713a
--- /dev/null
@@ -0,0 +1,59 @@
+/***************************************************************************
+ *   Copyright (C) 2005-07 by The Quassel IRC Development Team             *
+ *   devel@quassel-irc.org                                                 *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+
+#include "coresettings.h"
+
+#include <QStringList>
+
+CoreSettings::CoreSettings() : Settings("Core") {
+}
+
+CoreSettings::~CoreSettings() {
+}
+
+void CoreSettings::setDatabaseSettings(const QVariant &data) {
+  setLocalValue("DatabaseSettings", data);
+}
+
+QVariant CoreSettings::databaseSettings(const QVariant &def) {
+  return localValue("DatabaseSettings", def);
+}
+
+void CoreSettings::setPort(const uint &port) {
+  setLocalValue("Port", port);
+}
+
+uint CoreSettings::port(const uint &def) {
+  return localValue("Port", def).toUInt();
+}
+
+QStringList CoreSettings::sessionKeys() {
+  Q_ASSERT(false);
+  return QStringList();
+}
+
+void CoreSettings::setSessionValue(const QString &key, const QVariant &data) {
+  Q_ASSERT(false);
+}
+
+QVariant CoreSettings::sessionValue(const QString &key, const QVariant &def) {
+  Q_ASSERT(false);
+  return QVariant();
+}
diff --git a/src/core/coresettings.h b/src/core/coresettings.h
new file mode 100644 (file)
index 0000000..8c19d73
--- /dev/null
@@ -0,0 +1,48 @@
+/***************************************************************************
+ *   Copyright (C) 2005-07 by The Quassel IRC Development Team             *
+ *   devel@quassel-irc.org                                                 *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+
+#ifndef CORESETTINGS_H_
+#define CORESETTINGS_H_
+
+#include "settings.h"
+#include "global.h"
+
+class CoreSettings : public Settings {
+  Q_OBJECT
+  
+  public:
+    virtual ~CoreSettings();
+    CoreSettings();
+    
+    void setDatabaseSettings(const QVariant &data);
+    QVariant databaseSettings(const QVariant &def = QVariant());
+    
+    void setPort(const uint &port);
+    uint port(const uint &def = DEFAULT_PORT);
+        
+  private:
+    //virtual QStringList allSessionKeys() = 0;
+    virtual QStringList sessionKeys();
+    
+    virtual void setSessionValue(const QString &key, const QVariant &data);
+    virtual QVariant sessionValue(const QString &key, const QVariant &def = QVariant());
+};
+
+#endif /*CORESETTINGS_H_*/
index ffd2872..fcb0700 100644 (file)
 #include <QtSql>
 
 SqliteStorage::SqliteStorage() {
-  // TODO I don't think that this path is failsafe for windows users :) 
-  QString backlogFile = Global::quasselDir + "/quassel-storage.sqlite";
-  logDb = QSqlDatabase::addDatabase("QSQLITE");
-  logDb.setDatabaseName(backlogFile);
-  bool ok = logDb.open();
-
-  if(!ok) {
-    qWarning(tr("Could not open backlog database: %1").arg(logDb.lastError().text()).toAscii());
-    qWarning(tr("Disabling logging...").toAscii());
-    Q_ASSERT(ok);
-    return;
+  logMessageQuery = NULL;
+  addSenderQuery = NULL;
+  getLastMessageIdQuery = NULL;
+  requestMsgsQuery = NULL;
+  requestMsgsOffsetQuery = NULL;
+  requestMsgsSinceQuery = NULL;
+  requestMsgsSinceOffsetQuery = NULL;
+  requestMsgRangeQuery = NULL;
+  createNetworkQuery = NULL;
+  createBufferQuery = NULL;
+  getBufferInfoQuery = NULL;
+}
+
+SqliteStorage::~SqliteStorage() {
+  if (logMessageQuery) delete logMessageQuery;
+  if (addSenderQuery) delete addSenderQuery;
+  if (getLastMessageIdQuery) delete getLastMessageIdQuery;
+  if (requestMsgsQuery) delete requestMsgsQuery;
+  if (requestMsgsOffsetQuery) delete requestMsgsOffsetQuery;
+  if (requestMsgsSinceQuery) delete requestMsgsSinceQuery;
+  if (requestMsgsSinceOffsetQuery) delete requestMsgsSinceOffsetQuery;
+  if (requestMsgRangeQuery) delete requestMsgRangeQuery;
+  if (createNetworkQuery) delete createNetworkQuery;
+  if (createBufferQuery) delete createBufferQuery;
+  if (getBufferInfoQuery) delete getBufferInfoQuery;
+  
+  logDb.close();
+}
+
+bool SqliteStorage::isAvailable() {
+  if(!QSqlDatabase::isDriverAvailable("QSQLITE")) return false;
+  return true;
+}
+
+QString SqliteStorage::displayName() {
+  return QString("SQlite");
+}
+
+bool SqliteStorage::setup(const QVariantMap &settings) {
+  bool ok;
+  // this extra scope is needed to be able to remove the database connection later
+  {
+    logDb = QSqlDatabase::addDatabase("QSQLITE", "quassel_setup");
+    logDb.setDatabaseName(SqliteStorage::backlogFile(true));
+    bool ok = logDb.open();
+    
+    if (!ok) {
+      qWarning(tr("Could not open backlog database: %1").arg(logDb.lastError().text()).toAscii());
+    } else {
+      logDb.exec("CREATE TABLE quasseluser ("
+                    "userid INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
+                    "username TEXT UNIQUE NOT NULL,"
+                    "password BLOB NOT NULL)");
+         
+      logDb.exec("CREATE TABLE sender ("
+                    "senderid INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
+                    "sender TEXT UNIQUE NOT NULL)");
+         
+      logDb.exec("CREATE TABLE network ("
+                    "networkid INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
+                    "userid INTEGER NOT NULL,"
+                    "networkname TEXT NOT NULL,"
+                    "UNIQUE (userid, networkname))");
+         
+      logDb.exec("CREATE TABLE buffergroup ("
+                    "groupid INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
+                    "userid INTEGER NOT NULL,"
+                    "displayname TEXT)");
+         
+      logDb.exec("CREATE TABLE buffer ("
+                    "bufferid INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
+                    "userid INTEGER NOT NULL,"
+                    "groupid INTEGER,"
+                    "networkid INTEGER NOT NULL,"
+                    "buffername TEXT NOT NULL)");
+         
+      logDb.exec("CREATE UNIQUE INDEX buffer_idx "
+                    "ON buffer(userid, networkid, buffername)");
+           
+      logDb.exec("CREATE TABLE backlog ("
+                    "messageid INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
+                    "time INTEGER NOT NULL,"
+                    "bufferid INTEGER NOT NULL,"
+                    "type INTEGER NOT NULL,"
+                    "flags INTEGER NOT NULL,"
+                    "senderid INTEGER NOT NULL,"
+                    "message TEXT)");
+         
+      logDb.exec("CREATE TABLE coreinfo ("
+                    "updateid INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
+                    "version INTEGER NOT NULL)");
+         
+      logDb.exec("INSERT INTO coreinfo (version) VALUES (0)");
+      
+      // something fucked up -> no logging possible
+      // FIXME logDb.lastError is reset whenever exec is called
+      if(logDb.lastError().isValid()) { 
+        qWarning(tr("Could not create backlog table: %1").arg(logDb.lastError().text()).toAscii());
+        qWarning(tr("Disabling logging...").toAscii());
+        Q_ASSERT(false); // quassel does require logging
+        ok = false;
+      }
+    
+      logDb.close();
+    }
+  } 
+  
+  QSqlDatabase::removeDatabase("quassel_setup");
+  return ok;
+}
+
+bool SqliteStorage::init(const QVariantMap &settings) {
+  bool ok;
+  // i need the extra scope to be able to remove the database connection
+  {
+    logDb = QSqlDatabase::database("quassel_connection", false);
+    if (!logDb.isValid()) {
+      logDb = QSqlDatabase::addDatabase("QSQLITE", "quassel_connection");
+    }
+    logDb.setDatabaseName(SqliteStorage::backlogFile());
+    ok = logDb.open();
+    if (!ok) {
+      qWarning(tr("Could not open backlog database: %1").arg(logDb.lastError().text()).toAscii());
+    }
+  }
+
+  if (!ok) {
+    //QSqlDatabase::removeDatabase("quassel_connection");
+    return false;
   }
 
   // check if the db schema is up to date
@@ -43,7 +161,8 @@ SqliteStorage::SqliteStorage() {
     //checkVersion(query.value(0));
     qDebug() << "Sqlite is ready. Quassel Schema Version:" << query.value(0).toUInt();
   } else {
-    initDb();
+    qWarning("Sqlite is not ready!");
+    return false;
   }
 
   // we will need those pretty often... so let's speed things up:
@@ -105,93 +224,10 @@ SqliteStorage::SqliteStorage() {
                                 "WHERE (buffer.bufferid = :bufferid OR buffer.groupid = (SELECT groupid FROM buffer WHERE bufferid = :bufferid2)) AND "
                                 "backlog.messageid >= :firstmsg AND backlog.messageid <= :lastmsg "
                                 "ORDER BY messageid DESC ");
-
-}
-
-SqliteStorage::~SqliteStorage() {
-  //logDb.close();
-  delete logMessageQuery;
-  delete addSenderQuery;
-  delete getLastMessageIdQuery;
-  delete requestMsgsQuery;
-  delete requestMsgsOffsetQuery;
-  delete requestMsgsSinceQuery;
-  delete requestMsgsSinceOffsetQuery;
-  delete requestMsgRangeQuery;
-  delete createNetworkQuery;
-  delete createBufferQuery;
-  delete getBufferInfoQuery;
-  logDb.close();
-}
-
-
-void SqliteStorage::initDb() {
-  logDb.exec("CREATE TABLE quasseluser ("
-             "userid INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
-             "username TEXT UNIQUE NOT NULL,"
-             "password BLOB NOT NULL)");
-  
-  logDb.exec("CREATE TABLE sender ("
-             "senderid INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
-             "sender TEXT UNIQUE NOT NULL)");
   
-  logDb.exec("CREATE TABLE network ("
-             "networkid INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
-             "userid INTEGER NOT NULL,"
-             "networkname TEXT NOT NULL,"
-             "UNIQUE (userid, networkname))");
-  
-  logDb.exec("CREATE TABLE buffergroup ("
-             "groupid INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
-             "userid INTEGER NOT NULL,"
-             "displayname TEXT)");
-  
-  logDb.exec("CREATE TABLE buffer ("
-             "bufferid INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
-             "userid INTEGER NOT NULL,"
-             "groupid INTEGER,"
-             "networkid INTEGER NOT NULL,"
-             "buffername TEXT NOT NULL)");
-  
-  logDb.exec("CREATE UNIQUE INDEX buffer_idx "
-             "ON buffer(userid, networkid, buffername)");
-    
-  logDb.exec("CREATE TABLE backlog ("
-             "messageid INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
-             "time INTEGER NOT NULL,"
-             "bufferid INTEGER NOT NULL,"
-             "type INTEGER NOT NULL,"
-             "flags INTEGER NOT NULL,"
-             "senderid INTEGER NOT NULL,"
-             "message TEXT)");
-  
-  logDb.exec("CREATE TABLE coreinfo ("
-             "updateid INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
-             "version INTEGER NOT NULL)");
-  
-  logDb.exec("INSERT INTO coreinfo (version) VALUES (0)");
-
-
-  // something fucked up -> no logging possible
-  // FIXME logDb.lastError is reset whenever exec is called
-  if(logDb.lastError().isValid()) { 
-    qWarning(tr("Could not create backlog table: %1").arg(logDb.lastError().text()).toAscii());
-    qWarning(tr("Disabling logging...").toAscii());
-    Q_ASSERT(false); // quassel does require logging
-  }
-
-  addUser("Default", "password");
-}
-
-bool SqliteStorage::isAvailable() {
-  if(!QSqlDatabase::isDriverAvailable("QSQLITE")) return false;
   return true;
 }
 
-QString SqliteStorage::displayName() {
-  return QString("SqliteStorage");
-}
-
 UserId SqliteStorage::addUser(const QString &user, const QString &password) {
   QByteArray cryptopass = QCryptographicHash::hash(password.toUtf8(), QCryptographicHash::Sha1);
   cryptopass = cryptopass.toHex();
@@ -483,36 +519,24 @@ QList<Message> SqliteStorage::requestMsgRange(BufferInfo buffer, int first, int
   return messagelist;
 }
 
-void SqliteStorage::importOldBacklog() {
-  QSqlQuery query(logDb);
-  int user;
-  query.prepare("SELECT MIN(userid) FROM quasseluser");
-  query.exec();
-  if(!query.first()) {
-    qDebug() << "create a user first!";
-  } else {
-    user = query.value(0).toUInt();
+QString SqliteStorage::backlogFile(bool createPath) {
+  // kinda ugly, but I currently see no other way to do that
+#ifdef _WINDOWS
+  QString quasselDir = QDir::homePath() + qgetenv("APPDATA") + "\\quassel\\";
+#else
+  QString quasselDir = QDir::homePath() + "/.quassel/";
+#endif
+  
+  if (createPath) {
+    QDir *qDir = new QDir(quasselDir);
+    if (!qDir->exists(quasselDir)) {
+      qDir->mkpath(quasselDir);
+    }
+    delete qDir;
   }
-  query.prepare("DELETE FROM backlog WHERE bufferid IN (SELECT DISTINCT bufferid FROM buffer WHERE userid = :userid");
-  query.bindValue(":userid", user);
-  query.exec();
-  query.prepare("DELETE FROM buffer WHERE userid = :userid");
-  query.bindValue(":userid", user);
-  query.exec();
-  query.prepare("DELETE FROM buffergroup WHERE userid = :userid");
-  query.bindValue(":userid", user);
-  query.exec();
-  query.prepare("DELETE FROM network WHERE userid = :userid");
-  query.bindValue(":userid", user);
-  query.exec();
-  logDb.commit();
-  qDebug() << "All userdata has been deleted";
-  qDebug() << "importing old backlog files...";
-  initBackLogOld(user);
-  logDb.commit();
-  return;
-}
 
+  return quasselDir + "quassel-storage.sqlite";
+}
 
 bool SqliteStorage::watchQuery(QSqlQuery *query) {
   if(query->lastError().isValid()) {
index 74efe5a..ca56cab 100644 (file)
@@ -34,12 +34,12 @@ class SqliteStorage : public Storage {
     SqliteStorage();
     virtual ~SqliteStorage();
 
-    static void init();
-
     /* General */
 
     static bool isAvailable();
     static QString displayName();
+    virtual bool setup(const QVariantMap &settings = QVariantMap());
+    virtual bool init(const QVariantMap &settings = QVariantMap());
 
     // TODO: Add functions for configuring the backlog handling, i.e. defining auto-cleanup settings etc
 
@@ -65,23 +65,19 @@ class SqliteStorage : public Storage {
     virtual QList<Message> requestMsgs(BufferInfo buffer, QDateTime since, int offset = -1);
     virtual QList<Message> requestMsgRange(BufferInfo buffer, int first, int last);
 
-  public slots:
-    //! This is just for importing the old file-based backlog */
-    /** This slot needs to be implemented in the storage backends.
-     *  It should first prepare (delete?) the database, then call initBackLogOld(UserId id).
-     *  If the importing was successful, backLogEnabledOld will be true afterwards.
-     */
-    void importOldBacklog();
-
   signals:
     void bufferInfoUpdated(BufferInfo);
 
   protected:
 
   private:
-    void initDb();
+    static QString backlogFile(bool createPath = false);
+    
     void createBuffer(UserId user, const QString &network, const QString &buffer);
     bool watchQuery(QSqlQuery *query);
+
+    QSqlDatabase logDb;
+
     QSqlQuery *logMessageQuery;
     QSqlQuery *addSenderQuery;
     QSqlQuery *getLastMessageIdQuery;
@@ -95,5 +91,4 @@ class SqliteStorage : public Storage {
     QSqlQuery *getBufferInfoQuery;
 };
 
-
 #endif
index e7dcea5..4df7402 100644 (file)
  ***************************************************************************/
 
 #include "storage.h"
-
-
-// OBSOLETE
-// This is kept here for importing the old file-based backlog.
-
-/* This is a sample!
-
-void Storage::importOldBacklog() {
-  qDebug() << "Deleting backlog database...";
-  logDb.exec(QString("DELETE FROM 'Backlog$%1$' WHERE SenderId != '$VERSION$'").arg(user));
-  logDb.exec(QString("DELETE FROM 'Senders$%1$'").arg(user));
-  logDb.exec(QString("DELETE FROM 'Buffers$%1$'").arg(user));
-  nextMsgId = 1; nextBufferInfo = 1; nextSenderId = 1;
-  qDebug() << "Importing old backlog files...";
-  initBackLogOld();
-  if(!backLogEnabledOld) return;
-  logDb.exec("VACUUM");
-  qDebug() << "Backlog successfully imported, you have to restart Quassel now!";
-  exit(0);
-
-}
-*/
-
-// file name scheme: quassel-backlog-2006-29-10.bin
-void Storage::initBackLogOld(UserId uid) {
-  backLogDir = QDir(Global::quasselDir + "/backlog");
-  if(!backLogDir.exists()) {
-    qWarning(QString("Creating backlog directory \"%1\"...").arg(backLogDir.absolutePath()).toAscii());
-    if(!backLogDir.mkpath(backLogDir.absolutePath())) {
-      qWarning(QString("Could not create backlog directory! Disabling logging...").toAscii());
-      backLogEnabledOld = false;
-      return;
-    }
-  }
-  backLogDir.refresh();
-  //if(!backLogDir.isReadable()) {
-  //  qWarning(QString("Cannot read directory \"%1\". Disabling logging...").arg(backLogDir.absolutePath()).toAscii());
-  //  backLogEnabled = false;
-  //  return;
-  //}
-  QStringList networks = backLogDir.entryList(QDir::Dirs|QDir::NoDotAndDotDot|QDir::Readable, QDir::Name);
-  foreach(QString net, networks) {
-    QDir dir(backLogDir.absolutePath() + "/" + net);
-    if(!dir.exists()) {
-      qWarning(QString("Could not change to directory \"%1\"!").arg(dir.absolutePath()).toAscii());
-      continue;
-    }
-    QStringList logs = dir.entryList(QStringList("quassel-backlog-*.bin"), QDir::Files|QDir::Readable, QDir::Name);
-    foreach(QString name, logs) {
-      QFile f(dir.absolutePath() + "/" + name);
-      if(!f.open(QIODevice::ReadOnly)) {
-        qWarning(QString("Could not open \"%1\" for reading!").arg(f.fileName()).toAscii());
-        continue;
-      }
-      QDataStream in(&f);
-      in.setVersion(QDataStream::Qt_4_2);
-      QByteArray verstring; quint8 vernum; in >> verstring >> vernum;
-      if(verstring != BACKLOG_STRING) {
-        qWarning(QString("\"%1\" is not a Quassel backlog file!").arg(f.fileName()).toAscii());
-        f.close(); continue;
-      }
-      if(vernum != BACKLOG_FORMAT) {
-        qWarning(QString("\"%1\": Version mismatch!").arg(f.fileName()).toAscii());
-        f.close(); continue;
-      }
-      qDebug() << "Reading backlog from" << f.fileName();
-      logFileDates[net] = QDate::fromString(f.fileName(),
-                                            QString("'%1/quassel-backlog-'yyyy-MM-dd'.bin'").arg(dir.absolutePath()));
-      if(!logFileDates[net].isValid()) {
-        qWarning(QString("\"%1\" has an invalid file name!").arg(f.fileName()).toAscii());
-      }
-      while(!in.atEnd()) {
-        quint8 t, f;
-        quint32 ts;
-        QByteArray s, m, targ;
-        in >> ts >> t >> f >> targ >> s >> m;
-        QString target = QString::fromUtf8(targ);
-        QString sender = QString::fromUtf8(s);
-        QString text = QString::fromUtf8(m);
-        BufferInfo id;
-        if((f & Message::PrivMsg) && !(f & Message::Self)) {
-          id = getBufferInfo(uid, net, sender);
-        } else {
-          id = getBufferInfo(uid, net, target);
-        }
-        Message msg(QDateTime::fromTime_t(ts), id, (Message::Type)t, text, sender, f);
-        //backLog[net].append(m);
-        logMessage(msg);
-      }
-      f.close();
-    }
-  }
-  backLogEnabledOld = true;
-}
-
-
index f493721..f98b75b 100644 (file)
@@ -33,16 +33,6 @@ class Storage : public QObject {
     Storage() {};
     virtual ~Storage() {};
 
-    //! Initialize the static parts of the storage class
-    /** This is called by the core before any other method of the storage backend is used.
-     *  This should be used to perform any static initialization that might be necessary.
-     *  DO NOT use this for creating database connection or similar stuff, since init() might be
-     *  called even if the storage backend is never be actually used (because no user selected it).
-     *  For anything like this, the constructor (which is called if and when we actually create an instance
-     *  of the storage backend) is the right place.
-     */
-    static void init() {};
-
     /* General */
 
     //! Check if the storage type is available.
@@ -56,6 +46,19 @@ class Storage : public QObject {
     /** \return A string that can be used by the GUI to describe the storage backend */
     static QString displayName() { return ""; }
 
+    //! Setup the storage provider.
+    /** This prepares the storage provider (e.g. create tables, etc.) for use within Quassel.
+     *  \param settings   Hostname, port, username, password, ...
+     *  \return True if and only if the storage provider was initialized successfully.
+     */
+    virtual bool setup(const QVariantMap &settings = QVariantMap()) { return false; }
+    
+    //! Initialize the storage provider
+    /** \param settings   Hostname, port, username, password, ...  
+     *  \return True if and only if the storage provider was initialized successfully.
+     */
+    virtual bool init(const QVariantMap &settings = QVariantMap()) = 0;
+    
     // TODO: Add functions for configuring the backlog handling, i.e. defining auto-cleanup settings etc
 
     /* User handling */
@@ -152,14 +155,6 @@ class Storage : public QObject {
      */
     virtual QList<Message> requestMsgRange(BufferInfo buffer, int first, int last) = 0;
 
-  public slots:
-    //! This is just for importing the old file-based backlog */
-    /** This slot needs to be implemented in the storage backends.
-     *  It should first prepare (delete?) the database, then call initBackLogOld(UserId id).
-     *  If the importing was successful, backLogEnabledOld will be true afterwards.
-     */
-    virtual void importOldBacklog() = 0;
-
   signals:
     //! Sent when a new BufferInfo is created, or an existing one changed somehow.
     void bufferInfoUpdated(BufferInfo);
@@ -173,21 +168,6 @@ class Storage : public QObject {
   public:
     /* Exceptions */
     struct AuthError : public Exception {};
-
-  protected:
-    // Old stuff, just for importing old file-based data
-    void initBackLogOld(UserId id);
-
-    QSqlDatabase logDb; // FIXME this does not belong in the base class!
-      
-    bool backLogEnabledOld;
-    QDir backLogDir;
-    QHash<QString, QList<Message> > backLog;
-    QHash<QString, QFile *> logFiles;
-    QHash<QString, QDataStream *> logStreams;
-    QHash<QString, QDate> logFileDates;
-    QHash<QString, QDir> logFileDirs;
-
 };
 
 
diff --git a/src/qtui/configwizard.cpp b/src/qtui/configwizard.cpp
new file mode 100644 (file)
index 0000000..6dc444f
--- /dev/null
@@ -0,0 +1,202 @@
+/***************************************************************************
+ *   Copyright (C) 2005-07 by The Quassel Team                             *
+ *   devel@quassel-irc.org                                                 *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+
+#include <QtGui>
+
+#include "configwizard.h"
+
+ConfigWizard::ConfigWizard(const QStringList &storageProviders, QWidget *parent) : QWizard(parent) {
+  setPage(Page_Intro, new IntroPage());
+  setPage(Page_AdminUser, new AdminUserPage());
+  setPage(Page_StorageSelection, new StorageSelectionPage(storageProviders));
+  setPage(Page_StorageDetails, new StorageDetailsPage());
+  setPage(Page_Conclusion, new ConclusionPage(storageProviders));
+  
+  setStartId(Page_Intro);
+
+#ifndef Q_WS_MAC
+  setWizardStyle(ModernStyle);
+#endif
+  setOption(HaveHelpButton, false);
+  setOption(NoBackButtonOnStartPage, true);
+  setOption(HaveNextButtonOnLastPage, false);
+  setOption(HaveFinishButtonOnEarlyPages, false);
+  setOption(NoCancelButton, true);
+  
+  setWindowTitle(tr("Core Configuration Wizard"));
+}
+
+
+IntroPage::IntroPage(QWidget *parent) : QWizardPage(parent) {
+  setTitle(tr("Introduction"));
+  
+  label = new QLabel(tr("This wizard will guide you through the setup process for your shiny new Quassel IRC Client."));
+  label->setWordWrap(true);
+  
+  QVBoxLayout *layout = new QVBoxLayout();
+  layout->addWidget(label);
+  setLayout(layout);
+}
+
+int IntroPage::nextId() const {
+  return ConfigWizard::Page_AdminUser;
+}
+
+
+AdminUserPage::AdminUserPage(QWidget *parent) : QWizardPage(parent) {
+  setTitle(tr("Setup Admin User"));
+  setSubTitle(tr("Please enter credentials for the admin user."));
+  
+  nameLabel = new QLabel(tr("Name:"));
+  nameEdit = new QLineEdit();
+  nameLabel->setBuddy(nameEdit);
+  
+  passwordLabel = new QLabel(tr("Password:"));
+  passwordEdit = new QLineEdit();
+  passwordEdit->setEchoMode(QLineEdit::Password);
+  passwordLabel->setBuddy(passwordLabel);
+  
+  registerField("adminuser.name*", nameEdit);
+  registerField("adminuser.password*", passwordEdit);
+  
+  QGridLayout *layout = new QGridLayout();
+  layout->addWidget(nameLabel, 0, 0);
+  layout->addWidget(nameEdit, 0, 1);
+  layout->addWidget(passwordLabel, 1, 0);
+  layout->addWidget(passwordEdit, 1, 1);
+  setLayout(layout);
+}
+
+int AdminUserPage::nextId() const {
+  return ConfigWizard::Page_StorageSelection;
+}
+
+
+StorageSelectionPage::StorageSelectionPage(const QStringList &storageProviders, QWidget *parent) : QWizardPage(parent) {
+  setTitle(tr("Select Storage Provider"));
+  setSubTitle(tr("Please select the storage provider you want to use."));
+  
+  storageSelection = new QComboBox();
+  storageSelection->addItems(storageProviders);
+  
+  registerField("storage.provider", storageSelection);
+  
+  QVBoxLayout *layout = new QVBoxLayout();
+  layout->addWidget(storageSelection);
+  setLayout(layout);
+}
+
+int StorageSelectionPage::nextId() const {
+  QString selection = storageSelection->currentText();
+  if (!selection.compare("Sqlite", Qt::CaseInsensitive)) {
+    return ConfigWizard::Page_Conclusion;
+  } else {
+    return ConfigWizard::Page_StorageDetails;
+  }
+}
+
+
+StorageDetailsPage::StorageDetailsPage(QWidget *parent) : QWizardPage(parent) {
+  setTitle(tr("Setup Storage Provider"));
+  setSubTitle(tr("Please enter credentials for the selected storage provider."));
+  
+  hostLabel = new QLabel(tr("Host:"));
+  hostEdit = new QLineEdit();
+  hostLabel->setBuddy(hostEdit);
+
+  portLabel = new QLabel(tr("Port:"));
+  portEdit = new QLineEdit();
+  QIntValidator *portValidator = new QIntValidator(0, 65535, this);
+  portEdit->setValidator(portValidator);
+  portLabel->setBuddy(portEdit);
+  
+  databaseLabel = new QLabel(tr("Database:"));
+  databaseEdit = new QLineEdit();
+  databaseLabel->setBuddy(databaseEdit);
+  
+  userLabel = new QLabel(tr("User:"));
+  userEdit = new QLineEdit();
+  userLabel->setBuddy(userEdit);
+  
+  passwordLabel = new QLabel(tr("Password:"));
+  passwordEdit = new QLineEdit();
+  passwordEdit->setEchoMode(QLineEdit::Password);
+  passwordLabel->setBuddy(passwordLabel);
+  
+  registerField("storage.host*", hostEdit);
+  registerField("storage.port*", portEdit);
+  registerField("storage.database*", databaseEdit);
+  registerField("storage.user*", userEdit);
+  registerField("storage.password*", passwordEdit);
+  
+  QGridLayout *layout = new QGridLayout();
+  layout->addWidget(hostLabel, 0, 0);
+  layout->addWidget(hostEdit, 0, 1);
+  layout->addWidget(portLabel, 1, 0);
+  layout->addWidget(portEdit, 1, 1);
+  layout->addWidget(databaseLabel, 2, 0);
+  layout->addWidget(databaseEdit, 2, 1);
+  layout->addWidget(userLabel, 3, 0);
+  layout->addWidget(userEdit, 3, 1);
+  layout->addWidget(passwordLabel, 4, 0);
+  layout->addWidget(passwordEdit, 4, 1);
+  setLayout(layout);
+}
+
+int StorageDetailsPage::nextId() const {
+  return ConfigWizard::Page_Conclusion;
+}
+
+
+ConclusionPage::ConclusionPage(const QStringList &storageProviders, QWidget *parent) : QWizardPage(parent) {
+  setTitle(tr("Conclusion"));
+  setSubTitle(tr("You chose the following configuration:"));
+  
+  this->storageProviders = storageProviders;
+  
+  adminuser = new QLabel();
+  storage = new QLabel();
+  storage->setWordWrap(true);
+  
+  QVBoxLayout *layout = new QVBoxLayout();
+  layout->addWidget(adminuser);
+  layout->addWidget(storage);
+  setLayout(layout);
+}
+
+int ConclusionPage::nextId() const {
+  return -1;
+}
+
+void ConclusionPage::initializePage() {
+  QString adminuserText = "Admin User: " + field("adminuser.name").toString();
+  adminuser->setText(adminuserText);
+  
+  QString storageText = "Selected Storage Provider: ";
+  QString sp = storageProviders.value(field("storage.provider").toInt());
+  if (!sp.compare("Sqlite", Qt::CaseInsensitive)) {
+    storageText.append(sp);
+  } else {
+    storageText += sp + "\nHost: " + field("storage.host").toString() + "\nPort: " + field("storage.port").toString() + "\nDatabase: " + field("storage.database").toString() + "\nUser: " + field("storage.user").toString();
+  }
+  storage->setText(storageText);
+}
+
diff --git a/src/qtui/configwizard.h b/src/qtui/configwizard.h
new file mode 100644 (file)
index 0000000..c6e83c9
--- /dev/null
@@ -0,0 +1,120 @@
+/***************************************************************************
+ *   Copyright (C) 2005-07 by The Quassel Team                             *
+ *   devel@quassel-irc.org                                                 *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+
+#ifndef CONFIGWIZARD_H_
+#define CONFIGWIZARD_H_
+
+#include <QWizard>
+
+class QLabel;
+class QLineEdit;
+class QComboBox;
+
+class ConfigWizard : public QWizard {
+  Q_OBJECT
+  
+  public:
+    enum {
+      Page_Intro,
+      Page_AdminUser,
+      Page_StorageSelection,
+      Page_StorageDetails,
+      Page_Conclusion
+    };
+    
+    ConfigWizard(const QStringList &storageProviders, QWidget *parent = NULL);
+};
+
+class IntroPage : public QWizardPage {
+  Q_OBJECT
+  
+  public:
+    IntroPage(QWidget *parent = NULL);
+    
+    int nextId() const;
+    
+  private:
+    QLabel *label;
+};
+
+class AdminUserPage : public QWizardPage {
+  Q_OBJECT
+  
+  public:
+    AdminUserPage(QWidget *parent = NULL);
+    
+    int nextId() const;
+    
+  private:
+    QLabel *nameLabel;
+    QLineEdit *nameEdit;
+    QLabel *passwordLabel;
+    QLineEdit *passwordEdit;
+};
+
+class StorageSelectionPage : public QWizardPage {
+  Q_OBJECT
+  
+  public:
+    StorageSelectionPage(const QStringList &storageProviders, QWidget *parent = NULL);
+    
+    int nextId() const;
+    
+  private:
+    QComboBox *storageSelection;
+};
+
+class StorageDetailsPage : public QWizardPage {
+  Q_OBJECT
+  
+  public:
+    StorageDetailsPage(QWidget *parent = NULL);
+    
+    int nextId() const;
+    
+  private:
+    QLabel *hostLabel;
+    QLineEdit *hostEdit;
+    QLabel *portLabel;
+    QLineEdit *portEdit;
+    QLabel *databaseLabel;
+    QLineEdit *databaseEdit;
+    QLabel *userLabel;
+    QLineEdit *userEdit;
+    QLabel *passwordLabel;
+    QLineEdit *passwordEdit;
+};
+
+class ConclusionPage : public QWizardPage {
+  Q_OBJECT
+  
+  public:
+    ConclusionPage(const QStringList &storageProviders, QWidget *parent = NULL);
+    
+    void initializePage();
+    int nextId() const;
+    
+  private:
+    QLabel *adminuser;
+    QLabel *storage;
+    QStringList storageProviders;
+};
+
+#endif /*CONFIGWIZARD_H_*/
index d2c8d06..2f51fdd 100644 (file)
@@ -23,6 +23,7 @@
 #include "global.h"
 #include "client.h"
 #include "clientsettings.h"
+#include "configwizard.h"
 
 CoreConnectDlg::CoreConnectDlg(QWidget *parent, bool /*doAutoConnect*/) : QDialog(parent) {
   ui.setupUi(this); //qDebug() << "new dlg";
@@ -54,6 +55,8 @@ CoreConnectDlg::CoreConnectDlg(QWidget *parent, bool /*doAutoConnect*/) : QDialo
   connect(Client::instance(), SIGNAL(coreConnectionProgress(uint, uint)), this, SLOT(updateProgressBar(uint, uint)));
   connect(Client::instance(), SIGNAL(coreConnectionError(QString)), this, SLOT(coreConnectionError(QString)));
   connect(Client::instance(), SIGNAL(connected()), this, SLOT(coreConnected()));
+  
+  connect(Client::instance(), SIGNAL(showConfigWizard(const QVariantMap &)), this, SLOT(showConfigWizard(const QVariantMap &)));
 
   AccountSettings s;
   ui.accountList->addItems(s.knownAccounts());
@@ -310,3 +313,24 @@ void CoreConnectDlg::recvCoreState(QVariant state) {
 QVariant CoreConnectDlg::getCoreState() {
   return coreState;
 }
+
+void CoreConnectDlg::showConfigWizard(const QVariantMap &coredata) {
+  QStringList storageProviders = coredata["StorageProviders"].toStringList();
+  ConfigWizard *wizard = new ConfigWizard(storageProviders, this);
+  wizard->exec();
+  QVariantMap reply;
+  reply["GuiProtocol"] = GUI_PROTOCOL;
+  reply["HasSettings"] = true;
+  reply["User"] = wizard->field("adminuser.name").toString();
+  reply["Password"] = wizard->field("adminuser.password").toString();
+  QString sp = storageProviders.value(wizard->field("storage.provider").toInt());
+  reply["Type"] = sp;
+  if (sp.compare("Sqlite", Qt::CaseInsensitive)) {
+    reply["Host"] = wizard->field("storage.host").toString();
+    reply["Port"] = wizard->field("storage.port").toString();
+    reply["Database"] = wizard->field("storage.database").toString();
+    reply["User"] = wizard->field("storage.user").toString();
+    reply["Password"] = wizard->field("storage.password").toString();
+  }
+  Client::instance()->setCoreConfiguration(reply);
+}
index 9f988a3..3d8574f 100644 (file)
@@ -33,7 +33,7 @@ class CoreConnectDlg: public QDialog {
     QVariant getCoreState();
 
     bool willDoInternalAutoConnect();
-
+    
   public slots:
     void doAutoConnect();
 
@@ -54,6 +54,8 @@ class CoreConnectDlg: public QDialog {
     //void coreConnectionProgress(uint partial, uint total);
     void updateProgressBar(uint partial, uint total);
     void recvCoreState(QVariant);
+    
+    void showConfigWizard(const QVariantMap &coredata);
 
   private:
     Ui::CoreConnectDlg ui;
index 73cfc07..48c9075 100644 (file)
@@ -2,13 +2,12 @@ DEPMOD = uisupport common client
 QT_MOD = core gui network
 
 SRCS += bufferview.cpp bufferviewfilter.cpp bufferwidget.cpp channelwidgetinput.cpp chatline-old.cpp \
-        chatwidget.cpp coreconnectdlg.cpp \
-        guisettings.cpp identities.cpp mainwin.cpp qtui.cpp qtuistyle.cpp serverlist.cpp settingsdlg.cpp tabcompleter.cpp topicwidget.cpp
+       chatwidget.cpp coreconnectdlg.cpp configwizard.cpp \
+       guisettings.cpp identities.cpp mainwin.cpp qtui.cpp qtuistyle.cpp serverlist.cpp settingsdlg.cpp tabcompleter.cpp topicwidget.cpp
 
-HDRS += bufferview.h bufferviewfilter.h bufferwidget.h channelwidgetinput.h chatline-old.h chatwidget.h \
+HDRS += bufferview.h bufferviewfilter.h bufferwidget.h channelwidgetinput.h chatline-old.h chatwidget.h configwizard.h \
         coreconnectdlg.h guisettings.h identities.h mainwin.h qtui.h qtuistyle.h serverlist.h settingsdlg.h settingspage.h tabcompleter.h topicwidget.h
 
-
 FORMNAMES = identitiesdlg.ui identitieseditdlg.ui networkeditdlg.ui mainwin.ui nickeditdlg.ui serverlistdlg.ui \
             servereditdlg.ui coreconnectdlg.ui bufferviewwidget.ui bufferwidget.ui settingsdlg.ui \
             buffermgmtpage.ui connectionpage.ui usermgmtpage.ui topicwidget.ui