This is the long-awaited monster commit, bringing you a redesigned core arch and...
authorManuel Nickschas <sputnick@quassel-irc.org>
Thu, 17 Jan 2008 22:36:12 +0000 (22:36 +0000)
committerManuel Nickschas <sputnick@quassel-irc.org>
Thu, 17 Jan 2008 22:36:12 +0000 (22:36 +0000)
NOT STABLE! DO NOT USE! WORK IN PROGRESS! NOT CLEANED UP! NOT TESTED! YOU HAVE BEEN WARNED!

Known regressions:
* Networks always use the Default Identity from the _new_ dialog (accessible via the new SettingsDlg)
* No core config wizard. Will be back soon.
* No session save/restore, Will be back soon.
* Some more things, that you'll notice anyway.

50 files changed:
Quassel.kdevelop.filelist
build/targets/target.pri
src/client/client.cpp
src/client/client.h
src/client/client.pri
src/client/clientsettings.cpp
src/client/clientsettings.h
src/client/clientsyncer.cpp [new file with mode: 0644]
src/client/clientsyncer.h [new file with mode: 0644]
src/client/networkmodel.cpp
src/client/networkmodel.h
src/common/global.cpp
src/common/global.h
src/common/identity.cpp
src/common/identity.h
src/common/ircchannel.cpp
src/common/ircchannel.h
src/common/ircuser.cpp
src/common/ircuser.h
src/common/main.cpp
src/common/network.cpp
src/common/network.h
src/common/signalproxy.cpp
src/common/signalproxy.h
src/common/syncableobject.cpp
src/common/syncableobject.h
src/common/util.h
src/core/core.cpp
src/core/core.h
src/core/core.pri
src/core/coresession.cpp
src/core/coresession.h
src/core/ircserverhandler.h
src/core/networkconnection.cpp
src/core/networkconnection.h
src/core/sessionthread.cpp [new file with mode: 0644]
src/core/sessionthread.h [new file with mode: 0644]
src/core/sqlitestorage.cpp
src/core/sqlitestorage.h
src/core/storage.h
src/icons/icons.qrc
src/qtui/chatline-old.cpp
src/qtui/coreconnectdlg.cpp
src/qtui/coreconnectdlg.h
src/qtui/mainwin.cpp
src/qtui/qtui.pri
src/qtui/ui/coreaccounteditdlg.ui [new file with mode: 0644]
src/qtui/ui/coreconnectdlg.ui
src/qtui/ui/serverlistdlg.ui
version.inc [new file with mode: 0644]

index a43f888..fe1d9fa 100644 (file)
@@ -36,6 +36,8 @@ src/client/client.h
 src/client/client.pri
 src/client/clientsettings.cpp
 src/client/clientsettings.h
+src/client/clientsyncer.cpp
+src/client/clientsyncer.h
 src/client/mappedselectionmodel.cpp
 src/client/mappedselectionmodel.h
 src/client/modelpropertymapper.cpp
@@ -68,8 +70,6 @@ src/common/message.cpp
 src/common/message.h
 src/common/network.cpp
 src/common/network.h
-src/common/networkinfo.cpp
-src/common/networkinfo.h
 src/common/settings.cpp
 src/common/settings.h
 src/common/signalproxy.cpp
@@ -99,8 +99,8 @@ src/core/ircserverhandler.cpp
 src/core/ircserverhandler.h
 src/core/networkconnection.cpp
 src/core/networkconnection.h
-src/core/server.cpp
-src/core/server.h
+src/core/sessionthread.cpp
+src/core/sessionthread.h
 src/core/sqlitestorage.cpp
 src/core/sqlitestorage.h
 src/core/storage.cpp
@@ -188,7 +188,6 @@ src/qtui/settingspages/identitiessettingspage.cpp
 src/qtui/settingspages/identitiessettingspage.h
 src/qtui/settingspages/identitiessettingspage.ui
 src/qtui/settingspages/networkssettingspage.ui
-src/qtui/settingspages/nickeditdlg.ui
 src/qtui/settingspages/nickeditdlgnew.ui
 src/qtui/settingspages/saveidentitiesdlg.ui
 src/qtui/settingspages/servereditdlg.ui
index 1441f63..1f023b2 100644 (file)
@@ -15,6 +15,7 @@ for(mod, MODULES) {
   LIBS *= -L../modules/$$dirname(mod) -l$$basename(mod)
   PRE_TARGETDEPS *= ../modules/$$mod
 }
+PRE_TARGETDEPS *= ../../version.inc
 
 #CONTRIB += libqxt  # not needed
 #include(../contrib/contrib.pri)
index 1bf0759..34c903e 100644 (file)
@@ -45,7 +45,8 @@ Client *Client::instance() {
 }
 
 void Client::destroy() {
-  delete instanceptr;
+  //delete instanceptr;
+  instanceptr->deleteLater();
 }
 
 void Client::init(AbstractUi *ui) {
@@ -61,15 +62,16 @@ Client::Client(QObject *parent)
     _networkModel(0),
     _bufferModel(0),
     _nickModel(0),
-    connectedToCore(false)
+    _connectedToCore(false),
+    _syncedToCore(false)
 {
 }
 
 Client::~Client() {
+  disconnectFromCore();
 }
 
 void Client::init() {
-  blockSize = 0;
 
   _networkModel = new NetworkModel(this);
   connect(this, SIGNAL(bufferUpdated(BufferInfo)),
@@ -77,18 +79,16 @@ void Client::init() {
 
   _bufferModel = new BufferModel(_networkModel);
   _nickModel = new NickModel(_networkModel);
-  
+
   SignalProxy *p = signalProxy();
   p->attachSignal(this, SIGNAL(sendSessionData(const QString &, const QVariant &)),
                   SIGNAL(clientSessionDataChanged(const QString &, const QVariant &)));
   p->attachSlot(SIGNAL(coreSessionDataChanged(const QString &, const QVariant &)),
                 this, SLOT(recvSessionData(const QString &, const QVariant &)));
-  p->attachSlot(SIGNAL(coreState(const QVariant &)),
-                this, SLOT(recvCoreState(const QVariant &)));
-  p->attachSlot(SIGNAL(networkConnected(uint)),
-                this, SLOT(networkConnected(uint)));
-  p->attachSlot(SIGNAL(networkDisconnected(uint)),
-                this, SLOT(networkDisconnected(uint)));
+  //p->attachSlot(SIGNAL(networkConnected(uint)),
+  //FIXME              this, SLOT(networkConnected(uint)));
+  //p->attachSlot(SIGNAL(networkDisconnected(uint)),
+  //FIXME              this, SLOT(networkDisconnected(uint)));
   p->attachSlot(SIGNAL(displayMsg(const Message &)),
                 this, SLOT(recvMessage(const Message &)));
   p->attachSlot(SIGNAL(displayStatusMsg(QString, QString)),
@@ -106,7 +106,9 @@ void Client::init() {
   p->attachSlot(SIGNAL(identityCreated(const Identity &)), this, SLOT(coreIdentityCreated(const Identity &)));
   p->attachSlot(SIGNAL(identityRemoved(IdentityId)), this, SLOT(coreIdentityRemoved(IdentityId)));
 
-  connect(mainUi, SIGNAL(connectToCore(const QVariantMap &)), this, SLOT(connectToCore(const QVariantMap &)));
+  connect(p, SIGNAL(disconnected()), this, SLOT(disconnectFromCore()));
+
+  //connect(mainUi, SIGNAL(connectToCore(const QVariantMap &)), this, SLOT(connectToCore(const QVariantMap &)));
   connect(mainUi, SIGNAL(disconnectFromCore()), this, SLOT(disconnectFromCore()));
   connect(this, SIGNAL(connected()), mainUi, SLOT(connectedToCore()));
   connect(this, SIGNAL(disconnected()), mainUi, SLOT(disconnectedFromCore()));
@@ -122,12 +124,12 @@ void Client::init() {
 
 
 QList<Network *> Client::networks() {
-  return instance()->_network.values();
+  return instance()->_networks.values();
 }
 
 Network *Client::network(uint networkid) {
-  if(instance()->_network.contains(networkid))
-    return instance()->_network[networkid];
+  if(instance()->_networks.contains(networkid))
+    return instance()->_networks[networkid];
   else
     return 0;
 }
@@ -144,13 +146,16 @@ QList<Buffer *> Client::buffers() {
   return instance()->_buffers.values();
 }
 
-Buffer *Client::buffer(uint bufferUid) {
+
+// FIXME remove
+Buffer *Client::buffer(BufferId bufferUid) {
   if(instance()->_buffers.contains(bufferUid))
     return instance()->_buffers[bufferUid];
   else
     return 0;
 }
 
+// FIXME remove
 Buffer *Client::buffer(BufferInfo id) {
   Buffer *buff = buffer(id.uid());
 
@@ -169,6 +174,7 @@ Buffer *Client::buffer(BufferInfo id) {
   return buff;
 }
 
+
 NetworkModel *Client::networkModel() {
   return instance()->_networkModel;
 }
@@ -186,6 +192,13 @@ SignalProxy *Client::signalProxy() {
   return instance()->_signalProxy;
 }
 
+bool Client::isConnected() {
+  return instance()->_connectedToCore;
+}
+
+bool Client::isSynced() {
+  return instance()->_syncedToCore;
+}
 
 /*** Identity handling ***/
 
@@ -198,7 +211,6 @@ const Identity * Client::identity(IdentityId id) {
   else return 0;
 }
 
-
 void Client::createIdentity(const Identity &id) {
   emit instance()->requestCreateIdentity(id);
 }
@@ -233,11 +245,6 @@ void Client::coreIdentityRemoved(IdentityId id) {
 
 /***  ***/
 
-
-bool Client::isConnected() {
-  return instance()->connectedToCore;
-}
-
 void Client::fakeInput(uint bufferUid, QString message) {
   Buffer *buff = buffer(bufferUid);
   if(!buff)
@@ -250,65 +257,31 @@ void Client::fakeInput(BufferInfo bufferInfo, QString message) {
   fakeInput(bufferInfo, message);
 }
 
-void Client::connectToCore(const QVariantMap &conn) {
-  // TODO implement SSL
-  coreConnectionInfo = conn;
-  if(isConnected()) {
-    emit coreConnectionError(tr("Already connected to Core!"));
-    return;
-  }
-  
-  if(socket != 0)
-    socket->deleteLater();
-  
-  if(conn["Host"].toString().isEmpty()) {
-    clientMode = LocalCore;
-    socket = new QBuffer(this);
-    connect(socket, SIGNAL(readyRead()), this, SLOT(coreHasData()));
-    socket->open(QIODevice::ReadWrite);
-    //QVariant state = connectToLocalCore(coreConnectionInfo["User"].toString(), coreConnectionInfo["Password"].toString());
-    //syncToCore(state);
-    coreSocketConnected();
-  } else {
-    clientMode = RemoteCore;
-    emit coreConnectionMsg(tr("Connecting..."));
-    Q_ASSERT(!socket);
-    QTcpSocket *sock = new QTcpSocket(this);
-    socket = sock;
-    connect(sock, SIGNAL(readyRead()), this, SLOT(coreHasData()));
-    connect(sock, SIGNAL(connected()), this, SLOT(coreSocketConnected()));
-    connect(signalProxy(), SIGNAL(disconnected()), this, SLOT(coreSocketDisconnected()));
-    connect(sock, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(coreSocketError(QAbstractSocket::SocketError)));
-    sock->connectToHost(conn["Host"].toString(), conn["Port"].toUInt());
-  }
-}
-
-void Client::disconnectFromCore() {
-  socket->close();
-}
+/*** core connection stuff ***/
 
-void Client::setCoreConfiguration(const QVariantMap &settings) {
-  SignalProxy::writeDataToDevice(socket, settings);
+void Client::setConnectedToCore(QIODevice *sock) {
+  socket = sock;
+  signalProxy()->addPeer(socket);
+  _connectedToCore = true;
 }
 
-void Client::coreSocketConnected() {
-  connect(this, SIGNAL(recvPartialItem(uint, uint)), this, SIGNAL(coreConnectionProgress(uint, uint)));
-  emit coreConnectionMsg(tr("Synchronizing to core..."));
-  QVariantMap clientInit;
-  clientInit["GuiProtocol"] = GUI_PROTOCOL;
-  clientInit["User"] = coreConnectionInfo["User"].toString();
-  clientInit["Password"] = coreConnectionInfo["Password"].toString();
-  SignalProxy::writeDataToDevice(socket, clientInit);
+void Client::setSyncedToCore() {
+  _syncedToCore = true;
+  emit connected();
+  emit coreConnectionStateChanged(true);
 }
 
-void Client::coreSocketDisconnected() {
-  instance()->connectedToCore = false;
+void Client::disconnectFromCore() {
+  if(socket) {
+    socket->close();
+    socket->deleteLater();
+  }
+  _connectedToCore = false;
+  _syncedToCore = false;
   emit disconnected();
   emit coreConnectionStateChanged(false);
-  socket->deleteLater();
-  blockSize = 0;
 
-  /* Clear internal data. Hopefully nothing relies on it at this point. */
+  // Clear internal data. Hopefully nothing relies on it at this point.
   _networkModel->clear();
 
   QHash<BufferId, Buffer *>::iterator bufferIter =  _buffers.begin();
@@ -321,14 +294,14 @@ void Client::coreSocketDisconnected() {
   Q_ASSERT(_buffers.isEmpty());
 
 
-  QHash<NetworkId, Network*>::iterator netIter = _network.begin();
-  while(netIter != _network.end()) {
+  QHash<NetworkId, Network*>::iterator netIter = _networks.begin();
+  while(netIter != _networks.end()) {
     Network *net = netIter.value();
     disconnect(net, SIGNAL(destroyed()), this, 0);
-    netIter = _network.erase(netIter);
+    netIter = _networks.erase(netIter);
     net->deleteLater();
   }
-  Q_ASSERT(_network.isEmpty());
+  Q_ASSERT(_networks.isEmpty());
 
   QHash<IdentityId, Identity*>::iterator idIter = _identities.begin();
   while(idIter != _identities.end()) {
@@ -339,116 +312,16 @@ void Client::coreSocketDisconnected() {
   }
   Q_ASSERT(_identities.isEmpty());
 
-  coreConnectionInfo.clear();
   sessionData.clear();
   layoutQueue.clear();
   layoutTimer->stop();
 }
 
-void Client::recvCoreState(const QVariant &state) {
-  disconnect(this, SIGNAL(recvPartialItem(uint, uint)), this, SIGNAL(coreConnectionProgress(uint, uint)));
-  disconnect(socket, 0, this, 0);  // rest of communication happens through SignalProxy
-  signalProxy()->addPeer(socket);
-  syncToCore(state);
-}
-
-// TODO: auth errors
-void Client::syncToCore(const QVariant &coreState) {
-  if(!coreState.toMap().contains("SessionState")) {
-    emit coreConnectionError(tr("Invalid data received from core!"));
-    disconnectFromCore();
-    return;
-  }
-
-  QVariantMap sessionState = coreState.toMap()["SessionState"].toMap();
-
-  // store sessionData
-  QVariantMap sessData = sessionState["SessionData"].toMap();
-  foreach(QString key, sessData.keys())
-    recvSessionData(key, sessData[key]);
-
-  // create identities
-  foreach(QVariant vid, sessionState["Identities"].toList()) {
-    coreIdentityCreated(vid.value<Identity>());
-  }
-
-  // store Buffer details
-  QVariantList coreBuffers = sessionState["Buffers"].toList();
-  /* make lookups by id faster */
-  foreach(QVariant vid, coreBuffers) {
-    buffer(vid.value<BufferInfo>()); // create all buffers, so we see them in the network views
-  }
-
-  // create network objects
-  QVariantList networkids = sessionState["Networks"].toList();
-  foreach(QVariant networkid, networkids) {
-    networkConnected(networkid.toUInt());
-  }
-
-  instance()->connectedToCore = true;
-  updateCoreConnectionProgress();
-
+void Client::setCoreConfiguration(const QVariantMap &settings) {
+  SignalProxy::writeDataToDevice(socket, settings);
 }
 
-void Client::updateCoreConnectionProgress() {
-  // we'll do this in three steps:
-  // 1.) networks
-  // 2.) channels
-  // 3.) ircusers
-
-  int numNets = networks().count();
-  int numNetsWaiting = 0;
-
-  int numIrcUsers = 0;
-  int numIrcUsersWaiting = 0;
-
-  int numChannels = 0;
-  int numChannelsWaiting = 0;
-
-  foreach(Network *net, networks()) {
-    if(! net->initialized())
-      numNetsWaiting++;
-
-    numIrcUsers += net->ircUsers().count();
-    foreach(IrcUser *user, net->ircUsers()) {
-      if(! user->initialized())
-       numIrcUsersWaiting++;
-    }
-
-    numChannels += net->ircChannels().count();
-    foreach(IrcChannel *channel, net->ircChannels()) {
-      if(! channel->initialized())
-       numChannelsWaiting++;
-    }
-  }
-
-  if(numNetsWaiting > 0) {
-    emit coreConnectionMsg(tr("Requesting network states..."));
-    emit coreConnectionProgress(numNets - numNetsWaiting, numNets);
-    return;
-  }
-
-  if(numIrcUsersWaiting > 0) {
-    emit coreConnectionMsg(tr("Requesting User states..."));
-    emit coreConnectionProgress(numIrcUsers - numIrcUsersWaiting, numIrcUsers);
-    return;
-  }
-
-  if(numChannelsWaiting > 0) {
-    emit coreConnectionMsg(tr("Requesting Channel states..."));
-    emit coreConnectionProgress(numChannels - numChannelsWaiting, numChannels);
-    return;
-  }
-
-  emit coreConnectionProgress(1,1);
-  emit connected();
-  emit coreConnectionStateChanged(true);
-  foreach(Network *net, networks()) {
-    disconnect(net, 0, this, SLOT(updateCoreConnectionProgress()));
-  }
-
-  // signalProxy()->dumpProxyStats();
-}
+/*** Session data ***/
 
 void Client::recvSessionData(const QString &key, const QVariant &data) {
   sessionData[key] = data;
@@ -472,31 +345,9 @@ QStringList Client::sessionDataKeys() {
   return instance()->sessionData.keys();
 }
 
-void Client::coreSocketError(QAbstractSocket::SocketError) {
-  emit coreConnectionError(socket->errorString());
-  socket->deleteLater();
-}
-
-void Client::coreHasData() {
-  QVariant item;
-  if(SignalProxy::readDataFromDevice(socket, blockSize, item)) {
-    emit recvPartialItem(1,1);
-    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;
-  }
-  if(blockSize > 0) {
-    emit recvPartialItem(socket->bytesAvailable(), blockSize);
-  }
-}
+/*** ***/
 
+/*
 void Client::networkConnected(uint netid) {
   // TODO: create statusBuffer / switch to networkids
   //BufferInfo id = statusBufferInfo(net);
@@ -506,29 +357,40 @@ void Client::networkConnected(uint netid) {
   Network *netinfo = new Network(netid, this);
   netinfo->setProxy(signalProxy());
   networkModel()->attachNetwork(netinfo);
-  
-  if(!isConnected()) {
-    connect(netinfo, SIGNAL(initDone()), this, SLOT(updateCoreConnectionProgress()));
-    connect(netinfo, SIGNAL(ircUserInitDone()), this, SLOT(updateCoreConnectionProgress()));
-    connect(netinfo, SIGNAL(ircChannelInitDone()), this, SLOT(updateCoreConnectionProgress()));
-  }
   connect(netinfo, SIGNAL(destroyed()), this, SLOT(networkDestroyed()));
-  _network[netid] = netinfo;
+  _networks[netid] = netinfo;
 }
 
-void Client::networkDisconnected(uint networkid) {
-  if(!_network.contains(networkid)) {
+void Client::networkDisconnected(NetworkId networkid) {
+  if(!_networks.contains(networkid)) {
     qWarning() << "Client::networkDisconnected(uint): unknown Network" << networkid;
     return;
   }
 
-  Network *net = _network.take(networkid);
-  if(!net->initialized()) {
+  Network *net = _networks.take(networkid);
+  if(!net->isInitialized()) {
     qDebug() << "Network" << networkid << "disconnected while not yet initialized!";
     updateCoreConnectionProgress();
   }
   net->deleteLater();
 }
+*/
+
+void Client::addNetwork(NetworkId netid) {
+  Network *net = new Network(netid, instance());
+  addNetwork(net);
+}
+
+void Client::addNetwork(Network *net) {
+  net->setProxy(signalProxy());
+  signalProxy()->synchronize(net);
+  networkModel()->attachNetwork(net);
+  connect(net, SIGNAL(destroyed()), instance(), SLOT(networkDestroyed()));
+  instance()->_networks[net->networkId()] = net;
+  //if(net->networkId() == 1) net->requestConnect(); // FIXME
+}
+
+/*** ***/
 
 void Client::updateBufferInfo(BufferInfo id) {
   emit bufferUpdated(id);
@@ -548,9 +410,9 @@ void Client::bufferDestroyed() {
 
 void Client::networkDestroyed() {
   Network *netinfo = static_cast<Network *>(sender());
-  uint networkId = netinfo->networkId();
-  if(_network.contains(networkId))
-    _network.remove(networkId);
+  NetworkId networkId = netinfo->networkId();
+  if(_networks.contains(networkId))
+    _networks.remove(networkId);
 }
 
 void Client::recvMessage(const Message &msg) {
index d99534b..26e67cc 100644 (file)
@@ -38,6 +38,8 @@ class AbstractUi;
 class AbstractUiMsg;
 class NetworkModel;
 class BufferModel;
+class IrcUser;
+class IrcChannel;
 class NickModel;
 class SignalProxy;
 
@@ -53,11 +55,11 @@ public:
   static void init(AbstractUi *);
 
   static QList<Network *> networks();
-  static Network *network(uint networkid);
+  static Network *network(NetworkId networkid);
 
   static QList<BufferInfo> allBufferInfos();
   static QList<Buffer *> buffers();
-  static Buffer *buffer(uint bufferUid);
+  static Buffer *buffer(BufferId bufferUid);
   static Buffer *buffer(BufferInfo);
 
   static QList<IdentityId> identityIds();
@@ -81,6 +83,10 @@ public:
    */
   static void removeIdentity(IdentityId id);
 
+  static void addNetwork(NetworkId id);
+  static void addNetwork(Network *);
+
+
   static NetworkModel *networkModel();
   static BufferModel *bufferModel();
   static NickModel *nickModel();
@@ -89,8 +95,9 @@ public:
   static AbstractUiMsg *layoutMsg(const Message &);
 
   static bool isConnected();
+  static bool isSynced();
 
-  static void fakeInput(uint bufferUid, QString message);
+  static void fakeInput(BufferId bufferUid, QString message);
   static void fakeInput(BufferInfo bufferInfo, QString message);
 
   static void storeSessionData(const QString &key, const QVariant &data);
@@ -107,11 +114,6 @@ signals:
   void requestBacklog(BufferInfo, QVariant, QVariant);
   void requestNetworkStates();
 
-  void recvPartialItem(uint avail, uint size);
-  void coreConnectionError(QString errorMsg);
-  void coreConnectionMsg(const QString &msg);
-  void coreConnectionProgress(uint part, uint total);
-
   void showConfigWizard(const QVariantMap &coredata);
 
   void connected();
@@ -144,27 +146,24 @@ signals:
 
 public slots:
   //void selectBuffer(Buffer *);
-  //void connectToLocalCore();
-  void connectToCore(const QVariantMap &);
+
+  void setConnectedToCore(QIODevice *socket);
+  void setSyncedToCore();
   void disconnectFromCore();
 
   void setCoreConfiguration(const QVariantMap &settings);
 
+
 private slots:
-  void recvCoreState(const QVariant &state);
   void recvSessionData(const QString &key, const QVariant &data);
 
-  void coreSocketError(QAbstractSocket::SocketError);
-  void coreHasData();
-  void coreSocketConnected();
-  void coreSocketDisconnected();
+  //void coreSocketError(QAbstractSocket::SocketError);
 
   void userInput(BufferInfo, QString);
 
-  void networkConnected(uint);
-  void networkDisconnected(uint);
+  //void networkConnected(NetworkId);
+  //void networkDisconnected(NetworkId);
 
-  void updateCoreConnectionProgress();
   void recvMessage(const Message &message);
   void recvStatusMsg(QString network, QString message);
   void recvBacklogData(BufferInfo, QVariantList, bool);
@@ -182,7 +181,7 @@ private:
   virtual ~Client();
   void init();
 
-  void syncToCore(const QVariant &coreState);
+  void syncToCore(const QVariantMap &sessionState);
 
   static QPointer<Client> instanceptr;
 
@@ -195,12 +194,10 @@ private:
 
   ClientMode clientMode;
 
-  quint32 blockSize;
-  bool connectedToCore;
+  bool _connectedToCore, _syncedToCore;
 
-  QVariantMap coreConnectionInfo;
   QHash<BufferId, Buffer *> _buffers;
-  QHash<NetworkId, Network *> _network;
+  QHash<NetworkId, Network *> _networks;
   QHash<IdentityId, Identity *> _identities;
 
   QTimer *layoutTimer;
@@ -208,7 +205,7 @@ private:
 
   QVariantMap sessionData;
 
-
+  friend class ClientSyncer;
 };
 
 #endif
index 89088da..a35211c 100644 (file)
@@ -1,6 +1,6 @@
 DEPMOD = common
-QT_MOD = core network gui   # gui is needed just for QColor... FIXME!
-SRCS += buffer.cpp treemodel.cpp networkmodel.cpp buffermodel.cpp client.cpp clientsettings.cpp mappedselectionmodel.cpp modelpropertymapper.cpp \
-        nickmodel.cpp selectionmodelsynchronizer.cpp
-HDRS += buffer.h treemodel.h networkmodel.h buffermodel.h client.h clientsettings.h quasselui.h mappedselectionmodel.h modelpropertymapper.h \
-        nickmodel.h selectionmodelsynchronizer.h
+QT_MOD = core network gui
+SRCS += buffer.cpp treemodel.cpp networkmodel.cpp buffermodel.cpp client.cpp clientsettings.cpp clientsyncer.cpp \
+        mappedselectionmodel.cpp modelpropertymapper.cpp nickmodel.cpp selectionmodelsynchronizer.cpp
+HDRS += buffer.h treemodel.h networkmodel.h buffermodel.h client.h clientsettings.h clientsyncer.h quasselui.h \
+        mappedselectionmodel.h modelpropertymapper.h nickmodel.h selectionmodelsynchronizer.h
index 9cb4581..8410350 100644 (file)
@@ -48,41 +48,56 @@ QVariant ClientSettings::sessionValue(const QString &key, const QVariant &def) {
 
 /***********************************************************************************************/
 
-AccountSettings::AccountSettings() : ClientSettings("Accounts") {
+CoreAccountSettings::CoreAccountSettings() : ClientSettings("CoreAccounts") {
 
 
 }
 
-QStringList AccountSettings::knownAccounts() {
-  return localChildGroups();
+QStringList CoreAccountSettings::knownAccounts() {
+  return localChildKeys("Accounts");
 }
 
-QString AccountSettings::lastAccount() {
+QString CoreAccountSettings::lastAccount() {
   return localValue("LastAccount", "").toString();
 }
 
-void AccountSettings::setLastAccount(const QString &account) {
+void CoreAccountSettings::setLastAccount(const QString &account) {
   setLocalValue("LastAccount", account);
 }
 
-QString AccountSettings::autoConnectAccount() {
+QString CoreAccountSettings::autoConnectAccount() {
   return localValue("AutoConnectAccount", "").toString();
 }
 
-void AccountSettings::setAutoConnectAccount(const QString &account) {
+void CoreAccountSettings::setAutoConnectAccount(const QString &account) {
   setLocalValue("AutoConnectAccount", account);
 }
 
-void AccountSettings::setValue(const QString &account, const QString &key, const QVariant &data) {
-  setLocalValue(QString("%1/%2").arg(account).arg(key), data);
+void CoreAccountSettings::storeAccount(const QString name, const QVariantMap &data) {
+  setLocalValue(QString("Accounts/%2").arg(name), data);
 }
 
-QVariant AccountSettings::value(const QString &account, const QString &key, const QVariant &def) {
-  return localValue(QString("%1/%2").arg(account).arg(key), def);
+QVariantMap CoreAccountSettings::retrieveAccount(const QString &name) {
+  return localValue(QString("Accounts/%2").arg(name), QVariant()).toMap();
 }
 
-void AccountSettings::removeAccount(const QString &account) {
-  removeLocalKey(account);
+void CoreAccountSettings::storeAllAccounts(const QHash<QString, QVariantMap> accounts) {
+  removeLocalKey(QString("Accounts"));
+  foreach(QString name, accounts.keys()) {
+    storeAccount(name, accounts[name]);
+  }
+}
+
+QHash<QString, QVariantMap> CoreAccountSettings::retrieveAllAccounts() {
+  QHash<QString, QVariantMap> accounts;
+  foreach(QString name, knownAccounts()) {
+    accounts[name] = retrieveAccount(name);
+  }
+  return accounts;
+}
+
+void CoreAccountSettings::removeAccount(const QString &account) {
+  removeLocalKey(QString("Accounts/%1").arg(account));
 }
 
 
index 1c86dac..c874b78 100644 (file)
@@ -39,10 +39,10 @@ class ClientSettings : public Settings {
 
 };
 
-class AccountSettings : public ClientSettings {
+class CoreAccountSettings : public ClientSettings {
 
   public:
-    AccountSettings();
+    CoreAccountSettings();
 
     QStringList knownAccounts();
     QString lastAccount();
@@ -50,8 +50,10 @@ class AccountSettings : public ClientSettings {
     QString autoConnectAccount();
     void setAutoConnectAccount(const QString &account);
 
-    void setValue(const QString &account, const QString &key, const QVariant &data);
-    QVariant value(const QString &account, const QString &key, const QVariant &def = QVariant());
+    void storeAccount(const QString name, const QVariantMap &data);
+    QVariantMap retrieveAccount(const QString &name);
+    void storeAllAccounts(const QHash<QString, QVariantMap> accounts);
+    QHash<QString, QVariantMap> retrieveAllAccounts();
     void removeAccount(const QString &account);
 
 };
diff --git a/src/client/clientsyncer.cpp b/src/client/clientsyncer.cpp
new file mode 100644 (file)
index 0000000..afc1e16
--- /dev/null
@@ -0,0 +1,328 @@
+/***************************************************************************
+ *   Copyright (C) 2005-08 by the Quassel IRC 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) version 3.                                           *
+ *                                                                         *
+ *   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 "clientsyncer.h"
+
+#include "client.h"
+#include "global.h"
+#include "identity.h"
+#include "ircuser.h"
+#include "ircchannel.h"
+#include "network.h"
+#include "signalproxy.h"
+
+
+ClientSyncer::ClientSyncer(QObject *parent) : QObject(parent) {
+  socket = 0;
+  blockSize = 0;
+
+  connect(Client::signalProxy(), SIGNAL(disconnected()), this, SLOT(coreSocketDisconnected()));
+
+}
+
+ClientSyncer::~ClientSyncer() {
+
+
+}
+
+
+void ClientSyncer::coreHasData() {
+  QVariant item;
+  while(SignalProxy::readDataFromDevice(socket, blockSize, item)) {
+    emit recvPartialItem(1,1);
+    QVariantMap msg = item.toMap();
+    if(!msg.contains("MsgType")) {
+      // This core is way too old and does not even speak our init protocol...
+      emit connectionError(tr("The Quassel Core you try to connect to is too old! Please consider upgrading."));
+      disconnectFromCore();
+      return;
+    }
+    if(msg["MsgType"] == "ClientInitAck") {
+      clientInitAck(msg);
+    } else if(msg["MsgType"] == "ClientInitReject") {
+      emit connectionError(msg["Error"].toString());
+      disconnectFromCore();
+      return;
+    } else if(msg["MsgType"] == "ClientLoginReject") {
+      emit loginFailed(msg["Error"].toString());
+    } else if(msg["MsgType"] == "ClientLoginAck") {
+      // prevent multiple signal connections
+      disconnect(this, SIGNAL(recvPartialItem(quint32, quint32)), this, SIGNAL(sessionProgress(quint32, quint32)));
+      connect(this, SIGNAL(recvPartialItem(quint32, quint32)), this, SIGNAL(sessionProgress(quint32, quint32)));
+      emit loginSuccess();
+    } else if(msg["MsgType"] == "SessionInit") {
+      sessionStateReceived(msg["SessionState"].toMap());
+    } else {
+      emit connectionError(tr("<b>Invalid data received from core!</b><br>Disconnecting."));
+      disconnectFromCore();
+      return;
+    }
+    /*
+    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;
+  }
+    */
+  }
+  if(blockSize > 0) {
+    emit recvPartialItem(socket->bytesAvailable(), blockSize);
+  }
+}
+
+void ClientSyncer::coreSocketError(QAbstractSocket::SocketError) {
+  emit connectionError(socket->errorString());
+  socket->deleteLater();
+}
+
+void ClientSyncer::disconnectFromCore() {
+  if(socket) socket->close();
+}
+
+void ClientSyncer::connectToCore(const QVariantMap &conn) {
+  // TODO implement SSL
+  coreConnectionInfo = conn;
+  //if(isConnected()) {
+  //  emit coreConnectionError(tr("Already connected to Core!"));
+  //  return;
+  // }
+
+  if(socket != 0) {
+    socket->deleteLater();
+    socket = 0;
+  }
+  if(conn["Host"].toString().isEmpty()) {
+    emit connectionError(tr("Internal connections not yet supported."));
+    return; // FIXME implement internal connections
+    //clientMode = LocalCore;
+    socket = new QBuffer(this);
+    connect(socket, SIGNAL(readyRead()), this, SLOT(coreHasData()));
+    socket->open(QIODevice::ReadWrite);
+    //QVariant state = connectToLocalCore(coreConnectionInfo["User"].toString(), coreConnectionInfo["Password"].toString());
+    //syncToCore(state);
+    coreSocketConnected();
+  } else {
+    //clientMode = RemoteCore;
+    //emit coreConnectionMsg(tr("Connecting..."));
+    Q_ASSERT(!socket);
+    QTcpSocket *sock = new QTcpSocket(Client::instance());
+    socket = sock;
+    connect(sock, SIGNAL(readyRead()), this, SLOT(coreHasData()));
+    connect(sock, SIGNAL(connected()), this, SLOT(coreSocketConnected()));
+    connect(sock, SIGNAL(disconnected()), this, SLOT(coreSocketDisconnected()));
+    connect(sock, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(coreSocketError(QAbstractSocket::SocketError)));
+    connect(sock, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SIGNAL(socketStateChanged(QAbstractSocket::SocketState)));
+    sock->connectToHost(conn["Host"].toString(), conn["Port"].toUInt());
+  }
+}
+
+void ClientSyncer::coreSocketConnected() {
+  //connect(this, SIGNAL(recvPartialItem(uint, uint)), this, SIGNAL(coreConnectionProgress(uint, uint)));
+  // Phase One: Send client info and wait for core info
+
+  //emit coreConnectionMsg(tr("Synchronizing to core..."));
+  QVariantMap clientInit;
+  clientInit["MsgType"] = "ClientInit";
+  clientInit["ClientVersion"] = Global::quasselVersion;
+  clientInit["ClientDate"] = Global::quasselDate;
+  clientInit["ClientBuild"] = Global::quasselBuild; // this is a minimum, since we probably won't update for every commit
+  clientInit["UseSsl"] = false;  // FIXME implement SSL
+  SignalProxy::writeDataToDevice(socket, clientInit);
+}
+
+void ClientSyncer::coreSocketDisconnected() {
+  emit socketDisconnected();
+  Client::instance()->disconnectFromCore();
+
+  // FIXME handle disconnects gracefully in here as well!
+
+  coreConnectionInfo.clear();
+  netsToSync.clear();
+  channelsToSync.clear();
+  usersToSync.clear();
+  blockSize = 0;
+  //restartPhaseNull();
+}
+
+void ClientSyncer::clientInitAck(const QVariantMap &msg) {
+  // Core has accepted our version info and sent its own. Let's see if we accept it as well...
+  if(msg["CoreBuild"].toUInt() < Global::coreBuildNeeded) {
+    emit connectionError(tr("<b>The Quassel Core you are trying to connect to is too old!</b><br>"
+        "Need at least a Core Version %1 (Build >= %2) to connect.").arg(Global::quasselVersion).arg(Global::quasselBuild));
+    disconnectFromCore();
+    return;
+  }
+  emit connectionMsg(msg["CoreInfo"].toString());
+  if(msg["LoginEnabled"].toBool()) {
+    emit startLogin();
+  }
+}
+
+void ClientSyncer::loginToCore(const QString &user, const QString &passwd) {
+  emit connectionMsg(tr("Logging in..."));
+  QVariantMap clientLogin;
+  clientLogin["MsgType"] = "ClientLogin";
+  clientLogin["User"] = user;
+  clientLogin["Password"] = passwd;
+  SignalProxy::writeDataToDevice(socket, clientLogin);
+}
+
+void ClientSyncer::sessionStateReceived(const QVariantMap &state) {
+  emit sessionProgress(1, 1);
+  disconnect(this, SIGNAL(recvPartialItem(quint32, quint32)), this, SIGNAL(sessionProgress(quint32, quint32)));
+  disconnect(socket, 0, this, 0);  // rest of communication happens through SignalProxy
+  //Client::signalProxy()->addPeer(socket);
+  Client::instance()->setConnectedToCore(socket);
+  syncToCore(state);
+}
+
+void ClientSyncer::syncToCore(const QVariantMap &sessionState) {
+
+  // store sessionData
+  QVariantMap sessData = sessionState["SessionData"].toMap();
+  foreach(QString key, sessData.keys()) Client::instance()->recvSessionData(key, sessData[key]);
+
+  // create identities
+  foreach(QVariant vid, sessionState["Identities"].toList()) {
+    Client::instance()->coreIdentityCreated(vid.value<Identity>());
+  }
+
+  // create buffers
+  // FIXME: get rid of this crap
+  QVariantList bufferinfos = sessionState["BufferInfos"].toList();
+  foreach(QVariant vinfo, bufferinfos) Client::buffer(vinfo.value<BufferInfo>());  // create Buffers and BufferItems
+
+  QVariantList networkids = sessionState["NetworkIds"].toList();
+
+  // prepare sync progress thingys... FIXME: Care about removal of networks
+  numNetsToSync = networkids.count();
+  numChannelsToSync = 0; //sessionState["IrcChannelCount"].toUInt();
+  numUsersToSync = 0; // sessionState["IrcUserCount"].toUInt(); qDebug() << numUsersToSync;
+  emit networksProgress(0, numNetsToSync);
+  emit channelsProgress(0, numChannelsToSync);
+  emit ircUsersProgress(0, numUsersToSync);
+
+  // create network objects
+  foreach(QVariant networkid, networkids) {
+    NetworkId netid = networkid.value<NetworkId>();
+    Network *net = new Network(netid, Client::instance());
+    netsToSync.insert(net);
+    connect(net, SIGNAL(initDone()), this, SLOT(networkInitDone()));
+    connect(net, SIGNAL(ircUserInitDone(IrcUser *)), this, SLOT(ircUserInitDone(IrcUser *)));
+    connect(net, SIGNAL(ircUserAdded(IrcUser *)), this, SLOT(ircUserAdded(IrcUser *)));
+    connect(net, SIGNAL(ircUserRemoved(QObject *)), this, SLOT(ircUserRemoved(QObject *)));
+    connect(net, SIGNAL(ircChannelInitDone(IrcChannel *)), this, SLOT(ircChannelInitDone(IrcChannel *)));
+    connect(net, SIGNAL(ircChannelAdded(IrcChannel *)), this, SLOT(ircChannelAdded(IrcChannel *)));
+    connect(net, SIGNAL(ircChannelRemoved(QObject *)), this, SLOT(ircChannelRemoved(QObject *)));
+    Client::addNetwork(net);
+  }
+}
+
+void ClientSyncer::networkInitDone() {
+  netsToSync.remove(sender());
+  emit networksProgress(numNetsToSync - netsToSync.count(), numNetsToSync);
+  checkSyncState();
+}
+
+void ClientSyncer::ircChannelInitDone(IrcChannel *chan) {
+  channelsToSync.remove(chan);
+  emit channelsProgress(numChannelsToSync - channelsToSync.count(), numChannelsToSync);
+  checkSyncState();
+}
+
+void ClientSyncer::ircChannelAdded(IrcChannel *chan) {
+  if(!chan->isInitialized()) {
+    channelsToSync.insert(chan);
+    numChannelsToSync++;
+    emit channelsProgress(numChannelsToSync - channelsToSync.count(), numChannelsToSync);
+    checkSyncState();
+  }
+}
+
+void ClientSyncer::ircChannelRemoved(QObject *chan) {
+  if(channelsToSync.contains(chan)) {
+    numChannelsToSync--;
+    channelsToSync.remove(chan);
+    emit channelsProgress(numChannelsToSync - channelsToSync.count(), numChannelsToSync);
+    checkSyncState();
+  }
+}
+
+void ClientSyncer::ircUserInitDone(IrcUser *user) {
+  usersToSync.remove(user);
+  emit ircUsersProgress(numUsersToSync - usersToSync.count(), numUsersToSync);
+  checkSyncState();
+}
+
+void ClientSyncer::ircUserAdded(IrcUser *user) {
+  if(!user->isInitialized()) {
+    usersToSync.insert(user);
+    numUsersToSync++;
+    emit ircUsersProgress(numUsersToSync - usersToSync.count(), numUsersToSync);
+    checkSyncState();
+  }
+}
+
+void ClientSyncer::ircUserRemoved(QObject *user) {
+  if(usersToSync.contains(user)) {
+    numUsersToSync--;
+    usersToSync.remove(user);
+    emit ircUsersProgress(numUsersToSync - usersToSync.count(), numUsersToSync);
+    checkSyncState();
+  }
+}
+
+void ClientSyncer::checkSyncState() {
+  if(usersToSync.count() + channelsToSync.count() + netsToSync.count() == 0) {
+    // done syncing!
+    /*
+    qDebug() << "done";
+    foreach(Network *net, _networks.values()) {
+      //disconnect(net, 0, this, SLOT(networkInitDone()));
+      //disconnect(net, 0, this, SLOT(ircUserInitDone(IrcUser *)));
+      //disconnect(net, 0, this, SLOT(ircUserAdded(IrcUser *)));
+      //disconnect(net, 0, this, SLOT(ircUserRemoved(QObject *)));
+      //disconnect(net, 0, this, SLOT(ircChannelInitDone(IrcChannel *)));
+      //disconnect(net, 0, this, SLOT(ircChannelAdded(IrcChannel *)));
+      //disconnect(net, 0, this, SLOT(ircChannelRemoved(QObject *)));
+      qDebug() << "disconnecting";
+      disconnect(net, SIGNAL(initDone()), this, SLOT(networkInitDone()));
+      disconnect(net, SIGNAL(ircUserInitDone(IrcUser *)), this, SLOT(ircUserInitDone(IrcUser *)));
+      disconnect(net, SIGNAL(ircUserAdded(IrcUser *)), this, SLOT(ircUserAdded(IrcUser *)));
+      disconnect(net, SIGNAL(ircUserRemoved(QObject *)), this, SLOT(ircUserRemoved(QObject *)));
+      disconnect(net, SIGNAL(ircChannelInitDone(IrcChannel *)), this, SLOT(ircChannelInitDone(IrcChannel *)));
+      disconnect(net, SIGNAL(ircChannelAdded(IrcChannel *)), this, SLOT(ircChannelAdded(IrcChannel *)));
+      disconnect(net, SIGNAL(ircChannelRemoved(QObject *)), this, SLOT(ircChannelRemoved(QObject *)));
+    }
+    */
+
+    Client::instance()->setSyncedToCore();
+    emit syncFinished();
+    //emit connected();
+    //emit connectionStateChanged(true);
+
+  }
+}
+
diff --git a/src/client/clientsyncer.h b/src/client/clientsyncer.h
new file mode 100644 (file)
index 0000000..9501d8d
--- /dev/null
@@ -0,0 +1,92 @@
+/***************************************************************************
+ *   Copyright (C) 2005-08 by the Quassel IRC 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) version 3.                                           *
+ *                                                                         *
+ *   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 _CLIENTSYNCER_H_
+#define _CLIENTSYNCER_H_
+
+#include <QPointer>
+#include <QString>
+#include <QTcpSocket>
+#include <QVariantMap>
+
+class IrcUser;
+class IrcChannel;
+
+class ClientSyncer : public QObject {
+  Q_OBJECT
+
+  public:
+    ClientSyncer(QObject *parent = 0);
+    ~ClientSyncer();
+
+  signals:
+    void recvPartialItem(quint32 avail, quint32 size);
+    void connectionError(const QString &errorMsg);
+    void connectionMsg(const QString &msg);
+    void sessionProgress(quint32 part, quint32 total);
+    void networksProgress(quint32 part, quint32 total);
+    void channelsProgress(quint32 part, quint32 total);
+    void ircUsersProgress(quint32 part, quint32 total);
+    void socketStateChanged(QAbstractSocket::SocketState);
+    void socketDisconnected();
+
+    void startLogin();
+    void loginFailed(const QString &error);
+    void loginSuccess();
+    void syncFinished();
+
+
+  public slots:
+    void connectToCore(const QVariantMap &);
+    void loginToCore(const QString &user, const QString &passwd);
+    void disconnectFromCore();
+
+  private slots:
+    void coreSocketError(QAbstractSocket::SocketError);
+    void coreHasData();
+    void coreSocketConnected();
+    void coreSocketDisconnected();
+
+    void clientInitAck(const QVariantMap &msg);
+
+  // for sync progress
+    void networkInitDone();
+    void ircUserAdded(IrcUser *);
+    void ircUserRemoved(QObject *);
+    void ircUserInitDone(IrcUser *);
+    void ircChannelAdded(IrcChannel *);
+    void ircChannelRemoved(QObject *);
+    void ircChannelInitDone(IrcChannel *);
+    void checkSyncState();
+
+    void syncToCore(const QVariantMap &sessionState);
+    void sessionStateReceived(const QVariantMap &state);
+
+  private:
+    QPointer<QIODevice> socket;
+    quint32 blockSize;
+    QVariantMap coreConnectionInfo;
+
+    QSet<QObject *> netsToSync, channelsToSync, usersToSync;
+    int numNetsToSync, numChannelsToSync, numUsersToSync;
+
+};
+
+#endif
index 61ee7b9..59485da 100644 (file)
@@ -195,7 +195,7 @@ void BufferItem::removeUserFromCategory(IrcUser *ircUser) {
   IrcUserItem *userItem;
   for(int i = 0; i < childCount(); i++) {
     categoryItem = qobject_cast<UserCategoryItem *>(child(i));
-    if(userItem = qobject_cast<IrcUserItem *>(categoryItem->childById((quint64)ircUser))) {
+    if((userItem = qobject_cast<IrcUserItem *>(categoryItem->childById((quint64)ircUser)))) {
       userItem->deleteLater();
       return;
     }
@@ -210,10 +210,9 @@ void BufferItem::userModeChanged(IrcUser *ircUser) {
 /*****************************************
 *  Network Items
 *****************************************/
-NetworkItem::NetworkItem(const uint &netid, const QString &network, AbstractTreeItem *parent)
+NetworkItem::NetworkItem(const NetworkId &netid, AbstractTreeItem *parent)
   : PropertyMapItem(QList<QString>() << "networkName" << "currentServer" << "nickCount", parent),
-    _networkId(netid),
-    _networkName(network)
+    _networkId(netid)
 {
   setFlags(Qt::ItemIsEnabled);
 }
@@ -243,7 +242,7 @@ QString NetworkItem::networkName() const {
   if(_network)
     return _network->networkName();
   else
-    return _networkName;
+    return QString();
 }
 
 QString NetworkItem::currentServer() const {
@@ -404,31 +403,33 @@ bool NetworkModel::isBufferIndex(const QModelIndex &index) const {
   return index.data(NetworkModel::ItemTypeRole) == NetworkModel::BufferItemType;
 }
 
+/*
 Buffer *NetworkModel::getBufferByIndex(const QModelIndex &index) const {
   BufferItem *item = static_cast<BufferItem *>(index.internalPointer());
   return Client::instance()->buffer(item->id());
 }
+*/
 
 
 // experimental stuff :)
-QModelIndex NetworkModel::networkIndex(uint networkId) {
+QModelIndex NetworkModel::networkIndex(NetworkId networkId) {
   return indexById(networkId);
 }
 
-NetworkItem *NetworkModel::network(uint networkId) {
+NetworkItem *NetworkModel::existsNetworkItem(NetworkId networkId) {
   return qobject_cast<NetworkItem *>(rootItem->childById(networkId));
 }
 
-NetworkItem *NetworkModel::newNetwork(uint networkId, const QString &networkName) {
-  NetworkItem *networkItem = network(networkId);
+NetworkItem *NetworkModel::networkItem(NetworkId networkId) {
+  NetworkItem *netItem = existsNetworkItem(networkId);
 
-  if(networkItem == 0) {
-    networkItem = new NetworkItem(networkId, networkName, rootItem);
-    appendChild(rootItem, networkItem);
+  if(netItem == 0) {
+    netItem = new NetworkItem(networkId, rootItem);
+    appendChild(rootItem, netItem);
   }
 
-  Q_ASSERT(networkItem);
-  return networkItem;
+  Q_ASSERT(netItem);
+  return netItem;
 }
 
 QModelIndex NetworkModel::bufferIndex(BufferId bufferId) {
@@ -442,7 +443,7 @@ QModelIndex NetworkModel::bufferIndex(BufferId bufferId) {
   return QModelIndex();
 }
 
-BufferItem *NetworkModel::buffer(BufferInfo bufferInfo) {
+BufferItem *NetworkModel::existsBufferItem(const BufferInfo &bufferInfo) {
   QModelIndex bufferIdx = bufferIndex(bufferInfo.uid());
   if(bufferIdx.isValid())
     return static_cast<BufferItem *>(bufferIdx.internalPointer());
@@ -450,16 +451,16 @@ BufferItem *NetworkModel::buffer(BufferInfo bufferInfo) {
     return 0;
 }
 
-BufferItem *NetworkModel::newBuffer(BufferInfo bufferInfo) {
-  BufferItem *bufferItem = buffer(bufferInfo);
-  if(bufferItem == 0) {
-    NetworkItem *networkItem = newNetwork(bufferInfo.networkId(), bufferInfo.network());
-    bufferItem = new BufferItem(bufferInfo, networkItem);
-    appendChild(networkItem, bufferItem);
+BufferItem *NetworkModel::bufferItem(const BufferInfo &bufferInfo) {
+  BufferItem *bufItem = existsBufferItem(bufferInfo);
+  if(bufItem == 0) {
+    NetworkItem *netItem = networkItem(bufferInfo.networkId());
+    bufItem = new BufferItem(bufferInfo, netItem);
+    appendChild(netItem, bufItem);
   }
 
-  Q_ASSERT(bufferItem);
-  return bufferItem;
+  Q_ASSERT(bufItem);
+  return bufItem;
 }
 
 QStringList NetworkModel::mimeTypes() const {
@@ -475,19 +476,20 @@ bool NetworkModel::mimeContainsBufferList(const QMimeData *mimeData) {
   return mimeData->hasFormat("application/Quassel/BufferItemList");
 }
 
-QList< QPair<uint, uint> > NetworkModel::mimeDataToBufferList(const QMimeData *mimeData) {
-  QList< QPair<uint, uint> > bufferList;
+QList< QPair<NetworkId, BufferId> > NetworkModel::mimeDataToBufferList(const QMimeData *mimeData) {
+  QList< QPair<NetworkId, BufferId> > bufferList;
 
   if(!mimeContainsBufferList(mimeData))
     return bufferList;
 
   QStringList rawBufferList = QString::fromAscii(mimeData->data("application/Quassel/BufferItemList")).split(",");
-  uint networkId, bufferUid;
+  NetworkId networkId;
+  BufferId bufferUid;
   foreach(QString rawBuffer, rawBufferList) {
     if(!rawBuffer.contains(":"))
       continue;
-    networkId = rawBuffer.section(":", 0, 0).toUInt();
-    bufferUid = rawBuffer.section(":", 1, 1).toUInt();
+    networkId = rawBuffer.section(":", 0, 0).toInt();
+    bufferUid = rawBuffer.section(":", 1, 1).toInt();
     bufferList.append(qMakePair(networkId, bufferUid));
   }
   return bufferList;
@@ -500,8 +502,8 @@ QMimeData *NetworkModel::mimeData(const QModelIndexList &indexes) const {
   QStringList bufferlist;
   QString netid, uid, bufferid;
   foreach(QModelIndex index, indexes) {
-    netid = QString::number(index.data(NetworkIdRole).toUInt());
-    uid = QString::number(index.data(BufferIdRole).toUInt());
+    netid = QString::number(index.data(NetworkIdRole).value<NetworkId>());
+    uid = QString::number(index.data(BufferIdRole).value<BufferId>());
     bufferid = QString("%1:%2").arg(netid).arg(uid);
     if(!bufferlist.contains(bufferid))
       bufferlist << bufferid;
@@ -535,7 +537,7 @@ bool NetworkModel::dropMimeData(const QMimeData *data, Qt::DropAction action, in
   uint bufferId = bufferList.first().second;
 
   // no self merges (would kill us)
-  if(bufferId == parent.data(BufferIdRole).toUInt())
+  if(bufferId == parent.data(BufferIdRole).value<BufferId>())
     return false; 
   
   Q_ASSERT(rootItem->childById(netId));
@@ -547,24 +549,20 @@ bool NetworkModel::dropMimeData(const QMimeData *data, Qt::DropAction action, in
     return false;
     
   // TODO: warn user about buffermerge!
-  qDebug() << "merging" << bufferId << parent.data(BufferIdRole).toInt();
+  qDebug() << "merging" << bufferId << parent.data(BufferIdRole).value<BufferId>();
   removeRow(parent.row(), parent.parent());
   
   return true;
 }
 
 void NetworkModel::attachNetwork(Network *net) {
-  NetworkItem *networkItem = network(net->networkId());
-  if(!networkItem) {
-    qWarning() << "NetworkModel::attachNetwork(): network is unknown!";
-    return;
-  }
-  networkItem->attachNetwork(net);
+  NetworkItem *netItem = networkItem(net->networkId());
+  netItem->attachNetwork(net);
 }
 
 void NetworkModel::bufferUpdated(BufferInfo bufferInfo) {
-  BufferItem *bufferItem = newBuffer(bufferInfo);
-  QModelIndex itemindex = indexByItem(bufferItem);
+  BufferItem *bufItem = bufferItem(bufferInfo);
+  QModelIndex itemindex = indexByItem(bufItem);
   emit dataChanged(itemindex, itemindex);
 }
 
index a9a108d..b1cc15f 100644 (file)
@@ -114,7 +114,7 @@ class NetworkItem : public PropertyMapItem {
   Q_PROPERTY(int nickCount READ nickCount)
     
 public:
-  NetworkItem(const uint &netid, const QString &, AbstractTreeItem *parent = 0);
+  NetworkItem(const NetworkId &netid, AbstractTreeItem *parent = 0);
 
   virtual QVariant data(int column, int row) const;
   virtual quint64 id() const;
@@ -133,8 +133,7 @@ public slots:
   void attachIrcChannel(const QString &channelName);
   
 private:
-  uint _networkId;
-  QString _networkName;
+  NetworkId _networkId;
 
   QPointer<Network> _network;
 };
@@ -221,7 +220,7 @@ public:
   static QList<QVariant> defaultHeader();
 
   static bool mimeContainsBufferList(const QMimeData *mimeData);
-  static QList< QPair<uint, uint> > mimeDataToBufferList(const QMimeData *mimeData);
+  static QList< QPair<NetworkId, BufferId> > mimeDataToBufferList(const QMimeData *mimeData);
 
   virtual QStringList mimeTypes() const;
   virtual QMimeData *mimeData(const QModelIndexList &) const;
@@ -230,7 +229,7 @@ public:
   void attachNetwork(Network *network);
 
   bool isBufferIndex(const QModelIndex &) const;
-  Buffer *getBufferByIndex(const QModelIndex &) const;
+  //Buffer *getBufferByIndex(const QModelIndex &) const;
   QModelIndex bufferIndex(BufferId bufferId);
 
 public slots:
@@ -238,12 +237,11 @@ public slots:
   void bufferActivity(BufferItem::ActivityLevel, BufferInfo bufferInfo);
 
 private:
-  QModelIndex networkIndex(uint networkId);
-  NetworkItem *network(uint networkId);
-  NetworkItem *newNetwork(uint networkId, const QString &networkName);
-  
-  BufferItem *buffer(BufferInfo bufferInfo);
-  BufferItem *newBuffer(BufferInfo bufferInfo);
+  QModelIndex networkIndex(NetworkId networkId);
+  NetworkItem *networkItem(NetworkId networkId);
+  NetworkItem *existsNetworkItem(NetworkId networkId);
+  BufferItem *bufferItem(const BufferInfo &bufferInfo);
+  BufferItem *existsBufferItem(const BufferInfo &bufferInfo);
 
 };
 
index 09aa590..ce71aeb 100644 (file)
@@ -64,6 +64,7 @@ void Global::initIconMap() {
 
 //! Register our custom types with Qt's Meta Object System.
 /**  This makes them available for QVariant and in signals/slots, among other things.
+ *
  */
 void Global::registerMetaTypes() {
   // Complex types
@@ -82,13 +83,24 @@ void Global::registerMetaTypes() {
   qRegisterMetaType<IdentityId>("IdentityId");
   qRegisterMetaType<BufferId>("BufferId");
   qRegisterMetaType<NetworkId>("NetworkId");
+  qRegisterMetaType<UserId>("UserId");
 
   qRegisterMetaTypeStreamOperators<IdentityId>("IdentityId");
   qRegisterMetaTypeStreamOperators<BufferId>("BufferId");
   qRegisterMetaTypeStreamOperators<NetworkId>("NetworkId");
+  qRegisterMetaTypeStreamOperators<UserId>("UserId");
 
 }
 
+// Static variables
+
+QString Global::quasselVersion;
+QString Global::quasselDate;
+uint Global::quasselBuild;
+uint Global::clientBuildNeeded;
+QString Global::clientVersionNeeded;
+uint Global::coreBuildNeeded;
+QString Global::coreVersionNeeded;
+
 Global::RunMode Global::runMode;
 uint Global::defaultPort;
-
index 1c72f05..8b7cf83 100644 (file)
@@ -1,5 +1,5 @@
 /***************************************************************************
- *   Copyright (C) 2005 by the Quassel Project                             *
+ *   Copyright (C) 2005-08 by the Quassel Project                          *
  *   devel@quassel-irc.org                                                 *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
 // Enable some shortcuts and stuff
 //#define DEVELMODE
 
-/** The protocol version we use fo the communication between core and GUI */
-#define GUI_PROTOCOL 5
-
-//#define DEFAULT_PORT 4242
-
 /* Some global stuff */
 
 namespace Global {
+
+  extern QString quasselVersion;
+  extern QString quasselDate;
+  extern uint quasselBuild;
+
+  //! Minimum client build number the core needs
+  extern uint clientBuildNeeded;
+  extern QString clientVersionNeeded;
+
+  //! Minimum core build number the client needs
+  extern uint coreBuildNeeded;
+  extern QString coreVersionNeeded;
+
   // We need different config (QSettings) files for client and gui, since the core cannot work with GUI types
   // Set these here. They're used in ClientSettings and CoreSettings.
   const QString coreApplicationName = "Quassel Core";
index b69f898..d7bcbdc 100644 (file)
@@ -55,7 +55,6 @@ Identity::Identity(const Identity &other, QObject *parent) : SyncableObject(pare
 }
 
 void Identity::init() {
-  _initialized = false;
   setObjectName(QString::number(id()));
 }
 
@@ -87,14 +86,6 @@ bool Identity::isValid() const {
   return (id() > 0);
 }
 
-bool Identity::initialized() const {
-  return _initialized;
-}
-
-void Identity::setInitialized() {
-  _initialized = true;
-}
-
 IdentityId Identity::id() const {
   return _identityId;
 }
index bffd2a3..9c961a9 100644 (file)
@@ -84,9 +84,6 @@ class Identity : public SyncableObject {
     QString partReason() const;
     QString quitReason() const;
 
-    bool initialized() const;
-    void setInitialized();
-
   public slots:
     void setId(IdentityId id);
     void setIdentityName(const QString &name);
@@ -133,10 +130,7 @@ class Identity : public SyncableObject {
     void partReasonSet(const QString &);
     void quitReasonSet(const QString &);
 
-    void updatedRemotely();
-
   private:
-    bool _initialized;
     IdentityId _identityId;
     QString _identityName, _realName;
     QStringList _nicks;
index 1e567b5..5c12171 100644 (file)
@@ -73,10 +73,6 @@ bool IrcChannel::isValidChannelUserMode(const QString &mode) const {
   return isvalid;
 }
 
-bool IrcChannel::initialized() const {
-  return _initialized;
-}
-
 QString IrcChannel::name() const {
   return _name;
 }
@@ -169,7 +165,7 @@ void IrcChannel::part(IrcUser *ircuser) {
     // if you wonder why there is no counterpart to ircUserParted:
     // the joines are propagted by the ircuser. the signal ircUserParted is only for convenience
     emit ircUserParted(ircuser);
-    if(network->isMyNick(ircuser))
+    if(network->isMe(ircuser))
        deleteLater();
   }
 }
@@ -258,8 +254,3 @@ void IrcChannel::ircUserNickSet(QString nick) {
   emit ircUserNickSet(ircUser, nick);
 }
 
-void IrcChannel::setInitialized() {
-  _initialized = true;
-  emit initDone();
-}
-
index 2840b52..d970814 100644 (file)
@@ -45,8 +45,6 @@ public:
   bool isKnownUser(IrcUser *ircuser) const;
   bool isValidChannelUserMode(const QString &mode) const;
 
-  bool initialized() const;
-
   QString name() const;
   QString topic() const;
 
@@ -89,8 +87,6 @@ public slots:
   // init seters
   void initSetUserModes(const QVariantMap &usermodes);
 
-  void setInitialized();
-
 signals:
   void topicSet(QString topic);
   void userModesSet(QString nick, QString modes);
@@ -107,8 +103,6 @@ signals:
   void ircUserModeRemoved(IrcUser *ircuser, QString mode);
   void ircUserModesSet(IrcUser *ircuser, QString modes);
 
-  void initDone();
-
 private slots:
    void ircUserDestroyed();
    void ircUserNickSet(QString nick);
index f6818b9..08543e1 100644 (file)
@@ -48,9 +48,6 @@ IrcUser::~IrcUser() {
 // ====================
 //  PUBLIC:
 // ====================
-bool IrcUser::initialized() const {
-  return _initialized;
-}
 
 QString IrcUser::user() const {
   return _user;
@@ -232,8 +229,3 @@ void IrcUser::initSetChannels(const QStringList channels) {
   }
 }
 
-void IrcUser::setInitialized() {
-  _initialized = true;
-  emit initDone();
-}
-
index 0ca81a1..45be422 100644 (file)
@@ -46,8 +46,6 @@ public:
   IrcUser(const QString &hostmask, Network *network);
   virtual ~IrcUser();
 
-  bool initialized() const;
-
   QString user() const;
   QString host() const;
   QString nick() const;
@@ -88,8 +86,6 @@ public slots:
   // init seters
   void initSetChannels(const QStringList channels);
 
-  void setInitialized();
-
 signals:
   void userSet(QString user);
   void hostSet(QString host);
@@ -109,8 +105,6 @@ signals:
 //   void setUsermodes(const QSet<QString> &usermodes);
 //   QSet<QString> usermodes() const;
 
-  void initDone();
-
 private slots:
   void updateObjectName();
   void channelDestroyed();
index b5fe32c..ecd0fa5 100644 (file)
@@ -64,6 +64,8 @@ int main(int argc, char **argv) {
 
   Global::registerMetaTypes();
 
+#include "../../version.inc"
+
 #if defined BUILD_CORE
   Global::runMode = Global::CoreOnly;
   QCoreApplication app(argc, argv);
index 780a5d8..1388060 100644 (file)
 // ====================
 //  Public:
 // ====================
-Network::Network(const uint &networkid, QObject *parent)
-  : SyncableObject(parent),
+Network::Network(const NetworkId &networkid, QObject *parent) : SyncableObject(parent),
     _networkId(networkid),
-    _initialized(false),
+    _identity(0),
     _myNick(QString()),
-    _networkName(QString()),
+    _networkName(QString("<not initialized>")),
     _currentServer(QString()),
     _prefixes(QString()),
     _prefixModes(QString()),
@@ -56,28 +55,24 @@ Network::Network(const uint &networkid, QObject *parent)
 //   }
 //}
 
-uint Network::networkId() const {
+NetworkId Network::networkId() const {
   return _networkId;
 }
 
-bool Network::initialized() const {
-  return _initialized;
-}
-
 SignalProxy *Network::proxy() const {
   return _proxy;
 }
 
 void Network::setProxy(SignalProxy *proxy) {
   _proxy = proxy;
-  proxy->synchronize(this);
+  //proxy->synchronize(this);  // we should to this explicitly from the outside!
 }
 
 bool Network::isMyNick(const QString &nick) const {
   return (myNick().toLower() == nick.toLower());
 }
 
-bool Network::isMyNick(IrcUser *ircuser) const {
+bool Network::isMe(IrcUser *ircuser) const {
   return (ircuser->nick().toLower() == myNick().toLower());
 }
 
@@ -125,6 +120,10 @@ QString Network::myNick() const {
   return _myNick;
 }
 
+IdentityId Network::identity() const {
+  return _identity;
+}
+
 QStringList Network::nicks() const {
   // we don't use _ircUsers.keys() since the keys may be
   // not up to date after a nick change
@@ -139,6 +138,10 @@ QStringList Network::channels() const {
   return _ircChannels.keys();
 }
 
+QList<QVariantMap> Network::serverList() const {
+  return _serverList;
+}
+
 QString Network::prefixes() {
   if(_prefixes.isNull())
     determinePrefixes();
@@ -170,18 +173,19 @@ IrcUser *Network::newIrcUser(const QString &hostmask) {
   if(!_ircUsers.contains(nick)) {
     IrcUser *ircuser = new IrcUser(hostmask, this);
     // mark IrcUser as already initialized to keep the SignalProxy from requesting initData
-    if(initialized())
-      ircuser->setInitialized();
+    //if(isInitialized())
+    //  ircuser->setInitialized();
     if(proxy())
       proxy()->synchronize(ircuser);
     else
       qWarning() << "unable to synchronize new IrcUser" << hostmask << "forgot to call Network::setProxy(SignalProxy *)?";
     
     connect(ircuser, SIGNAL(nickSet(QString)), this, SLOT(ircUserNickChanged(QString)));
-    connect(ircuser, SIGNAL(initDone()), this, SIGNAL(ircUserInitDone()));
+    connect(ircuser, SIGNAL(initDone()), this, SLOT(ircUserInitDone()));
     connect(ircuser, SIGNAL(destroyed()), this, SLOT(ircUserDestroyed()));
     _ircUsers[nick] = ircuser;
     emit ircUserAdded(hostmask);
+    emit ircUserAdded(ircuser);
   }
   return _ircUsers[nick];
 }
@@ -196,8 +200,9 @@ void Network::removeIrcUser(IrcUser *ircuser) {
     return;
 
   _ircUsers.remove(nick);
-  ircuser->deleteLater();
   emit ircUserRemoved(nick);
+  emit ircUserRemoved(ircuser);
+  ircuser->deleteLater();
 }
 
 void Network::removeIrcUser(QString nick) {
@@ -222,22 +227,27 @@ QList<IrcUser *> Network::ircUsers() const {
   return _ircUsers.values();
 }
 
+quint32 Network::ircUserCount() const {
+  return _ircUsers.count();
+}
+
 IrcChannel *Network::newIrcChannel(const QString &channelname) {
   if(!_ircChannels.contains(channelname.toLower())) {
     IrcChannel *channel = new IrcChannel(channelname, this);
     // mark IrcUser as already initialized to keep the SignalProxy from requesting initData
-    if(initialized())
-      channel->setInitialized();
+    //if(isInitialized())
+    //  channel->setInitialized();
 
     if(proxy())
       proxy()->synchronize(channel);
     else
       qWarning() << "unable to synchronize new IrcChannel" << channelname << "forgot to call Network::setProxy(SignalProxy *)?";
 
-    connect(channel, SIGNAL(initDone()), this, SIGNAL(ircChannelInitDone()));
+    connect(channel, SIGNAL(initDone()), this, SLOT(ircChannelInitDone()));
     connect(channel, SIGNAL(destroyed()), this, SLOT(channelDestroyed()));
     _ircChannels[channelname.toLower()] = channel;
     emit ircChannelAdded(channelname);
+    emit ircChannelAdded(channel);
   }
   return _ircChannels[channelname.toLower()];
 }
@@ -263,24 +273,30 @@ QList<IrcChannel *> Network::ircChannels() const {
   return _ircChannels.values();
 }
 
-QTextCodec *Network::codecForEncoding() const {
-  return _codecForEncoding;
+quint32 Network::ircChannelCount() const {
+  return _ircChannels.count();
 }
 
-void Network::setCodecForEncoding(const QString &name) {
-  setCodecForEncoding(QTextCodec::codecForName(name.toAscii()));
+QByteArray Network::codecForEncoding() const {
+  if(_codecForEncoding) return _codecForEncoding->name();
+  return QByteArray();
+}
+
+void Network::setCodecForEncoding(const QByteArray &name) {
+  setCodecForEncoding(QTextCodec::codecForName(name));
 }
 
 void Network::setCodecForEncoding(QTextCodec *codec) {
   _codecForEncoding = codec;
 }
 
-QTextCodec *Network::codecForDecoding() const {
-  return _codecForDecoding;
+QByteArray Network::codecForDecoding() const {
+  if(_codecForDecoding) return _codecForDecoding->name();
+  else return QByteArray();
 }
 
-void Network::setCodecForDecoding(const QString &name) {
-  setCodecForDecoding(QTextCodec::codecForName(name.toAscii()));
+void Network::setCodecForDecoding(const QByteArray &name) {
+  setCodecForDecoding(QTextCodec::codecForName(name));
 }
 
 void Network::setCodecForDecoding(QTextCodec *codec) {
@@ -316,6 +332,16 @@ void Network::setMyNick(const QString &nickname) {
   emit myNickSet(nickname);
 }
 
+void Network::setIdentity(IdentityId id) {
+  _identity = id;
+  emit identitySet(id);
+}
+
+void Network::setServerList(const QList<QVariantMap> &serverList) {
+  _serverList = serverList;
+  emit serverListSet(serverList);
+}
+
 void Network::addSupport(const QString &param, const QString &value) {
   if(!_supports.contains(param)) {
     _supports[param] = value;
@@ -340,6 +366,12 @@ QVariantMap Network::initSupports() const {
   return supports;
 }
 
+QVariantList Network::initServerList() const {
+  QList<QVariant> list;
+  foreach(QVariantMap serverdata, serverList()) list << QVariant(serverdata);
+  return list;
+}
+
 QStringList Network::initIrcUsers() const {
   QStringList hostmasks;
   foreach(IrcUser *ircuser, ircUsers()) {
@@ -360,6 +392,12 @@ void Network::initSetSupports(const QVariantMap &supports) {
   }
 }
 
+void Network::initSetServerList(const QVariantList & serverList) {
+  QList<QVariantMap> slist;
+  foreach(QVariant v, serverList) slist << v.toMap();
+  setServerList(slist);
+}
+
 void Network::initSetIrcUsers(const QStringList &hostmasks) {
   if(!_ircUsers.empty())
     return;
@@ -395,11 +433,23 @@ void Network::ircUserNickChanged(QString newnick) {
     return;
 
   if(newnick.toLower() != oldnick) _ircUsers[newnick.toLower()] = _ircUsers.take(oldnick);
-  
+
   if(myNick().toLower() == oldnick)
     setMyNick(newnick);
 }
 
+void Network::ircUserInitDone() {
+  IrcUser *ircuser = static_cast<IrcUser *>(sender());
+  Q_ASSERT(ircuser);
+  emit ircUserInitDone(ircuser);
+}
+
+void Network::ircChannelInitDone() {
+  IrcChannel *ircchannel = static_cast<IrcChannel *>(sender());
+  Q_ASSERT(ircchannel);
+  emit ircChannelInitDone(ircchannel);
+}
+
 void Network::ircUserDestroyed() {
   IrcUser *ircuser = static_cast<IrcUser *>(sender());
   Q_ASSERT(ircuser);
@@ -409,12 +459,14 @@ void Network::ircUserDestroyed() {
 void Network::channelDestroyed() {
   IrcChannel *channel = static_cast<IrcChannel *>(sender());
   Q_ASSERT(channel);
+  emit ircChannelRemoved(sender());
   _ircChannels.remove(_ircChannels.key(channel));
 }
 
-void Network::setInitialized() {
-  _initialized = true;
-  emit initDone();
+void Network::requestConnect() {
+  if(!proxy()) return;
+  if(proxy()->proxyMode() == SignalProxy::Client) emit connectRequested(); // on the client this triggers calling this slot on the core
+  else emit connectRequested(networkId());  // and this is for CoreSession :)
 }
 
 // ====================
index 93d9d51..6a58d84 100644 (file)
 #ifndef _NETWORK_H_
 #define _NETWORK_H_
 
+#include <QDebug>
 #include <QString>
 #include <QStringList>
 #include <QList>
 #include <QHash>
 #include <QVariantMap>
 #include <QPointer>
+#include <QMutex>
 
 #include "types.h"
 #include "syncableobject.h"
@@ -35,6 +37,7 @@ class SignalProxy;
 class IrcUser;
 class IrcChannel;
 
+// TODO: ConnectionInfo to propagate and sync the current state of NetworkConnection, encodings etcpp
 
 class Network : public SyncableObject {
   Q_OBJECT
@@ -42,19 +45,22 @@ class Network : public SyncableObject {
   Q_PROPERTY(QString networkName READ networkName WRITE setNetworkName STORED false)
   Q_PROPERTY(QString currentServer READ currentServer WRITE setCurrentServer STORED false)
   Q_PROPERTY(QString myNick READ myNick WRITE setMyNick STORED false)
+  Q_PROPERTY(QByteArray codecForEncoding READ codecForEncoding WRITE setCodecForEncoding STORED false)
+  Q_PROPERTY(QByteArray codecForDecoding READ codecForDecoding WRITE setCodecForDecoding STORED false)
+  Q_PROPERTY(IdentityId identityId READ identity WRITE setIdentity STORED false)
+  // Q_PROPERTY(bool isConnected READ isConnected STORED false)
 
 public:
-  Network(const uint &networkid, QObject *parent = 0);
+  Network(const NetworkId &networkid, QObject *parent = 0);
   //virtual ~Network();
 
   NetworkId networkId() const;
-  bool initialized() const;
 
   SignalProxy *proxy() const;
   void setProxy(SignalProxy *proxy);
 
   bool isMyNick(const QString &nick) const;
-  bool isMyNick(IrcUser *ircuser) const;
+  bool isMe(IrcUser *ircuser) const;
 
   bool isChannelName(const QString &channelname) const;
 
@@ -66,8 +72,10 @@ public:
   QString networkName() const;
   QString currentServer() const;
   QString myNick() const;
+  IdentityId identity() const;
   QStringList nicks() const;
   QStringList channels() const;
+  QList<QVariantMap> serverList() const;
 
   QString prefixes();
   QString prefixModes();
@@ -80,19 +88,18 @@ public:
   IrcUser *ircUser(QString nickname) const;
   IrcUser *ircUser(const QByteArray &nickname) const;
   QList<IrcUser *> ircUsers() const;
+  quint32 ircUserCount() const;
 
   IrcChannel *newIrcChannel(const QString &channelname);
   IrcChannel *newIrcChannel(const QByteArray &channelname);
   IrcChannel *ircChannel(QString channelname);
   IrcChannel *ircChannel(const QByteArray &channelname);
-  
   QList<IrcChannel *> ircChannels() const;
+  quint32 ircChannelCount() const;
 
-  QTextCodec *codecForEncoding() const;
-  QTextCodec *codecForDecoding() const;
-  void setCodecForEncoding(const QString &codecName);
+  QByteArray codecForEncoding() const;
+  QByteArray codecForDecoding() const;
   void setCodecForEncoding(QTextCodec *codec);
-  void setCodecForDecoding(const QString &codecName);
   void setCodecForDecoding(QTextCodec *codec);
 
   QString decodeString(const QByteArray &text) const;
@@ -102,6 +109,12 @@ public slots:
   void setNetworkName(const QString &networkName);
   void setCurrentServer(const QString &currentServer);
   void setMyNick(const QString &mynick);
+  void setIdentity(IdentityId);
+
+  void setServerList(const QList<QVariantMap> &serverList);
+
+  void setCodecForEncoding(const QByteArray &codecName);
+  void setCodecForDecoding(const QByteArray &codecName);
 
   void addSupport(const QString &param, const QString &value = QString());
   void removeSupport(const QString &param);
@@ -111,11 +124,13 @@ public slots:
   
   //init geters
   QVariantMap initSupports() const;
+  QVariantList initServerList() const;
   QStringList initIrcUsers() const;
   QStringList initIrcChannels() const;
   
   //init seters
   void initSetSupports(const QVariantMap &supports);
+  void initSetServerList(const QVariantList &serverList);
   void initSetIrcUsers(const QStringList &hostmasks);
   void initSetChannels(const QStringList &channels);
   
@@ -124,34 +139,50 @@ public slots:
   // these slots are to keep the hashlists of all users and the
   // channel lists up to date
   void ircUserNickChanged(QString newnick);
-  void setInitialized();
+
+  void requestConnect();
 
 private slots:
   void ircUserDestroyed();
   void channelDestroyed();
   void removeIrcUser(IrcUser *ircuser);
-  
+  void ircUserInitDone();
+  void ircChannelInitDone();
+
 signals:
   void networkNameSet(const QString &networkName);
   void currentServerSet(const QString &currentServer);
   void myNickSet(const QString &mynick);
+  void identitySet(IdentityId);
+
+  void serverListSet(const QList<QVariantMap> &serverList);
+
+  void codecForEncodingSet(const QString &codecName);
+  void codecForDecodingSet(const QString &codecName);
 
   void supportAdded(const QString &param, const QString &value);
   void supportRemoved(const QString &param);
-  
-  void ircUserAdded(QString hostmask);
-  void ircChannelAdded(QString channelname);
 
-  void ircUserRemoved(QString nick);
-  
-  void initDone();
-  void ircUserInitDone();
-  void ircChannelInitDone();
-  
+  void ircUserAdded(const QString &hostmask);
+  void ircUserAdded(IrcUser *);
+  void ircChannelAdded(const QString &channelname);
+  void ircChannelAdded(IrcChannel *);
+
+  void ircUserRemoved(const QString &nick);
+
+  // needed for client sync progress
+  void ircUserRemoved(QObject *);
+  void ircChannelRemoved(QObject *);
+
+  void ircUserInitDone(IrcUser *);
+  void ircChannelInitDone(IrcChannel *);
+
+  void connectRequested(NetworkId = 0);
+
 private:
-  uint _networkId;
-  bool _initialized;
-  
+  NetworkId _networkId;
+  IdentityId _identity;
+
   QString _myNick;
   QString _networkName;
   QString _currentServer;
@@ -163,6 +194,7 @@ private:
   QHash<QString, IrcChannel *> _ircChannels; // stores all known channels
   QHash<QString, QString> _supports;  // stores results from RPL_ISUPPORT
 
+  QList<QVariantMap> _serverList;
   //QVariantMap networkSettings;
   //QVariantMap identity;
   
index e496479..204c197 100644 (file)
@@ -91,11 +91,11 @@ int SignalRelay::qt_metacall(QMetaObject::Call _c, int _id, void **_a) {
       // dispatch Sync Signal if necessary
       QByteArray signature(caller->metaObject()->method(_id).signature());
       if(synchronize() && proxy->syncMap(qobject_cast<SyncableObject *>(caller)).contains(signature)) {
-       // qDebug() << "__SYNC__ >>>"
-       //       << caller->metaObject()->className()
-       //       << caller->objectName()
-       //       << proxy->methodName(caller, _id)
-       //       << params;
+        //qDebug() << "__SYNC__ >>>"
+        //      << caller->metaObject()->className()
+        //      << caller->objectName()
+        //      << signature
+        //      << params;
        // params.prepend(QVariant(_id));
        params.prepend(signature);
        params.prepend(caller->objectName());
@@ -131,10 +131,10 @@ bool SignalRelay::isSyncMethod(int i) {
   if(!proxy->syncMap(qobject_cast<SyncableObject *>(caller)).contains(signature))
     return false;
   
-  if(proxy->proxyMode() == SignalProxy::Server && !signature.startsWith("request"))
+  if(proxy->proxyMode() == SignalProxy::Server && !signature.contains("Requested"))
     return true;
 
-  if(proxy->proxyMode() == SignalProxy::Client && signature.startsWith("request"))
+  if(proxy->proxyMode() == SignalProxy::Client && signature.contains("Requested"))
     return true;
 
   return false;
@@ -338,12 +338,6 @@ const QList<int> &SignalProxy::argTypes(QObject *obj, int methodId) {
   return _classInfo[obj->metaObject()]->argTypes[methodId];
 }
 
-bool SignalProxy::hasUpdateSignal(QObject *obj) {
-  if(!_classInfo.contains(obj->metaObject()))
-    return false;
-  return _classInfo[obj->metaObject()]->hasUpdateSignal;
-}
-
 void SignalProxy::setMethodName(QObject *obj, int methodId) {
   const QMetaObject *meta = obj->metaObject();
   QByteArray method(::methodName(meta->method(methodId)));
@@ -406,7 +400,6 @@ void SignalProxy::createClassInfo(QObject *obj) {
     return;
 
   ClassInfo *classInfo = new ClassInfo();
-  classInfo->hasUpdateSignal = (obj->metaObject()->indexOfSignal(QMetaObject::normalizedSignature("updatedRemotely()")) != -1);
   _classInfo[obj->metaObject()] = classInfo;
 }
 
@@ -478,18 +471,16 @@ void SignalProxy::synchronize(SyncableObject *obj) {
 }
 
 void SignalProxy::setInitialized(SyncableObject *obj) {
-  QMetaObject::invokeMethod(obj, "setInitialized");
+  obj->setInitialized();
+  emit objectInitialized(obj);
 }
 
-bool SignalProxy::initialized(SyncableObject *obj) {
-  bool init;
-  if(!QMetaObject::invokeMethod(obj, "initialized", Q_RETURN_ARG(bool, init)))
-    init = false;
-  return init;
+bool SignalProxy::isInitialized(SyncableObject *obj) const {
+  return obj->isInitialized();
 }
 
 void SignalProxy::requestInit(SyncableObject *obj) {
-  if(proxyMode() == Server || initialized(obj))
+  if(proxyMode() == Server || isInitialized(obj))
     return;
 
   QVariantList params;
@@ -634,8 +625,7 @@ void SignalProxy::handleSync(QVariantList params) {
     qWarning("SignalProxy::handleSync(): invokeMethod for \"%s\" failed ", methodName(receiver, slotId).constData());
     return;
   }
-  if(hasUpdateSignal(receiver))
-    QMetaObject::invokeMethod(receiver, "updatedRemotely");
+  QMetaObject::invokeMethod(receiver, "updatedRemotely");
 }
 
 void SignalProxy::handleInitRequest(QIODevice *sender, const QVariantList &params) {
@@ -798,7 +788,7 @@ QVariantMap SignalProxy::initData(SyncableObject *obj) const {
 }
 
 void SignalProxy::setInitData(SyncableObject *obj, const QVariantMap &properties) {
-  if(initialized(obj))
+  if(isInitialized(obj))
     return;
   obj->fromVariantMap(properties);
   setInitialized(obj);
index 1a8dfac..d9871a2 100644 (file)
@@ -67,7 +67,7 @@ public:
   void synchronize(SyncableObject *obj);
 
   void setInitialized(SyncableObject *obj);
-  bool initialized(SyncableObject *obj);
+  bool isInitialized(SyncableObject *obj) const;
   void requestInit(SyncableObject *obj);
 
   void detachObject(QObject *obj);
@@ -89,9 +89,8 @@ public:
   static bool readDataFromDevice(QIODevice *dev, quint32 &blockSize, QVariant &item);
 
   static QString methodBaseName(const QMetaMethod &method);
-  
+
   const QList<int> &argTypes(QObject *obj, int methodId);
-  bool hasUpdateSignal(QObject *obj);
   const QByteArray &methodName(QObject *obj, int methodId);
   const QHash<QByteArray, int> &syncMap(SyncableObject *obj);
 
@@ -101,7 +100,6 @@ public:
     ArgHash argTypes;
     MethodNameHash methodNames;
     QHash<QByteArray, int> syncMap;
-    bool hasUpdateSignal;
   };
 
   void dumpProxyStats();
@@ -117,6 +115,7 @@ signals:
   void peerRemoved(QIODevice *obj);
   void connected();
   void disconnected();
+  void objectInitialized(SyncableObject *);
   
 private:
   void initServer();
@@ -147,7 +146,9 @@ private:
   void _detachSlots(QObject *receiver);
   void _stopSync(SyncableObject *obj);
 
+  public:
   void dumpSyncMap(SyncableObject *object);
+  private:
 
   // Hash of used QIODevices
   QHash<QIODevice*, quint32> _peerByteCount;
index dc202e2..668f61c 100644 (file)
 #include "util.h"
 
 SyncableObject::SyncableObject(QObject *parent) : QObject(parent) {
-
+  _initialized = false;
 }
 
 SyncableObject::SyncableObject(const SyncableObject &other, QObject *parent) : QObject(parent) {
-  Q_UNUSED(other);
+  _initialized = other._initialized;
+
+}
+
+bool SyncableObject::isInitialized() const {
+  return _initialized;
+}
 
+void SyncableObject::setInitialized() {
+  _initialized = true;
+  emit initDone();
 }
 
 QVariantMap SyncableObject::toVariantMap() {
index 4ce8c91..04ba44b 100644 (file)
@@ -37,10 +37,11 @@ class SyncableObject : public QObject {
     /** The default implementation takes dynamic properties as well as getters that have
      *  names starting with "init" and stores them in a QVariantMap. Override this method in
      *  derived classes in order to store the object state in a custom form.
-     *  \Note: This is used by SignalProxy to transmit the state of the object to clients
+     *  \note  This is used by SignalProxy to transmit the state of the object to clients
      *         that request the initial object state. Later updates use a different mechanism
      *         and assume that the state is completely covered by properties and init* getters.
      *         DO NOT OVERRIDE THIS unless you know exactly what you do!
+     *
      *  \return The object's state in a QVariantMap
      */
     virtual QVariantMap toVariantMap();
@@ -50,9 +51,20 @@ class SyncableObject : public QObject {
      */
     virtual void fromVariantMap(const QVariantMap &map);
 
+    virtual bool isInitialized() const;
+
+  public slots:
+    virtual void setInitialized();
+
+  signals:
+    void initDone();
+    void updatedRemotely();
+
   private:
     bool setInitValue(const QString &property, const QVariant &value);
 
+    bool _initialized;
+
 };
 
 #endif
index 528f60d..9354620 100644 (file)
@@ -38,7 +38,7 @@ bool isChannelName(QString str);
 /** This function takes a string and first checks if it is encoded in utf8, in which case it is
  *  decoded appropriately. Otherwise, the specified text codec is used to transform the string.
  *  \param input The input string containing encoded data
- *  \param encoding The text codec we use if the input is not utf8
+ *  \param codec The text codec we use if the input is not utf8
  *  \return The decoded string.
  */
 QString decodeString(const QByteArray &input, QTextCodec *codec = 0);
index 7da0aee..3233798 100644 (file)
  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
  ***************************************************************************/
 
+#include <QMetaObject>
+#include <QMetaMethod>
+#include <QMutexLocker>
+#include <QCoreApplication>
+
 #include "core.h"
 #include "coresession.h"
 #include "coresettings.h"
 #include "signalproxy.h"
 #include "sqlitestorage.h"
 
-#include <QMetaObject>
-#include <QMetaMethod>
-
-#include <QCoreApplication>
-
 Core *Core::instanceptr = 0;
+QMutex Core::mutex;
 
 Core *Core::instance() {
   if(instanceptr) return instanceptr;
@@ -46,71 +47,17 @@ void Core::destroy() {
 Core::Core()
   : storage(0)
 {
+  startTime = QDateTime::currentDateTime();  // for uptime :)
 }
 
 void Core::init() {
-  // TODO: Remove this again at some point
-  // Check if old core settings need to be migrated in order to make the switch to the
-  // new location less painful.
-  CoreSettings cs;
-  QVariant foo = cs.databaseSettings();
-  
-  if(!foo.isValid()) {
-    // ok, no settings stored yet. check for old ones.
-#ifdef Q_WS_MAC
-    QSettings os("quassel-irc.org", "Quassel IRC", this);
-#else
-    QSettings os("Quassel IRC Development Team", "Quassel IRC");
-#endif
-    QVariant bar = os.value("Core/DatabaseSettings");
-    if(bar.isValid()) {
-      // old settings available -- migrate!
-      qWarning() << "\n\nOld settings detected. Will migrate core settings to the new location...\nNOTE: GUI style settings won't be migrated!\n";
-#ifdef Q_WS_MAC
-      QSettings ncs("quassel-irc.org", "Quassel Core");
-#else
-      QSettings ncs("Quassel Project", "Quassel Core");
-#endif
-      ncs.setValue("Core/CoreState", os.value("Core/CoreState"));
-      ncs.setValue("Core/DatabaseSettings", os.value("Core/DatabaseSettings"));
-      os.beginGroup("SessionData");
-      foreach(QString group, os.childGroups()) {
-        ncs.setValue(QString("CoreUser/%1/SessionData/Identities").arg(group), os.value(QString("%1/Identities").arg(group)));
-        ncs.setValue(QString("CoreUser/%1/SessionData/Networks").arg(group), os.value(QString("%1/Networks").arg(group)));
-      }
-      os.endGroup();
-#ifdef Q_WS_MAC
-      QSettings ngs("quassel-irc.org", "Quassel Client");
-#else
-      QSettings ngs("Quassel Project", "Quassel Client");
-#endif
-      os.beginGroup("Accounts");
-      foreach(QString key, os.childKeys()) {
-        ngs.setValue(QString("Accounts/%1").arg(key), os.value(key));
-      }
-      foreach(QString group, os.childGroups()) {
-        ngs.setValue(QString("Accounts/%1/AccountData").arg(group), os.value(QString("%1/AccountData").arg(group)));
-      }
-      os.endGroup();
-      os.beginGroup("Geometry");
-      foreach(QString key, os.childKeys()) {
-        ngs.setValue(QString("UI/%1").arg(key), os.value(key));
-      }
-      os.endGroup();
-
-      ncs.sync();
-      ngs.sync();
-      qWarning() << "Migration successfully finished. You may now delete $HOME/.config/Quassel IRC Development Team/ (on Linux).\n\n";
-    }
-  }
-  // END
-
   configured = false;
 
+  CoreSettings cs;
   if(!(configured = initStorage(cs.databaseSettings().toMap()))) {
     qWarning("Core is currently not configured!");
   }
-  
+
   connect(&server, SIGNAL(newConnection()), this, SLOT(incomingConnection()));
   startListening(cs.port());
   guiUser = 0;
@@ -129,6 +76,7 @@ bool Core::initStorage(QVariantMap dbSettings, bool setup) {
   // FIXME register new storageProviders here
   if(engine == "sqlite" && SqliteStorage::isAvailable()) {
     storage = new SqliteStorage(this);
+    connect(storage, SIGNAL(bufferInfoUpdated(UserId, const BufferInfo &)), this, SIGNAL(bufferInfoUpdated(UserId, const BufferInfo &)));
   } else {
     qWarning() << "Selected StorageBackend is not available:" << dbSettings["Type"].toString();
     return configured = false;
@@ -141,15 +89,14 @@ bool Core::initStorage(QVariantMap dbSettings, bool setup) {
   return configured = storage->init(dbSettings);
 }
 
-bool Core::initStorage(QVariantMap dbSettings) {
-  return initStorage(dbSettings, false);
-}
-
 Core::~Core() {
+  // FIXME properly shutdown the sessions
   qDeleteAll(sessions);
 }
 
 void Core::restoreState() {
+  return;
+  /*
   Q_ASSERT(!instance()->sessions.count());
   CoreSettings s;
   QList<QVariant> users = s.coreState().toList();
@@ -159,45 +106,67 @@ void Core::restoreState() {
       QVariantMap m = v.toMap();
       if(m.contains("UserId")) {
         CoreSession *sess = createSession(m["UserId"].toUInt());
-        sess->restoreState(m["State"]);
+        sess->restoreState(m["State"]);  // FIXME multithreading
       }
     }
     qDebug() << "...done.";
   }
+  */
 }
 
 void Core::saveState() {
+  /*
   CoreSettings s;
   QList<QVariant> users;
   foreach(CoreSession *sess, instance()->sessions.values()) {
     QVariantMap m;
-    m["UserId"] = sess->userId();
+    m["UserId"] = sess->user();  // FIXME multithreading
     m["State"] = sess->state();
     users << m;
   }
   s.setCoreState(users);
+  */
+}
+
+/*** Storage Access ***/
+
+NetworkId Core::networkId(UserId user, const QString &network) {
+  QMutexLocker locker(&mutex);
+  return instance()->storage->getNetworkId(user, network);
 }
 
-CoreSession *Core::session(UserId uid) {
-  Core *core = instance();
-  if(core->sessions.contains(uid)) return core->sessions[uid];
-  else return 0;
+BufferInfo Core::bufferInfo(UserId user, const QString &network, const QString &buffer) {
+  //QMutexLocker locker(&mutex);
+  return instance()->storage->getBufferInfo(user, network, buffer);
 }
 
-CoreSession *Core::localSession() {
-  Core *core = instance();
-  if(core->guiUser && core->sessions.contains(core->guiUser)) return core->sessions[core->guiUser];
-  else return 0;
+MsgId Core::storeMessage(const Message &message) {
+  QMutexLocker locker(&mutex);
+  return instance()->storage->logMessage(message);
 }
 
-CoreSession *Core::createSession(UserId uid) {
-  Core *core = instance();
-  Q_ASSERT(!core->sessions.contains(uid));
-  CoreSession *sess = new CoreSession(uid, core->storage);
-  core->sessions[uid] = sess;
-  return sess;
+QList<Message> Core::requestMsgs(BufferInfo buffer, int lastmsgs, int offset) {
+  QMutexLocker locker(&mutex);
+  return instance()->storage->requestMsgs(buffer, lastmsgs, offset);
+}
+
+QList<Message> Core::requestMsgs(BufferInfo buffer, QDateTime since, int offset) {
+  QMutexLocker locker(&mutex);
+  return instance()->storage->requestMsgs(buffer, since, offset);
+}
+
+QList<Message> Core::requestMsgRange(BufferInfo buffer, int first, int last) {
+  QMutexLocker locker(&mutex);
+  return instance()->storage->requestMsgRange(buffer, first, last);
+}
+
+QList<BufferInfo> Core::requestBuffers(UserId user, QDateTime since) {
+  QMutexLocker locker(&mutex);
+  return instance()->storage->requestBuffers(user, since);
 }
 
+/*** Network Management ***/
+
 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());
@@ -218,9 +187,10 @@ void Core::incomingConnection() {
     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();
-    
+    QVariantMap clientInfo;
+    blocksizes.insert(socket, (quint32)0);
+    qDebug() << "Client connected from"  << qPrintable(socket->peerAddress().toString());
+
     if (!configured) {
       server.close();
       qDebug() << "Closing server for basic setup.";
@@ -230,10 +200,73 @@ void Core::incomingConnection() {
 
 void Core::clientHasData() {
   QTcpSocket *socket = dynamic_cast<QTcpSocket*>(sender());
-  Q_ASSERT(socket && blockSizes.contains(socket));
-  quint32 bsize = blockSizes.value(socket);
+  Q_ASSERT(socket && blocksizes.contains(socket));
   QVariant item;
-  if(SignalProxy::readDataFromDevice(socket, bsize, item)) {
+  while(SignalProxy::readDataFromDevice(socket, blocksizes[socket], item)) {
+    QVariantMap msg = item.toMap();
+    if(!msg.contains("MsgType")) {
+      // Client is way too old, does not even use the current init format
+      qWarning() << qPrintable(tr("Antique client trying to connect... refusing."));
+      socket->close();
+      return;
+    }
+    // OK, so we have at least an init message format we can understand
+    if(msg["MsgType"] == "ClientInit") {
+      QVariantMap reply;
+      reply["CoreVersion"] = Global::quasselVersion;
+      reply["CoreDate"] = Global::quasselDate;
+      reply["CoreBuild"] = Global::quasselBuild;
+      // TODO: Make the core info configurable
+      int uptime = startTime.secsTo(QDateTime::currentDateTime());
+      int updays = uptime / 86400; uptime %= 86400;
+      int uphours = uptime / 3600; uptime %= 3600;
+      int upmins = uptime / 60;
+      reply["CoreInfo"] = tr("<b>Quassel Core Version %1 (Build >= %2)</b><br>"
+                             "Up %3d%4h%5m (since %6)").arg(Global::quasselVersion).arg(Global::quasselBuild)
+                             .arg(updays).arg(uphours,2,10,QChar('0')).arg(upmins,2,10,QChar('0')).arg(startTime.toString(Qt::TextDate));
+
+      reply["SupportSsl"] = false;
+      reply["LoginEnabled"] = true;
+      // TODO: check if we are configured, start wizard otherwise
+
+      // Just version information -- check it!
+      if(msg["ClientBuild"].toUInt() < Global::clientBuildNeeded) {
+        reply["MsgType"] = "ClientInitReject";
+        reply["Error"] = tr("<b>Your Quassel Client is too old!</b><br>"
+                            "This core needs at least client version %1 (Build >= %2).<br>"
+                            "Please consider upgrading your client.").arg(Global::quasselVersion).arg(Global::quasselBuild);
+        SignalProxy::writeDataToDevice(socket, reply);
+        qWarning() << qPrintable(tr("Client %1 too old, rejecting.").arg(socket->peerAddress().toString()));
+        socket->close(); return;
+      }
+      clientInfo[socket] = msg; // store for future reference
+      reply["MsgType"] = "ClientInitAck";
+      SignalProxy::writeDataToDevice(socket, reply);
+    } else if(msg["MsgType"] == "ClientLogin") {
+      QVariantMap reply;
+      if(!clientInfo.contains(socket)) {
+        reply["MsgType"] = "ClientLoginReject";
+        reply["Error"] = tr("<b>Client not initialized!</b><br>You need to send an init message before trying to login.");
+        SignalProxy::writeDataToDevice(socket, reply);
+        qWarning() << qPrintable(tr("Client %1 did not send an init message before trying to login, rejecting.").arg(socket->peerAddress().toString()));
+        socket->close(); return;
+      }
+      mutex.lock();
+      UserId uid = storage->validateUser(msg["User"].toString(), msg["Password"].toString());
+      mutex.unlock();
+      if(!uid) {
+        reply["MsgType"] = "ClientLoginReject";
+        reply["Error"] = tr("<b>Invalid username or password!</b><br>The username/password combination you supplied could not be found in the database.");
+        SignalProxy::writeDataToDevice(socket, reply);
+        continue;
+      }
+      reply["MsgType"] = "ClientLoginAck";
+      SignalProxy::writeDataToDevice(socket, reply);
+      qDebug() << qPrintable(tr("Client %1 initialized and authentificated successfully as \"%2\".").arg(socket->peerAddress().toString(), msg["User"].toString()));
+      setupClientSession(socket, uid);
+    }
+    //socket->close(); return;
+    /*
     // we need to auth the client
     try {
       QVariantMap msg = item.toMap();
@@ -253,50 +286,36 @@ void Core::clientHasData() {
       qWarning() << "Client init error:" << e.msg();
       socket->close();
       return;
-    }
+    } */
   }
-  blockSizes[socket] = bsize = 0;  // FIXME blockSizes aufr´┐Żum0rn!
 }
 
-// FIXME: no longer called, since connection handling is now in SignalProxy
-// No, it is called as long as core is not configured. (kaffeedoktor)
+// Potentially called during the initialization phase (before handing the connection off to the session)
 void Core::clientDisconnected() {
   QTcpSocket *socket = dynamic_cast<QTcpSocket*>(sender());
-  blockSizes.remove(socket);
-  qDebug() << "Client disconnected.";
-  
-  // make server listen again if still not configured
+  blocksizes.remove(socket);
+  clientInfo.remove(socket);
+  qDebug() << qPrintable(tr("Client %1 disconnected.").arg(socket->peerAddress().toString()));
+  socket->deleteLater();
+  socket = 0;
+
+  // make server listen again if still not configured  FIXME
   if (!configured) {
     startListening();
   }
-  
-  // TODO remove unneeded sessions - if necessary/possible...
-}
-
-QVariant Core::connectLocalClient(QString user, QString passwd) {
-  UserId uid = instance()->storage->validateUser(user, passwd);
-  QVariant reply = instance()->initSession(uid);
-  instance()->guiUser = uid;
-  qDebug() << "Local client connected.";
-  return reply;
-}
 
-void Core::disconnectLocalClient() {
-  qDebug() << "Local client disconnected.";
-  instance()->guiUser = 0;
+  // TODO remove unneeded sessions - if necessary/possible...
+  // Suggestion: kill sessions if they are not connected to any network and client.
 }
 
-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);
+  
+  //disconnect(socket, 0, this, 0);
+  /*
+  sessions[uid]->addClient(socket);  // FIXME multithreading
   qDebug() << "Client initialized successfully.";
   SignalProxy::writeDataToDevice(socket, reply);
-}
+  */
+
 
 void Core::processCoreSetup(QTcpSocket *socket, QVariantMap &msg) {
   if(msg["HasSettings"].toBool()) {
@@ -322,7 +341,7 @@ void Core::processCoreSetup(QTcpSocket *socket, QVariantMap &msg) {
       storage->addUser(auth["User"].toString(), auth["Password"].toString());
       startListening();
       // continue the normal procedure
-      processClientInit(socket, auth);
+      //processClientInit(socket, auth);
     }
   } else {
     // notify client to start wizard
@@ -333,16 +352,29 @@ void Core::processCoreSetup(QTcpSocket *socket, QVariantMap &msg) {
   }
 }
 
-QVariant Core::initSession(UserId uid) {
+void Core::setupClientSession(QTcpSocket *socket, UserId uid) {
   // Find or create session for validated user
-  CoreSession *sess;
-  if(sessions.contains(uid))
-    sess = sessions[uid];
-  else
-    sess = createSession(uid);
-  QVariantMap reply;
-  reply["SessionState"] = sess->sessionState();
-  return reply;
+  SessionThread *sess;
+  if(sessions.contains(uid)) sess = sessions[uid];
+  else sess = createSession(uid);
+  // Hand over socket, session then sends state itself
+  disconnect(socket, 0, this, 0);
+  if(!sess) {
+    qWarning() << qPrintable(tr("Could not initialize session for client %1!").arg(socket->peerAddress().toString()));
+    socket->close();
+  }
+  sess->addClient(socket);
+}
+
+SessionThread *Core::createSession(UserId uid) {
+  if(sessions.contains(uid)) {
+    qWarning() << "Calling createSession() when a session for the user already exists!";
+    return 0;
+  }
+  SessionThread *sess = new SessionThread(uid, this);
+  sessions[uid] = sess;
+  sess->start();
+  return sess;
 }
 
 QStringList Core::availableStorageProviders() {
index ae39dc1..7669317 100644 (file)
 #ifndef _CORE_H_
 #define _CORE_H_
 
+#include <QDateTime>
+#include <QMutex>
 #include <QString>
 #include <QVariant>
 #include <QTcpServer>
 #include <QTcpSocket>
 
+#include "bufferinfo.h"
+#include "message.h"
 #include "global.h"
+#include "sessionthread.h"
 #include "types.h"
 
 class CoreSession;
+class SessionThread;
 class Storage;
 
 class Core : public QObject {
@@ -39,16 +45,85 @@ class Core : public QObject {
     static Core * instance();
     static void destroy();
 
-    static CoreSession * session(UserId);
-    static CoreSession * localSession();
-    static CoreSession * createSession(UserId);
-
-    static QVariant connectLocalClient(QString user, QString passwd);
-    static void disconnectLocalClient();
-
     static void saveState();
     static void restoreState();
 
+    /*** Storage access ***/
+    // These methods are threadsafe.
+
+    //! Get the NetworkId for a network name.
+    /** \note This method is threadsafe.
+     *
+     *  \param user    The core user
+     *  \param network The name of the network
+     *  \return The NetworkId corresponding to the given network.
+     */
+    static NetworkId networkId(UserId user, const QString &network);
+
+    //! Get the unique BufferInfo for the given combination of network and buffername for a user.
+    /** \note This method is threadsafe.
+     *
+     *  \param user    The core user who owns this buffername
+     *  \param network The network name
+     *  \param buffer  The buffer name (if empty, the net's status buffer is returned)
+     *  \return The BufferInfo corresponding to the given network and buffer name, or 0 if not found
+     */
+    static BufferInfo bufferInfo(UserId user, const QString &network, const QString &buffer = "");
+
+    //! Store a Message in the backlog.
+    /** \note This method is threadsafe.
+     *
+     *  \param msg  The message object to be stored
+     *  \return The globally unique id for the stored message
+     */
+    static MsgId storeMessage(const Message &message);
+
+    //! Request a certain number (or all) messages stored in a given buffer.
+    /** \note This method is threadsafe.
+     *
+     *  \param buffer   The buffer we request messages from
+     *  \param lastmsgs The number of messages we would like to receive, or -1 if we'd like all messages from that buffername
+     *  \param offset   Do not return (but DO count) messages with MsgId >= offset, if offset >= 0
+     *  \return The requested list of messages
+     */
+    static QList<Message> requestMsgs(BufferInfo buffer, int lastmsgs = -1, int offset = -1);
+
+    //! Request messages stored in a given buffer since a certain point in time.
+    /** \note This method is threadsafe.
+     *
+     *  \param buffer   The buffer we request messages from
+     *  \param since    Only return messages newer than this point in time
+     *  \param offset   Do not return messages with MsgId >= offset, if offset >= 0
+     *  \return The requested list of messages
+     */
+    static QList<Message> requestMsgs(BufferInfo buffer, QDateTime since, int offset = -1);
+
+    //! Request a range of messages stored in a given buffer.
+    /** \note This method is threadsafe.
+     *
+     *  \param buffer   The buffer we request messages from
+     *  \param first    Return messages with first <= MsgId <= last
+     *  \param last     Return messages with first <= MsgId <= last
+     *  \return The requested list of messages
+     */
+    static QList<Message> requestMsgRange(BufferInfo buffer, int first, int last);
+
+    //! Request a list of all buffers known to a user since a certain point in time.
+    /** This method is used to get a list of all buffers we have stored a backlog from.
+     *  Optionally, a QDateTime can be given, so that only buffers are listed that were active
+     *  since that point in time.
+     *  \note This method is threadsafe.
+     *
+     *  \param user  The user whose buffers we request
+     *  \param since If this is defined, older buffers will be ignored
+     *  \return A list of the BufferInfos for all buffers as requested
+     */
+    static QList<BufferInfo> requestBuffers(UserId user, QDateTime since = QDateTime());
+
+  signals:
+    //! Sent when a BufferInfo is updated in storage.
+    void bufferInfoUpdated(UserId user, const BufferInfo &info);
+
   private slots:
     bool startListening(uint port = Global::defaultPort);
     void stopListening();
@@ -56,35 +131,33 @@ class Core : public QObject {
     void clientHasData();
     void clientDisconnected();
 
-    bool initStorage(QVariantMap dbSettings, bool setup);
-    bool initStorage(QVariantMap dbSettings);
+    bool initStorage(QVariantMap dbSettings, bool setup = false);
 
   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.
-     * \param userId The user
-     * \return A QVariant containing the session data, e.g. global data and buffers
-     */
-    QVariant initSession(UserId userId);
-    void processClientInit(QTcpSocket *socket, const QVariantMap &msg);
+
+    SessionThread *createSession(UserId userId);
+    void setupClientSession(QTcpSocket *socket, UserId uid);
     void processCoreSetup(QTcpSocket *socket, QVariantMap &msg);
-    
+
     QStringList availableStorageProviders();
 
     UserId guiUser;
-    QHash<UserId, CoreSession *> sessions;
+    QHash<UserId, SessionThread *> sessions;
     Storage *storage;
 
     QTcpServer server; // TODO: implement SSL
-    QHash<QTcpSocket *, quint32> blockSizes;
-    
+    QHash<QTcpSocket *, quint32> blocksizes;
+    QHash<QTcpSocket *, QVariantMap> clientInfo;
+
+    QDateTime startTime;
+
     bool configured;
+
+    static QMutex mutex;
 };
 
 #endif
index 352858b..8d71feb 100644 (file)
@@ -1,6 +1,6 @@
 DEPMOD = common
 QT_MOD = core network sql script
 SRCS = core.cpp coresession.cpp coresettings.cpp networkconnection.cpp sqlitestorage.cpp abstractsqlstorage.cpp storage.cpp basichandler.cpp \
-       ircserverhandler.cpp userinputhandler.cpp ctcphandler.cpp coreusersettings.cpp
+       ircserverhandler.cpp userinputhandler.cpp ctcphandler.cpp coreusersettings.cpp sessionthread.cpp
 HDRS = core.h coresession.h coresettings.h networkconnection.h sqlitestorage.h abstractsqlstorage.h storage.h basichandler.h \
-       ircserverhandler.h userinputhandler.h ctcphandler.h coreusersettings.h
+       ircserverhandler.h userinputhandler.h ctcphandler.h coreusersettings.h sessionthread.h
index 2b484b3..2d2c67e 100644 (file)
@@ -18,6 +18,7 @@
  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
  ***************************************************************************/
 
+#include "core.h"
 #include "coresession.h"
 #include "networkconnection.h"
 
 
 #include <QtScript>
 
-CoreSession::CoreSession(UserId uid, Storage *_storage, QObject *parent)
-  : QObject(parent),
-    user(uid),
+CoreSession::CoreSession(UserId uid, QObject *parent) : QObject(parent),
+    _user(uid),
     _signalProxy(new SignalProxy(SignalProxy::Server, 0, this)),
-    storage(_storage),
     scriptEngine(new QScriptEngine(this))
 {
 
   SignalProxy *p = signalProxy();
 
-  CoreUserSettings s(user);
+  CoreUserSettings s(user());
   sessionData = s.sessionData();
 
   foreach(IdentityId id, s.identityIds()) {
@@ -69,15 +68,15 @@ CoreSession::CoreSession(UserId uid, Storage *_storage, QObject *parent)
     createIdentity(i);
   }
 
-  p->attachSlot(SIGNAL(requestNetworkStates()), this, SLOT(networkStateRequested()));
+  //p->attachSlot(SIGNAL(requestNetworkStates()), this, SLOT(networkStateRequested()));
   p->attachSlot(SIGNAL(requestConnect(QString)), this, SLOT(connectToNetwork(QString)));
-  p->attachSlot(SIGNAL(sendInput(BufferInfo, QString)), this, SLOT(msgFromGui(BufferInfo, QString)));
+  p->attachSlot(SIGNAL(sendInput(BufferInfo, QString)), this, SLOT(msgFromClient(BufferInfo, QString)));
   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)));
   p->attachSignal(this, SIGNAL(backlogData(BufferInfo, QVariantList, bool)));
   p->attachSignal(this, SIGNAL(bufferInfoUpdated(BufferInfo)));
-  p->attachSignal(storage, SIGNAL(bufferInfoUpdated(BufferInfo)));
+
   p->attachSignal(this, SIGNAL(sessionDataChanged(const QString &, const QVariant &)), SIGNAL(coreSessionDataChanged(const QString &, const QVariant &)));
   p->attachSlot(SIGNAL(clientSessionDataChanged(const QString &, const QVariant &)), this, SLOT(storeSessionData(const QString &, const QVariant &)));
 
@@ -92,17 +91,56 @@ CoreSession::CoreSession(UserId uid, Storage *_storage, QObject *parent)
   foreach(Identity *id, _identities.values()) {
     p->synchronize(id);
   }
+
+  // Load and init networks.
+  // FIXME For now we use the old info from sessionData...
+
+  QVariantMap networks = retrieveSessionData("Networks").toMap();
+  foreach(QString netname, networks.keys()) {
+    QVariantMap network = networks[netname].toMap();
+    NetworkId netid = Core::networkId(user(), netname);
+    Network *net = new Network(netid, this);
+    connect(net, SIGNAL(connectRequested(NetworkId)), this, SLOT(connectToNetwork(NetworkId)));
+    net->setNetworkName(netname);
+    net->setIdentity(1); // FIXME default identity for now
+    net->setCodecForEncoding("ISO-8859-15"); // FIXME
+    net->setCodecForDecoding("ISO-8859-15"); // FIXME
+    QList<QVariantMap> slist;
+    foreach(QVariant v, network["Servers"].toList()) slist << v.toMap();
+    net->setServerList(slist);
+    net->setProxy(p);
+    _networks[netid] = net;
+    p->synchronize(net);
+  }
+
+  emit initialized();
 }
 
 CoreSession::~CoreSession() {
 }
 
-UserId CoreSession::userId() const {
-  return user;
+UserId CoreSession::user() const {
+  return _user;
+}
+
+Network *CoreSession::network(NetworkId id) const {
+  if(_networks.contains(id)) return _networks[id];
+  return 0;
+}
+
+NetworkConnection *CoreSession::networkConnection(NetworkId id) const {
+  if(_connections.contains(id)) return _connections[id];
+  return 0;
+}
+
+Identity *CoreSession::identity(IdentityId id) const {
+  if(_identities.contains(id)) return _identities[id];
+  return 0;
 }
 
-QVariant CoreSession::state() const {
+QVariant CoreSession::state() const { // FIXME
   QVariantMap res;
+  /*
   QList<QVariant> conn;
   foreach(NetworkConnection *net, connections.values()) {
     if(net->isConnected()) {
@@ -113,11 +151,13 @@ QVariant CoreSession::state() const {
     }
   }
   res["ConnectedServers"] = conn;
+  */
   return res;
 }
 
-void CoreSession::restoreState(const QVariant &previousState) {
+void CoreSession::restoreState(const QVariant &previousState) { // FIXME
   // Session restore
+  /*
   QVariantMap state = previousState.toMap();
   if(state.contains("ConnectedServers")) {
     foreach(QVariant v, state["ConnectedServers"].toList()) {
@@ -126,66 +166,90 @@ void CoreSession::restoreState(const QVariant &previousState) {
       if(!net.isEmpty()) connectToNetwork(net, m["State"]);
     }
   }
+  */
 }
 
 
 void CoreSession::storeSessionData(const QString &key, const QVariant &data) {
-  CoreUserSettings s(user);
-  mutex.lock();
+  CoreUserSettings s(user());
   s.setSessionValue(key, data);
   sessionData[key] = data;
-  mutex.unlock();
   emit sessionDataChanged(key, data);
   emit sessionDataChanged(key);
 }
 
 QVariant CoreSession::retrieveSessionData(const QString &key, const QVariant &def) {
   QVariant data;
-  mutex.lock();
   if(!sessionData.contains(key)) data = def;
   else data = sessionData[key];
-  mutex.unlock();
   return data;
 }
 
-// FIXME switch to NetworkIDs
-void CoreSession::connectToNetwork(QString networkname, const QVariant &previousState) {
-  uint networkid = getNetworkId(networkname);
-  if(networkid == 0) {
-    qWarning() << "unable to connect to Network" << networkname << "(User:" << userId() << "): unable to determine NetworkId";
+void CoreSession::updateBufferInfo(UserId uid, const BufferInfo &bufinfo) {
+  if(uid == user()) emit bufferInfoUpdated(bufinfo);
+}
+
+// FIXME remove
+void CoreSession::connectToNetwork(QString netname, const QVariant &previousState) {
+  Network *net = 0;
+  foreach(Network *n, _networks.values()) {
+    if(n->networkName() == netname) {
+      net = n; break;
+    }
+  }
+  if(!net) {
+    qWarning() << "Connect to unknown network requested, ignoring!";
+    return;
+  }
+  connectToNetwork(net->networkId(), previousState);
+}
+
+void CoreSession::connectToNetwork(NetworkId id, const QVariant &previousState) {
+  Network *net = network(id);
+  if(!net) {
+    qWarning() << "Connect to unknown network requested! net:" << id << "user:" << user();
     return;
   }
-  if(!connections.contains(networkid)) {
-    NetworkConnection *connection = new NetworkConnection(userId(), networkid, networkname, previousState);
-    connections[networkid] = connection;
-    attachNetworkConnection(connection);
-    connection->start();
+
+  NetworkConnection *conn = networkConnection(id);
+  if(!conn) {
+    conn = new NetworkConnection(net, this, previousState);
+    _connections[id] = conn;
+    attachNetworkConnection(conn);
+    conn->connectToIrc();
   }
-  emit connectToIrc(networkname);
 }
 
-void CoreSession::attachNetworkConnection(NetworkConnection *network) {
-  connect(this, SIGNAL(connectToIrc(QString)), network, SLOT(connectToIrc(QString)));
-  connect(this, SIGNAL(disconnectFromIrc(QString)), network, SLOT(disconnectFromIrc(QString)));
-  connect(this, SIGNAL(msgFromGui(uint, QString, QString)), network, SLOT(userInput(uint, QString, QString)));
-  
-  connect(network, SIGNAL(connected(uint)), this, SLOT(networkConnected(uint)));
-  connect(network, SIGNAL(disconnected(uint)), this, SLOT(networkDisconnected(uint)));
-  connect(network, SIGNAL(displayMsg(Message::Type, QString, QString, QString, quint8)), this, SLOT(recvMessageFromServer(Message::Type, QString, QString, QString, quint8)));
-  connect(network, SIGNAL(displayStatusMsg(QString)), this, SLOT(recvStatusMsgFromServer(QString)));
-
-  // connect serversignals to proxy
-  signalProxy()->attachSignal(network, SIGNAL(networkState(QString, QVariantMap)), SIGNAL(networkState(QString, QVariantMap)));
-  signalProxy()->attachSignal(network, SIGNAL(connected(uint)), SIGNAL(networkConnected(uint)));
-  signalProxy()->attachSignal(network, SIGNAL(disconnected(uint)), SIGNAL(networkDisconnected(uint)));
+void CoreSession::attachNetworkConnection(NetworkConnection *conn) {
+  //connect(this, SIGNAL(connectToIrc(QString)), network, SLOT(connectToIrc(QString)));
+  //connect(this, SIGNAL(disconnectFromIrc(QString)), network, SLOT(disconnectFromIrc(QString)));
+  //connect(this, SIGNAL(msgFromGui(uint, QString, QString)), network, SLOT(userInput(uint, QString, QString)));
+
+  connect(conn, SIGNAL(connected(NetworkId)), this, SLOT(networkConnected(NetworkId)));
+  connect(conn, SIGNAL(disconnected(NetworkId)), this, SLOT(networkDisconnected(NetworkId)));
+  signalProxy()->attachSignal(conn, SIGNAL(connected(NetworkId)), SIGNAL(networkConnected(NetworkId)));
+  signalProxy()->attachSignal(conn, SIGNAL(disconnected(NetworkId)), SIGNAL(networkDisconnected(NetworkId)));
+
+  connect(conn, SIGNAL(displayMsg(Message::Type, QString, QString, QString, quint8)), this, SLOT(recvMessageFromServer(Message::Type, QString, QString, QString, quint8)));
+  connect(conn, SIGNAL(displayStatusMsg(QString)), this, SLOT(recvStatusMsgFromServer(QString)));
+
   // TODO add error handling
 }
 
 void CoreSession::networkStateRequested() {
 }
 
-void CoreSession::addClient(QIODevice *device) {
-  signalProxy()->addPeer(device);
+void CoreSession::addClient(QObject *dev) { // this is QObject* so we can use it in signal connections
+  QIODevice *device = qobject_cast<QIODevice *>(dev);
+  if(!device) {
+    qWarning() << "Invoking CoreSession::addClient with a QObject that is not a QIODevice!";
+  } else {
+    signalProxy()->addPeer(device);
+    QVariantMap reply;
+    reply["MsgType"] = "SessionInit";
+    reply["SessionState"] = sessionState();
+    SignalProxy::writeDataToDevice(device, reply);
+  }
 }
 
 SignalProxy *CoreSession::signalProxy() const {
@@ -193,17 +257,25 @@ SignalProxy *CoreSession::signalProxy() const {
 }
 
 void CoreSession::networkConnected(uint networkid) {
-  storage->getBufferInfo(userId(), connections[networkid]->networkName()); // create status buffer
+  Core::bufferInfo(user(), networkConnection(networkid)->networkName()); // create status buffer
 }
 
 void CoreSession::networkDisconnected(uint networkid) {
-  Q_ASSERT(connections.contains(networkid));
-  connections.take(networkid)->deleteLater();
-  Q_ASSERT(!connections.contains(networkid));
+  // FIXME
+  // connection should only go away on explicit /part, and handle reconnections etcpp internally otherwise
+  Q_ASSERT(_connections.contains(networkid));
+  _connections.take(networkid)->deleteLater();
+  Q_ASSERT(!_connections.contains(networkid));
 }
 
-void CoreSession::msgFromGui(BufferInfo bufid, QString msg) {
-  emit msgFromGui(bufid.networkId(), bufid.buffer(), msg);
+// FIXME switch to BufferId
+void CoreSession::msgFromClient(BufferInfo bufinfo, QString msg) {
+  NetworkConnection *conn = networkConnection(bufinfo.networkId());
+  if(conn) {
+    conn->userInput(bufinfo.buffer(), msg);
+  } else {
+    qWarning() << "Trying to send to unconnected network!";
+  }
 }
 
 // ALL messages coming pass through these functions before going to the GUI.
@@ -213,12 +285,12 @@ void CoreSession::recvMessageFromServer(Message::Type type, QString target, QStr
   Q_ASSERT(s);
   BufferInfo buf;
   if((flags & Message::PrivMsg) && !(flags & Message::Self)) {
-    buf = storage->getBufferInfo(user, s->networkName(), nickFromMask(sender));
+    buf = Core::bufferInfo(user(), s->networkName(), nickFromMask(sender));
   } else {
-    buf = storage->getBufferInfo(user, s->networkName(), target);
+    buf = Core::bufferInfo(user(), s->networkName(), target);
   }
   Message msg(buf, type, text, sender, flags);
-  msg.setMsgId(storage->logMessage(msg));
+  msg.setMsgId(Core::storeMessage(msg));
   Q_ASSERT(msg.msgId());
   emit displayMsg(msg);
 }
@@ -229,13 +301,8 @@ void CoreSession::recvStatusMsgFromServer(QString msg) {
   emit displayStatusMsg(s->networkName(), msg);
 }
 
-
-uint CoreSession::getNetworkId(const QString &net) const {
-  return storage->getNetworkId(user, net);
-}
-
 QList<BufferInfo> CoreSession::buffers() const {
-  return storage->requestBuffers(user);
+  return Core::requestBuffers(user());
 }
 
 
@@ -243,24 +310,29 @@ QVariant CoreSession::sessionState() {
   QVariantMap v;
 
   QVariantList bufs;
-  foreach(BufferInfo id, storage->requestBuffers(user))
-    bufs.append(QVariant::fromValue(id));
-  v["Buffers"] = bufs;
-
-  mutex.lock();
-  v["SessionData"] = sessionData;
-  mutex.unlock();
-
-  QVariantList networks;
-  foreach(NetworkId networkid, connections.keys())
-    networks.append(QVariant(networkid));
-  v["Networks"] = QVariant(networks);
+  foreach(BufferInfo id, buffers()) bufs << QVariant::fromValue(id);
+  v["BufferInfos"] = bufs;
+  QVariantList networkids;
+  foreach(NetworkId id, _networks.keys()) networkids << QVariant::fromValue(id);
+  v["NetworkIds"] = networkids;
+
+  quint32 ircusercount = 0;
+  quint32 ircchannelcount = 0;
+  foreach(Network *net, _networks.values()) {
+    ircusercount += net->ircUserCount();
+    ircchannelcount += net->ircChannelCount();
+  }
+  v["IrcUserCount"] = ircusercount;
+  v["IrcChannelCount"] = ircchannelcount;
+  qDebug() << "nets:" << _networks.count() << " chans:" << ircchannelcount << " users:" << ircusercount;
 
   QList<QVariant> idlist;
   foreach(Identity *i, _identities.values()) idlist << QVariant::fromValue<Identity>(*i);
   v["Identities"] = idlist;
 
-  // v["Payload"] = QByteArray(100000000, 'a');  // for testing purposes
+  v["SessionData"] = sessionData;
+
+    //v["Payload"] = QByteArray(100000000, 'a');  // for testing purposes
   return v;
 }
 
@@ -271,7 +343,7 @@ void CoreSession::sendBacklog(BufferInfo id, QVariant v1, QVariant v2) {
 
 
   } else {
-    msglist = storage->requestMsgs(id, v1.toInt(), v2.toInt());
+    msglist = Core::requestMsgs(id, v1.toInt(), v2.toInt());
   }
 
   // Send messages out in smaller packages - we don't want to make the signal data too large!
@@ -289,9 +361,10 @@ void CoreSession::sendBacklog(BufferInfo id, QVariant v1, QVariant v2) {
 void CoreSession::initScriptEngine() {
   signalProxy()->attachSlot(SIGNAL(scriptRequest(QString)), this, SLOT(scriptRequest(QString)));
   signalProxy()->attachSignal(this, SIGNAL(scriptResult(QString)));
-  
-  QScriptValue storage_ = scriptEngine->newQObject(storage);
-  scriptEngine->globalObject().setProperty("storage", storage_);
+
+  // FIXME
+  //QScriptValue storage_ = scriptEngine->newQObject(storage);
+  //scriptEngine->globalObject().setProperty("storage", storage_);
 }
 
 void CoreSession::scriptRequest(QString script) {
@@ -309,7 +382,7 @@ void CoreSession::createIdentity(const Identity &id) {
   newId->setId(i);
   _identities[i] = newId;
   signalProxy()->synchronize(newId);
-  CoreUserSettings s(user);
+  CoreUserSettings s(user());
   s.storeIdentity(*newId);
   emit identityCreated(*newId);
 }
@@ -321,7 +394,7 @@ void CoreSession::updateIdentity(const Identity &id) {
   }
   _identities[id.id()]->update(id);
 
-  CoreUserSettings s(user);
+  CoreUserSettings s(user());
   s.storeIdentity(id);
 }
 
@@ -329,7 +402,7 @@ void CoreSession::removeIdentity(IdentityId id) {
   Identity *i = _identities.take(id);
   if(i) {
     emit identityRemoved(id);
-    CoreUserSettings s(user);
+    CoreUserSettings s(user());
     s.removeIdentity(id);
     i->deleteLater();
   }
index 27417e5..1c8924a 100644 (file)
 #ifndef _CORESESSION_H_
 #define _CORESESSION_H_
 
-#include <QObject>
 #include <QString>
 #include <QVariant>
 
 #include "message.h"
 
 class Identity;
-class NetworkConnection;
+class NetworkConnection;  // FIXME get rid of
+class Network;
 class SignalProxy;
-class Storage;
 
 class QScriptEngine;
 
@@ -38,12 +37,15 @@ class CoreSession : public QObject {
   Q_OBJECT
 
 public:
-  CoreSession(UserId, Storage *, QObject *parent = 0);
-  virtual ~CoreSession();
+  CoreSession(UserId, QObject *parent = 0);
+  ~CoreSession();
 
-  NetworkId getNetworkId(const QString &network) const;
   QList<BufferInfo> buffers() const;
-  UserId userId() const;
+  UserId user() const;
+  Network *network(NetworkId) const;
+  NetworkConnection *networkConnection(NetworkId) const;
+  Identity *identity(IdentityId) const;
+
   QVariant sessionState();
 
   //! Retrieve a piece of session-wide data.
@@ -63,14 +65,14 @@ public slots:
 
   void networkStateRequested();
 
-  void addClient(QIODevice *connection);
+  void addClient(QObject *socket);
 
   void connectToNetwork(QString, const QVariant &previousState = QVariant());
-  //void connectToNetwork(NetworkId);
+  void connectToNetwork(NetworkId, const QVariant &previousState = QVariant());
 
   //void processSignal(ClientSignal, QVariant, QVariant, QVariant);
   void sendBacklog(BufferInfo, QVariant, QVariant);
-  void msgFromGui(BufferInfo, QString message);
+  void msgFromClient(BufferInfo, QString message);
 
   //! Create an identity and propagate the changes to the clients.
   /** \param identity The identity to be created.
@@ -88,12 +90,14 @@ public slots:
   void removeIdentity(IdentityId identity);
 
 signals:
-  void msgFromGui(uint netid, QString buf, QString message);
+  void initialized();
+
+  //void msgFromGui(uint netid, QString buf, QString message);
   void displayMsg(Message message);
   void displayStatusMsg(QString, QString);
 
-  void connectToIrc(QString net);
-  void disconnectFromIrc(QString net);
+  //void connectToIrc(QString net);
+  //void disconnectFromIrc(QString net);
 
   void backlogData(BufferInfo, QVariantList, bool done);
 
@@ -121,23 +125,29 @@ private slots:
   void networkConnected(uint networkid);
   void networkDisconnected(uint networkid);
 
+  //! Called when storage updated a BufferInfo.
+  /** This emits bufferInfoUpdated() via SignalProxy, iff it's one of our buffers.
+   *  \param user       The buffer's owner (not necessarily us)
+   *  \param bufferInfo The updated BufferInfo
+   */
+  void updateBufferInfo(UserId user, const BufferInfo &bufferInfo);
+
   void scriptRequest(QString script);
-  
+
 private:
   void initScriptEngine();
-  
-  UserId user;
-  
+
+  UserId _user;
+
   SignalProxy *_signalProxy;
-  Storage *storage;
-  QHash<NetworkId, NetworkConnection *> connections;
-  
+  QHash<NetworkId, NetworkConnection *> _connections;
+  QHash<NetworkId, Network *> _networks;
+  QHash<IdentityId, Identity *> _identities;
+
   QVariantMap sessionData;
-  QMutex mutex;
 
   QScriptEngine *scriptEngine;
 
-  QHash<IdentityId, Identity *> _identities;
 };
 
 #endif
index a821a35..591c86f 100644 (file)
@@ -27,7 +27,7 @@ class IrcServerHandler : public BasicHandler {
   Q_OBJECT
 
 public:
-  IrcServerHandler(NetworkConnection *parent = 0);
+  IrcServerHandler(NetworkConnection *parent);
   ~IrcServerHandler();
 
   void handleServerMsg(QByteArray rawMsg);
index ae8ac13..21e7f63 100644 (file)
 
 #include "ircuser.h"
 #include "network.h"
+#include "identity.h"
 
 #include "ircserverhandler.h"
 #include "userinputhandler.h"
 #include "ctcphandler.h"
 
-NetworkConnection::NetworkConnection(UserId uid, NetworkId networkId, QString net, const QVariant &state)
-  : _userId(uid),
-    _networkId(networkId),
+NetworkConnection::NetworkConnection(Network *network, CoreSession *session, const QVariant &state) : QObject(network),
+    _network(network),
+    _coreSession(session),
     _ircServerHandler(new IrcServerHandler(this)),
     _userInputHandler(new UserInputHandler(this)),
     _ctcpHandler(new CtcpHandler(this)),
-    _network(new Network(networkId, this)),
     _previousState(state)
 {
-  connect(network(), SIGNAL(currentServerSet(const QString &)), this, SLOT(sendPerform()));
-  network()->setCodecForEncoding("ISO-8859-15"); // FIXME
-  network()->setCodecForDecoding("ISO-8859-15"); // FIXME
-  network()->setNetworkName(net);
-  network()->setProxy(coreSession()->signalProxy());
+  connect(network, SIGNAL(currentServerSet(const QString &)), this, SLOT(sendPerform()));
+
+  connect(&socket, SIGNAL(connected()), this, SLOT(socketConnected()));
+  connect(&socket, SIGNAL(disconnected()), this, SLOT(quit()));
+  connect(&socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(socketError(QAbstractSocket::SocketError)));
+  connect(&socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(socketStateChanged(QAbstractSocket::SocketState)));
+  connect(&socket, SIGNAL(readyRead()), this, SLOT(socketHasData()));
+
 }
 
 NetworkConnection::~NetworkConnection() {
@@ -56,15 +59,36 @@ NetworkConnection::~NetworkConnection() {
   delete _ctcpHandler;
 }
 
-void NetworkConnection::run() {
-  connect(&socket, SIGNAL(connected()), this, SLOT(socketConnected()));
-  connect(&socket, SIGNAL(disconnected()), this, SLOT(quit()));
-  connect(&socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(socketError(QAbstractSocket::SocketError)));
-  connect(&socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(socketStateChanged(QAbstractSocket::SocketState)));
-  connect(&socket, SIGNAL(readyRead()), this, SLOT(socketHasData()));
-  connect(this, SIGNAL(finished()), this, SLOT(threadFinished()));
+bool NetworkConnection::isConnected() const {
+  return socket.state() == QAbstractSocket::ConnectedState;
+}
+
+uint NetworkConnection::networkId() const {
+  return network()->networkId();
+}
+
+QString NetworkConnection::networkName() const {
+  return network()->networkName();
+}
+
+Network *NetworkConnection::network() const {
+  return _network;
+}
 
-  exec();
+CoreSession *NetworkConnection::coreSession() const {
+  return _coreSession;
+}
+
+IrcServerHandler *NetworkConnection::ircServerHandler() const {
+  return _ircServerHandler;
+}
+
+UserInputHandler *NetworkConnection::userInputHandler() const {
+  return _userInputHandler;
+}
+
+CtcpHandler *NetworkConnection::ctcpHandler() const {
+  return _ctcpHandler;
 }
 
 QString NetworkConnection::serverDecode(const QByteArray &string) const {
@@ -100,18 +124,21 @@ QByteArray NetworkConnection::userEncode(const QString &userNick, const QString
 }
 
 
-void NetworkConnection::connectToIrc(QString net) {
-  if(net != networkName())
-    return; // not me!
-  
-  CoreSession *sess = coreSession();
-  networkSettings = sess->retrieveSessionData("Networks").toMap()[net].toMap();
-  identity = sess->retrieveSessionData("Identities").toMap()[networkSettings["Identity"].toString()].toMap();
-
-  //FIXME this will result in a pretty fuckup if there are no servers in the list
-  QList<QVariant> servers = networkSettings["Servers"].toList();
-  QString host = servers[0].toMap()["Address"].toString();
-  quint16 port = servers[0].toMap()["Port"].toUInt();
+void NetworkConnection::connectToIrc() {
+  QList<QVariantMap> serverList = network()->serverList();
+  Identity *identity = coreSession()->identity(network()->identity());
+  if(!serverList.count()) {
+    qWarning() << "Server list empty, ignoring connect request!";
+    return;
+  }
+  if(!identity) {
+    qWarning() << "Invalid identity configures, ignoring connect request!";
+    return;
+  }
+
+  // TODO implement cycling / random servers
+  QString host = serverList[0]["Address"].toString();
+  quint16 port = serverList[0]["Port"].toUInt();
   displayStatusMsg(QString("Connecting to %1:%2...").arg(host).arg(port));
   socket.connectToHost(host, port);
 }
@@ -138,15 +165,13 @@ void NetworkConnection::sendPerform() {
   _previousState = QVariant();
 }
 
-QVariant NetworkConnection::state() {
+QVariant NetworkConnection::state() const {
   IrcUser *me = network()->ircUser(network()->myNick());
   if(!me) return QVariant();  // this shouldn't really happen, I guess
   return me->channels();
 }
 
-void NetworkConnection::disconnectFromIrc(QString net) {
-  if(net != networkName())
-    return; // not me!
+void NetworkConnection::disconnectFromIrc() {
   socket.disconnectFromHost();
 }
 
@@ -158,29 +183,27 @@ void NetworkConnection::socketHasData() {
 }
 
 void NetworkConnection::socketError( QAbstractSocket::SocketError err ) {
-  //qDebug() << "Socket Error!";
+  qDebug() << "Socket Error!";
 }
 
 void NetworkConnection::socketConnected() {
   emit connected(networkId());
-  putRawLine(QString("NICK :%1").arg(identity["NickList"].toStringList()[0]));  // FIXME: try more nicks if error occurs
-  putRawLine(QString("USER %1 8 * :%2").arg(identity["Ident"].toString()).arg(identity["RealName"].toString()));
-}
-
-void NetworkConnection::threadFinished() {
-  // the Socket::disconnected() is connect to this::quit()
-  // so after the event loop is finished we're beeing called
-  // and propagate the disconnect
-  emit disconnected(networkId());
+  Identity *identity = coreSession()->identity(network()->identity());
+  if(!identity) {
+    qWarning() << "Identity invalid!";
+    disconnectFromIrc();
+    return;
+  }
+  putRawLine(QString("NICK :%1").arg(identity->nicks()[0]));  // FIXME: try more nicks if error occurs
+  putRawLine(QString("USER %1 8 * :%2").arg(identity->ident(), identity->realName()));
 }
 
 void NetworkConnection::socketStateChanged(QAbstractSocket::SocketState state) {
   //qDebug() << "Socket state changed: " << state;
 }
 
-void NetworkConnection::userInput(uint netid, QString buf, QString msg) {
-  if(netid != networkId())
-    return; // not me!
+// FIXME switch to BufferId
+void NetworkConnection::userInput(QString buf, QString msg) {
   userInputHandler()->handleUserInput(buf, msg);
 }
 
@@ -204,19 +227,6 @@ void NetworkConnection::putCmd(QString cmd, QStringList params, QString prefix)
   putRawLine(msg);
 }
 
-
-uint NetworkConnection::networkId() const {
-  return _networkId;
-}
-
-QString NetworkConnection::networkName() const {
-  return network()->networkName();
-}
-
-CoreSession *NetworkConnection::coreSession() const {
-  return Core::session(userId());
-}
-
 /* Exception classes for message handling */
 NetworkConnection::ParseError::ParseError(QString cmd, QString prefix, QStringList params) {
   Q_UNUSED(prefix);
index a7d6eba..1e1247b 100644 (file)
 #include <QString>
 #include <QStringList>
 #include <QTcpSocket>
-#include <QThread>
 #include <QTimer>
 
 #include "message.h"
 #include "signalproxy.h"
 
+class CoreSession;
 class Network;
 
 class IrcServerHandler;
 class UserInputHandler;
 class CtcpHandler;
-class CoreSession;
 
-/*!
- * This is a server object, managing a single connection to an IRC server, handling the associated channels and so on.
- * We have this running in its own thread mainly to not block other server objects or the core if something goes wrong,
- * e.g. if some scripts starts running wild...
- */
-
-class NetworkConnection : public QThread {
+class NetworkConnection : public QObject {
   Q_OBJECT
 
 public:
-  NetworkConnection(UserId uid, NetworkId networkId, QString network, const QVariant &previousState = QVariant());
+  NetworkConnection(Network *network, CoreSession *session, const QVariant &previousState = QVariant());
   ~NetworkConnection();
 
-  UserId userId() const { return _userId; } 
-
-  // networkState state();
-  bool isConnected() const { return socket.state() == QAbstractSocket::ConnectedState; }
-
   NetworkId networkId() const;
-  QString networkName() const;  // hasbeen getNetwork()
+  QString networkName() const;
+  Network *network() const;
+  CoreSession *coreSession() const;
+
+  bool isConnected() const;
 
-  Network *network() const { return _network; }
-  IrcServerHandler *ircServerHandler() const { return _ircServerHandler; }
-  UserInputHandler *userInputHandler() const { return _userInputHandler; }
-  CtcpHandler *ctcpHandler() const { return _ctcpHandler; }
+  IrcServerHandler *ircServerHandler() const;
+  UserInputHandler *userInputHandler() const;
+  CtcpHandler *ctcpHandler() const;
 
-  QVariant state(); ///< Return data necessary to restore the server's state upon core restart
+  //! Return data necessary to restore the connection state upon core restart
+  QVariant state() const;
 
   //! Decode a string using the server (network) decoding.
   QString serverDecode(const QByteArray &string) const;
@@ -86,60 +78,52 @@ public:
 
 public slots:
   // void setServerOptions();
-  void connectToIrc(QString net);
-  void disconnectFromIrc(QString net);
-  void userInput(uint netid, QString buffer, QString msg);
+  void connectToIrc();
+  void disconnectFromIrc();
+  void userInput(QString buffer, QString msg);
 
   void putRawLine(QString input);
   void putCmd(QString cmd, QStringList params, QString prefix = 0);
 
 
 private slots:
-  void threadFinished();
   void sendPerform();
 
 signals:
-  void networkState(QString net, QVariantMap data);
+  // #void networkState(QString net, QVariantMap data);
   void recvRawServerMsg(QString);
   void displayStatusMsg(QString);
   //void displayMsg(Message msg);
   void displayMsg(Message::Type, QString target, QString text, QString sender = "", quint8 flags = Message::None);
-  void connected(uint networkId);
-  void disconnected(uint networkId);
+  void connected(NetworkId networkId);
+  void disconnected(NetworkId networkId);
 
   void connectionInitialized(); ///< Emitted after receipt of 001 to indicate that we can now send data to the IRC server
 
-  void synchronizeClients();
-  
-  void queryRequested(QString network, QString nick);
+  //void queryRequested(QString network, QString nick);
 
 
 private slots:
-  void run();
   void socketHasData();
   void socketError(QAbstractSocket::SocketError);
   void socketConnected();
   void socketStateChanged(QAbstractSocket::SocketState);
 
 private:
-  UserId _userId;
-  NetworkId _networkId;
-
   QTcpSocket socket;
 
+  Network *_network;
+  CoreSession *_coreSession;
+
   IrcServerHandler *_ircServerHandler;
   UserInputHandler *_userInputHandler;
   CtcpHandler *_ctcpHandler;
 
-  Network *_network;
-
   QVariantMap networkSettings;
   QVariantMap identity;
 
   QVariant _previousState;
 
-  CoreSession *coreSession() const;
-  
   class ParseError : public Exception {
   public:
     ParseError(QString cmd, QString prefix, QStringList params);
diff --git a/src/core/sessionthread.cpp b/src/core/sessionthread.cpp
new file mode 100644 (file)
index 0000000..d507095
--- /dev/null
@@ -0,0 +1,83 @@
+/***************************************************************************
+ *   Copyright (C) 2005-08 by the Quassel IRC 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) version 3.                                           *
+ *                                                                         *
+ *   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 <QMutexLocker>
+
+#include "sessionthread.h"
+
+#include "coresession.h"
+
+SessionThread::SessionThread(UserId uid, QObject *parent) : QThread(parent) {
+    _user = uid;
+    _session = 0;
+    _sessionInitialized = false;
+    connect(this, SIGNAL(initialized()), this, SLOT(setSessionInitialized()));
+}
+
+SessionThread::~SessionThread() {
+  // FIXME
+  quit();
+  wait();
+  if(session()) _session->deleteLater();
+}
+
+CoreSession *SessionThread::session() {
+  return _session;
+}
+
+UserId SessionThread::user() {
+  return _user;
+}
+
+bool SessionThread::isSessionInitialized() {
+  return _sessionInitialized;
+}
+
+void SessionThread::setSessionInitialized() {
+  _sessionInitialized = true;
+  foreach(QIODevice *socket, clientQueue) {
+    addClientToSession(socket);
+  }
+  clientQueue.clear();
+}
+
+void SessionThread::addClient(QIODevice *socket) {
+  if(isSessionInitialized()) {
+    addClientToSession(socket);
+  } else {
+    clientQueue.append(socket);
+  }
+}
+
+void SessionThread::addClientToSession(QIODevice *socket) {
+  socket->setParent(0);
+  socket->moveToThread(session()->thread());
+  if(!QMetaObject::invokeMethod(session(), "addClient", Q_ARG(QObject *, socket))) {
+    qWarning() << qPrintable(tr("Could not initialize session!"));
+    socket->close();
+  }
+}
+
+void SessionThread::run() {
+  _session = new CoreSession(user());
+  emit initialized();
+  exec();
+}
+
diff --git a/src/core/sessionthread.h b/src/core/sessionthread.h
new file mode 100644 (file)
index 0000000..ee29d2e
--- /dev/null
@@ -0,0 +1,63 @@
+/***************************************************************************
+ *   Copyright (C) 2005-08 by the Quassel IRC 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) version 3.                                           *
+ *                                                                         *
+ *   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 _SESSIONTHREAD_H_
+#define _SESSIONTHREAD_H_
+
+#include <QMutex>
+#include <QThread>
+
+#include "types.h"
+
+class CoreSession;
+class QIODevice;
+
+class SessionThread : public QThread {
+  Q_OBJECT
+
+  public:
+    SessionThread(UserId user, QObject *parent = 0);
+    ~SessionThread();
+
+    void run();
+
+    CoreSession *session();
+    UserId user();
+
+  public slots:
+    void addClient(QIODevice *socket);
+
+  private slots:
+    void setSessionInitialized();
+
+  signals:
+    void initialized();
+
+  private:
+    CoreSession *_session;
+    UserId _user;
+    QList<QIODevice *> clientQueue;
+    bool _sessionInitialized;
+
+    bool isSessionInitialized();
+    void addClientToSession(QIODevice *socket);
+};
+
+#endif
index 90a111e..81108bd 100644 (file)
@@ -113,7 +113,6 @@ UserId SqliteStorage::validateUser(const QString &user, const QString &password)
   if(query.first()) {
     return query.value(0).toUInt();
   } else {
-    throw AuthError();
     return 0;
   }
 }
@@ -203,7 +202,7 @@ BufferInfo SqliteStorage::getBufferInfo(UserId user, const QString &network, con
     getBufferInfoQuery->exec();
     if(getBufferInfoQuery->first()) {
       bufferid = BufferInfo(getBufferInfoQuery->value(0).toUInt(), networkId, 0, network, buffer);
-      emit bufferInfoUpdated(bufferid);
+      emit bufferInfoUpdated(user, bufferid);
     }
   } else {
     bufferid = BufferInfo(getBufferInfoQuery->value(0).toUInt(), networkId, 0, network, buffer);
index 3b27205..992fc8f 100644 (file)
@@ -69,9 +69,6 @@ protected:
   inline virtual QString databaseName() { return backlogFile(); }
   virtual int installedSchemaVersion();
   
-signals:
-  void bufferInfoUpdated(BufferInfo);
-  
 private:
   static QString backlogFile();
   void createBuffer(UserId user, const QString &network, const QString &buffer);
index 69a229e..db68417 100644 (file)
@@ -157,7 +157,7 @@ class Storage : public QObject {
 
   signals:
     //! Sent when a new BufferInfo is created, or an existing one changed somehow.
-    void bufferInfoUpdated(BufferInfo);
+    void bufferInfoUpdated(UserId user, const BufferInfo &);
     //! Sent when a new user has been added
     void userAdded(UserId, const QString &username);
     //! Sent when a user has been renamed
@@ -166,8 +166,7 @@ class Storage : public QObject {
     void userRemoved(UserId);
 
   public:
-    /* Exceptions */
-    struct AuthError : public Exception {};
+
 };
 
 
index fe36a6d..5630df6 100644 (file)
         <file>oxygen/22x22/actions/media-seek-forward.png</file>
         <file>oxygen/22x22/actions/media-skip-backward.png</file>
         <file>oxygen/22x22/actions/media-skip-forward.png</file>
-        <file>oxygen/22x22/actions/network-connect.png</file>
-        <file>oxygen/22x22/actions/network-disconnect.png</file>
+        <file alias="network-connect">oxygen/22x22/actions/network-connect.png</file>
+        <file alias="network-disconnect">oxygen/22x22/actions/network-disconnect.png</file>
         <file>oxygen/22x22/actions/news-subscribe.png</file>
         <file>oxygen/22x22/actions/news-unsubscribe.png</file>
         <file>oxygen/22x22/actions/object-rotate-left.png</file>
         <file>oxygen/22x22/actions/zoom-original.png</file>
         <file>oxygen/22x22/actions/zoom-out.png</file>
     </qresource>
+    <qresource prefix="/22x22/status" >
+        <file alias="dialog-error">oxygen/22x22/status/dialog-error.png</file>
+        <file>oxygen/22x22/status/dialog-information.png</file>
+        <file>oxygen/22x22/status/dialog-password.png</file>
+        <file>oxygen/22x22/status/dialog-warning.png</file>
+        <file>oxygen/22x22/status/script-error.png</file>
+        <file>oxygen/22x22/status/security-high.png</file>
+        <file>oxygen/22x22/status/security-low.png</file>
+        <file>oxygen/22x22/status/security-medium.png</file>
+    </qresource>
     <qresource prefix="/icons" >
         <file>quassel-icon.png</file>
     </qresource>
index 4146db9..017a479 100644 (file)
 #include "chatline-old.h"
 #include "qtui.h"
 
-//!\brief Construct a ChatLine object from a message.
+//! Construct a ChatLine object from a message.
 /**
  * \param m   The message to be layouted and rendered
- * \param net The network name
- * \param buf The buffer name
  */
 ChatLine::ChatLine(Message m) {
   hght = 0;
index 643b0ff..3b4a21a 100644 (file)
@@ -1,5 +1,5 @@
 /***************************************************************************
- *   Copyright (C) 2005-08 by the Quassel Project                          *
+ *   Copyright (C) 2005-08 by the Quassel IRC Team                         *
  *   devel@quassel-irc.org                                                 *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
  ***************************************************************************/
 
-#include <QtGui>
+#include <QDebug>
+#include <QMessageBox>
+
 #include "coreconnectdlg.h"
-#include "client.h"
+
 #include "clientsettings.h"
-#include "configwizard.h"
-#include "global.h"
+#include "clientsyncer.h"
+
+CoreConnectDlg::CoreConnectDlg(QWidget *parent, bool autoconnect) : QDialog(parent) {
+  ui.setupUi(this);
 
-CoreConnectDlg::CoreConnectDlg(QWidget *parent, bool /*doAutoConnect*/) : QDialog(parent) {
-  ui.setupUi(this); //qDebug() << "new dlg";
+  clientSyncer = new ClientSyncer(this);
 
   setAttribute(Qt::WA_DeleteOnClose);
 
-  coreState = 0;
-  /* We show ui.internalCore in any case, because we might want to run as monolithic client anyway at another time
-  if(Global::runMode == Global::Monolithic) {
-    connect(ui.internalCore, SIGNAL(toggled(bool)), ui.hostEdit, SLOT(setDisabled(bool)));
-    connect(ui.internalCore, SIGNAL(toggled(bool)), ui.port, SLOT(setDisabled(bool)));
-    ui.internalCore->setChecked(true);
-  } else {
-    //ui.internalCore->hide();
-  }
-  */
-  connect(ui.newAccount, SIGNAL(clicked()), this, SLOT(createAccount()));
-  connect(ui.delAccount, SIGNAL(clicked()), this, SLOT(removeAccount()));
-  connect(ui.buttonBox1, SIGNAL(accepted()), this, SLOT(doConnect()));
-  connect(ui.hostEdit, SIGNAL(textChanged(const QString &)), this, SLOT(checkInputValid()));
-  connect(ui.userEdit, SIGNAL(textChanged(const QString &)), this, SLOT(checkInputValid()));
-  connect(ui.internalCore, SIGNAL(toggled(bool)), this, SLOT(checkInputValid()));
-  connect(ui.internalCore, SIGNAL(toggled(bool)), ui.hostEdit, SLOT(setDisabled(bool)));
-  connect(ui.internalCore, SIGNAL(toggled(bool)), ui.port, SLOT(setDisabled(bool)));
-  connect(ui.accountList, SIGNAL(currentIndexChanged(const QString &)), this, SLOT(accountChanged(const QString &)));
-  connect(ui.autoConnect, SIGNAL(clicked(bool)), this, SLOT(autoConnectToggled(bool)));
-
-  connect(Client::instance(), SIGNAL(coreConnectionMsg(const QString &)), ui.connectionStatus, SLOT(setText(const QString &)));
-  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;
+  doingAutoConnect = false;
+
+  ui.stackedWidget->setCurrentWidget(ui.accountPage);
+  ui.accountButtonBox->setFocus();
+
+  CoreAccountSettings s;
   QString lastacc = s.lastAccount();
-  ui.accountList->addItems(s.knownAccounts());
-  if(!ui.accountList->count()) {
-    //if(doAutoConnect) reject();
-
-    setAccountEditEnabled(false);
-    QString newacc = QInputDialog::getText(this, tr("Create Account"), tr(
-                                           "In order to connect to a Quassel Core, you need to create an account.<br>"
-                                           "Please enter a name for this account now:"), QLineEdit::Normal, tr("Default"));
-    if(!newacc.isEmpty()) {
-      ui.accountList->addItem(newacc);
-      ui.hostEdit->setText("localhost");
-      ui.port->setValue(Global::defaultPort);
-      ui.internalCore->setChecked(false);
-      setAccountEditEnabled(true);
-    }
-    /*
-    // FIXME We create a default account here that just connects to the internal core
-    curacc = "Default";
-    ui.accountList->addItem("Default");
-    ui.internalCore->setChecked(true);
-    ui.userEdit->setText("Default");
-    ui.passwdEdit->setText("password");
-    ui.rememberPasswd->setChecked(true);
-    accountChanged(curacc);
-    ui.passwdEdit->setText("password");
-    ui.accountList->setCurrentIndex(0);
-    ui.autoConnect->setChecked(true);
-    autoConnectToggled(true);
-    */
-  } else {
-    if(!lastacc.isEmpty()) {
-      //if(doAutoConnect) { qDebug() << "auto";
-      //  AccountSettings s;
-      //  int idx = ui.accountList->findText(s.autoConnectAccount());
-      //  if(idx < 0) reject();
-      //  else {
-      //    ui.accountList->setCurrentIndex(idx);
-      //    doConnect();
-      //  }
-      //} else {
-        int idx = ui.accountList->findText(lastacc);
-        ui.accountList->setCurrentIndex(idx);
-      //}
-    }
+  autoConnectAccount = s.autoConnectAccount();
+  accounts = s.retrieveAllAccounts();
+  ui.accountList->addItems(accounts.keys());
+  QList<QListWidgetItem *> l = ui.accountList->findItems(lastacc, Qt::MatchExactly);
+  if(l.count()) ui.accountList->setCurrentItem(l[0]);
+  else ui.accountList->setCurrentRow(0);
+
+  setAccountWidgetStates();
+
+  connect(clientSyncer, SIGNAL(socketStateChanged(QAbstractSocket::SocketState)),this, SLOT(initPhaseSocketState(QAbstractSocket::SocketState)));
+  connect(clientSyncer, SIGNAL(connectionError(const QString &)), this, SLOT(initPhaseError(const QString &)));
+  connect(clientSyncer, SIGNAL(connectionMsg(const QString &)), this, SLOT(initPhaseMsg(const QString &)));
+  connect(clientSyncer, SIGNAL(startLogin()), this, SLOT(startLogin()));
+  connect(clientSyncer, SIGNAL(loginFailed(const QString &)), this, SLOT(loginFailed(const QString &)));
+  connect(clientSyncer, SIGNAL(loginSuccess()), this, SLOT(startSync()));
+  connect(clientSyncer, SIGNAL(sessionProgress(quint32, quint32)), this, SLOT(coreSessionProgress(quint32, quint32)));
+  connect(clientSyncer, SIGNAL(networksProgress(quint32, quint32)), this, SLOT(coreNetworksProgress(quint32, quint32)));
+  connect(clientSyncer, SIGNAL(channelsProgress(quint32, quint32)), this, SLOT(coreChannelsProgress(quint32, quint32)));
+  connect(clientSyncer, SIGNAL(ircUsersProgress(quint32, quint32)), this, SLOT(coreIrcUsersProgress(quint32, quint32)));
+  connect(clientSyncer, SIGNAL(syncFinished()), this, SLOT(accept()));
+
+  connect(ui.user, SIGNAL(textChanged(const QString &)), this, SLOT(setLoginWidgetStates()));
+  connect(ui.password, SIGNAL(textChanged(const QString &)), this, SLOT(setLoginWidgetStates()));
+
+  connect(ui.loginButtonBox, SIGNAL(rejected()), this, SLOT(restartPhaseNull()));
+  connect(ui.syncButtonBox->button(QDialogButtonBox::Abort), SIGNAL(clicked()), this, SLOT(restartPhaseNull()));
+
+  if(autoconnect && ui.accountList->count() && !autoConnectAccount.isEmpty() && autoConnectAccount == ui.accountList->currentItem()->text()) {
+    doingAutoConnect = true;
+    on_accountButtonBox_accepted();
   }
 }
 
 CoreConnectDlg::~CoreConnectDlg() {
-  //qDebug() << "destroy";
+  if(ui.accountList->selectedItems().count()) {
+    CoreAccountSettings s;
+    s.setLastAccount(ui.accountList->selectedItems()[0]->text());
+  }
 }
 
-void CoreConnectDlg::setAccountEditEnabled(bool en) {
-  ui.accountList->setEnabled(en);
-  ui.hostEdit->setEnabled(en && !ui.internalCore->isChecked());
-  ui.userEdit->setEnabled(en);
-  ui.passwdEdit->setEnabled(en);
-  ui.port->setEnabled(en && !ui.internalCore->isChecked());
-  ui.editAccount->setEnabled(en);
-  ui.delAccount->setEnabled(en);
-  ui.internalCore->setEnabled(en);
-  ui.rememberPasswd->setEnabled(en);
-  ui.autoConnect->setEnabled(en);
-  ui.buttonBox1->button(QDialogButtonBox::Ok)->setEnabled(en && checkInputValid());
+
+/****************************************************
+ * Account Management
+ ***************************************************/
+
+void CoreConnectDlg::on_accountList_itemSelectionChanged() {
+  setAccountWidgetStates();
 }
 
-void CoreConnectDlg::accountChanged(const QString &text) {
-  AccountSettings s;
-  if(!curacc.isEmpty()) {
-    QVariantMap oldAcc;
-    oldAcc["User"] = ui.userEdit->text();
-    oldAcc["Host"] = ui.hostEdit->text();
-    oldAcc["Port"] = ui.port->value();
-    oldAcc["InternalCore"] = ui.internalCore->isChecked();
-    if(ui.rememberPasswd->isChecked()) oldAcc["Password"] = ui.passwdEdit->text();
-    s.setValue(curacc, "AccountData", oldAcc);
-  }
-  ui.autoConnect->setChecked(false);
-  if(!text.isEmpty()) { // empty text: just save stuff
-    curacc = text;
-    s.setLastAccount(curacc);
-    QVariantMap newAcc = s.value(curacc, "AccountData").toMap();
-    ui.userEdit->setText(newAcc["User"].toString());
-    ui.hostEdit->setText(newAcc["Host"].toString());
-    ui.port->setValue(newAcc["Port"].toInt());
-    ui.internalCore->setChecked(newAcc["InternalCore"].toBool());
-    if(newAcc.contains("Password")) {
-      ui.passwdEdit->setText(newAcc["Password"].toString());
-      ui.rememberPasswd->setChecked(true);
-    } else ui.rememberPasswd->setChecked(false);
-    if(s.autoConnectAccount() == curacc) ui.autoConnect->setChecked(true);
+void CoreConnectDlg::setAccountWidgetStates() {
+  QList<QListWidgetItem *> selectedItems = ui.accountList->selectedItems();
+  ui.editAccount->setEnabled(selectedItems.count());
+  ui.deleteAccount->setEnabled(selectedItems.count());
+  ui.autoConnect->setEnabled(selectedItems.count());
+  if(selectedItems.count()) {
+    ui.autoConnect->setChecked(selectedItems[0]->text() == autoConnectAccount);
   }
 }
 
-void CoreConnectDlg::autoConnectToggled(bool autoConnect) {
-  AccountSettings s;
-  if(autoConnect) s.setAutoConnectAccount(curacc);
-  else s.setAutoConnectAccount("");
+void CoreConnectDlg::on_autoConnect_clicked(bool state) {
+  if(!state) {
+    autoConnectAccount = QString();
+  } else {
+    if(ui.accountList->selectedItems().count()) {
+      autoConnectAccount = ui.accountList->selectedItems()[0]->text();
+    } else {
+      qWarning() << "Checked auto connect without an enabled item!";  // should never happen!
+      autoConnectAccount = QString();
+    }
+  }
+  setAccountWidgetStates();
 }
 
-bool CoreConnectDlg::checkInputValid() {
-  bool res = (ui.internalCore->isChecked() || ui.hostEdit->text().count()) && ui.userEdit->text().count();
-  ui.buttonBox1->button(QDialogButtonBox::Ok)->setEnabled(res);
-  return res;
+void CoreConnectDlg::on_addAccount_clicked() {
+  QStringList existing;
+  for(int i = 0; i < ui.accountList->count(); i++) existing << ui.accountList->item(i)->text();
+  CoreAccountEditDlg dlg(QString(), QVariantMap(), existing, this);
+  if(dlg.exec() == QDialog::Accepted) {
+    accounts[dlg.accountName()] = dlg.accountData();
+    ui.accountList->addItem(dlg.accountName());
+    ui.accountList->setCurrentItem(ui.accountList->findItems(dlg.accountName(), Qt::MatchExactly)[0]);
+  }
 }
 
-void CoreConnectDlg::createAccount() {
-  QString accname = QInputDialog::getText(this, tr("Create Account"), tr("Please enter a name for the new account:"));
-  if(accname.isEmpty()) return;
-  if(ui.accountList->findText(accname) >= 0) {
-    QMessageBox::warning(this, tr("Account name already exists!"), tr("An account named '%1' already exists, and account names must be unique!").arg(accname));
-    return;
+void CoreConnectDlg::on_editAccount_clicked() {
+  QStringList existing;
+  for(int i = 0; i < ui.accountList->count(); i++) existing << ui.accountList->item(i)->text();
+  QString current = ui.accountList->currentItem()->text();
+  QVariantMap acct = accounts[current];
+  CoreAccountEditDlg dlg(current, acct, existing, this);
+  if(dlg.exec() == QDialog::Accepted) {
+    if(current != dlg.accountName()) {
+      if(autoConnectAccount == current) autoConnectAccount = dlg.accountName();
+      accounts.remove(current);
+      current = dlg.accountName();
+      ui.accountList->currentItem()->setText(current);
+    }
+    accounts[current] = dlg.accountData();
   }
-  QVariantMap defdata;
-  ui.accountList->addItem(accname);
-  ui.accountList->setCurrentIndex(ui.accountList->findText(accname));
-  setAccountEditEnabled(true);
+  //ui.accountList->setCurrent
 }
 
-void CoreConnectDlg::removeAccount() {
-  QString acc = ui.accountList->currentText();
-  int res = QMessageBox::warning(this, tr("Delete account?"), tr("Do you really want to delete the data for the account '%1'?<br>"
-                                                       "Note that this only affects your local account settings and will not remove "
-                                                       "any data from the core.").arg(acc),
-                             QMessageBox::Yes|QMessageBox::No, QMessageBox::No);
-  if(res == QMessageBox::Yes) {
-    AccountSettings s;
-    s.removeAccount(acc);
-    curacc = "";
-    ui.accountList->removeItem(ui.accountList->findText(acc));
-    if(!ui.accountList->count()) setAccountEditEnabled(false);
+void CoreConnectDlg::on_deleteAccount_clicked() {
+  QString current = ui.accountList->currentItem()->text();
+  int ret = QMessageBox::question(this, tr("Remove Account Settings"),
+                                  tr("Do you really want to remove your local settings for this Quassel Core account?<br>"
+                                  "Note: This will <em>not</em> remove or change any data on the Core itself!"),
+                                  QMessageBox::Yes|QMessageBox::No, QMessageBox::No);
+  if(ret == QMessageBox::Yes) {
+    int idx = ui.accountList->currentRow();
+    delete ui.accountList->item(idx);
+    ui.accountList->setCurrentRow(qMin(idx, ui.accountList->count()));
+    accounts.remove(current);
   }
 }
 
-bool CoreConnectDlg::willDoInternalAutoConnect() {
-  AccountSettings s;
-  if(Global::runMode != Global::Monolithic) return false;
-  if(ui.autoConnect->isChecked() && s.autoConnectAccount() == curacc && ui.internalCore->isChecked()) {
-    return true;
-  }
-  return false;
+void CoreConnectDlg::on_accountList_itemDoubleClicked(QListWidgetItem *item) {
+  Q_UNUSED(item);
+  on_accountButtonBox_accepted();
+}
+
+void CoreConnectDlg::on_accountButtonBox_accepted() {
+  // save accounts
+  CoreAccountSettings s;
+  s.storeAllAccounts(accounts);
+  s.setAutoConnectAccount(autoConnectAccount);
+
+  ui.stackedWidget->setCurrentWidget(ui.loginPage);
+  accountName = ui.accountList->currentItem()->text();
+  account = s.retrieveAccount(accountName);
+  s.setLastAccount(accountName);
+  connectToCore();
+}
+
+/*****************************************************
+ * Connecting to the Core
+ ****************************************************/
+
+/*** Phase One: initializing the core connection ***/
+
+void CoreConnectDlg::connectToCore() {
+  ui.connectIcon->setPixmap(QPixmap::fromImage(QImage(":/22x22/actions/network-disconnect")));
+  ui.connectLabel->setText(tr("Connect to %1").arg(account["Host"].toString()));
+  ui.coreInfoLabel->setText("");
+  ui.loginStack->setCurrentWidget(ui.loginEmptyPage);
+  ui.loginButtonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);
+  ui.loginButtonBox->button(QDialogButtonBox::Ok)->setDisabled(true);
+  disconnect(ui.loginButtonBox, 0, this, 0);
+  connect(ui.loginButtonBox, SIGNAL(rejected()), this, SLOT(restartPhaseNull()));
+
+
+  //connect(Client::instance(), SIGNAL(coreConnectionPhaseOne(const QVariantMap &)), this, SLOT(phaseOneFinished
+  clientSyncer->connectToCore(account);
+}
+
+void CoreConnectDlg::initPhaseError(const QString &error) {
+  doingAutoConnect = false;
+  ui.connectIcon->setPixmap(QPixmap::fromImage(QImage(":/22x22/status/dialog-error")));
+  //ui.connectLabel->setBrush(QBrush("red"));
+  ui.connectLabel->setText(tr("<div style=color:red;>Connection to %1 failed!</div>").arg(account["Host"].toString()));
+  ui.coreInfoLabel->setText(error);
+  ui.loginButtonBox->setStandardButtons(QDialogButtonBox::Retry|QDialogButtonBox::Cancel);
+  disconnect(ui.loginButtonBox, 0, this, 0);
+  connect(ui.loginButtonBox, SIGNAL(accepted()), this, SLOT(restartPhaseNull()));
+  connect(ui.loginButtonBox, SIGNAL(rejected()), this, SLOT(reject()));
+}
+
+void CoreConnectDlg::initPhaseMsg(const QString &msg) {
+  ui.coreInfoLabel->setText(msg);
 }
 
-void CoreConnectDlg::doAutoConnect() {
-  AccountSettings s;
-  if(s.autoConnectAccount() == curacc) {
-    doConnect();
+void CoreConnectDlg::initPhaseSocketState(QAbstractSocket::SocketState state) {
+  QString s;
+  QString host = account["Host"].toString();
+  switch(state) {
+    case QAbstractSocket::UnconnectedState: s = tr("Not connected to %1.").arg(host); break;
+    case QAbstractSocket::HostLookupState: s = tr("Looking up %1...").arg(host); break;
+    case QAbstractSocket::ConnectingState: s = tr("Connecting to %1...").arg(host); break;
+    case QAbstractSocket::ConnectedState: s = tr("Connected to %1").arg(host); break;
+    default: s = tr("Unknown connection state to %1"); break;
   }
+  ui.connectLabel->setText(s);
 }
 
-void CoreConnectDlg::doConnect() {
-  accountChanged(); // save current account info
-  QVariantMap conninfo;
-  ui.stackedWidget->setCurrentIndex(1);
-  if(ui.internalCore->isChecked()) {
-    // FIXME
-    coreConnectionError(tr("Can't connect to internal core at the moment [serious breakage due to switch to dynamic signals]. Please check back later."));
-    return;
-    if(Global::runMode != Global::Monolithic) {
-      coreConnectionError(tr("Can't connect to internal core, since we are running as a standalone GUI!"));
-      return;
+void CoreConnectDlg::restartPhaseNull() {
+  doingAutoConnect = false;
+  ui.stackedWidget->setCurrentWidget(ui.accountPage);
+  clientSyncer->disconnectFromCore();
+}
+
+/*********************************************************
+ * Phase Two: Login
+ *********************************************************/
+
+void CoreConnectDlg::startLogin() {
+  ui.connectIcon->setPixmap(QPixmap::fromImage(QImage(":/22x22/actions/network-connect")));
+  ui.loginStack->setCurrentWidget(ui.loginCredentialsPage);
+  ui.loginStack->setMinimumSize(ui.loginStack->sizeHint()); ui.loginStack->updateGeometry();
+  ui.loginButtonBox->setStandardButtons(QDialogButtonBox::Ok|QDialogButtonBox::Cancel);
+  if(!account["User"].toString().isEmpty()) {
+    ui.user->setText(account["User"].toString());
+    if(account["RememberPasswd"].toBool()) {
+      ui.password->setText(account["Password"].toString());
+      ui.rememberPasswd->setChecked(true);
+    } else {
+      ui.rememberPasswd->setChecked(false);
+      ui.password->setFocus();
     }
-    ui.connectionGroupBox->setTitle(tr("Connecting to internal core"));
-    ui.connectionProgress->hide();
+  } else ui.user->setFocus();
+  disconnect(ui.loginButtonBox, 0, this, 0);
+  connect(ui.loginButtonBox, SIGNAL(accepted()), this, SLOT(doLogin()));
+  connect(ui.loginButtonBox, SIGNAL(rejected()), this, SLOT(restartPhaseNull()));
+  if(doingAutoConnect) doLogin();
+}
+
+void CoreConnectDlg::doLogin() {
+  ui.loginGroup->setTitle(tr("Logging in..."));
+  ui.user->setDisabled(true);
+  ui.password->setDisabled(true);
+  ui.rememberPasswd->setDisabled(true);
+  ui.loginButtonBox->button(QDialogButtonBox::Ok)->setDisabled(true);
+  account["User"] = ui.user->text();
+  account["RememberPasswd"] = ui.rememberPasswd->isChecked();
+  if(ui.rememberPasswd->isChecked()) account["Password"] = ui.password->text();
+  else account.remove("Password");
+  CoreAccountSettings s;
+  s.storeAccount(accountName, account);
+  clientSyncer->loginToCore(account["User"].toString(), account["Password"].toString());
+}
+
+void CoreConnectDlg::setLoginWidgetStates() {
+  ui.loginButtonBox->button(QDialogButtonBox::Ok)->setDisabled(ui.user->text().isEmpty() || ui.password->text().isEmpty());
+}
+
+void CoreConnectDlg::loginFailed(const QString &error) {
+  ui.loginGroup->setTitle(tr("Login"));
+  ui.user->setEnabled(true);
+  ui.password->setEnabled(true);
+  ui.rememberPasswd->setEnabled(true);
+  ui.coreInfoLabel->setText(error);
+  ui.loginButtonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
+  ui.password->setFocus();
+  doingAutoConnect = false;
+}
+
+/************************************************************
+ * Phase Three: Syncing
+ ************************************************************/
+
+void CoreConnectDlg::startSync() {
+  ui.sessionProgress->setRange(0, 1);
+  ui.sessionProgress->setValue(0);
+  ui.networksProgress->setRange(0, 1);
+  ui.networksProgress->setValue(0);
+  ui.channelsProgress->setRange(0, 1);
+  ui.channelsProgress->setValue(0);
+  ui.ircUsersProgress->setRange(0, 1);
+  ui.ircUsersProgress->setValue(0);
+
+  ui.stackedWidget->setCurrentWidget(ui.syncPage);
+  // clean up old page
+  ui.loginGroup->setTitle(tr("Login"));
+  ui.user->setEnabled(true);
+  ui.password->setEnabled(true);
+  ui.rememberPasswd->setEnabled(true);
+  ui.loginButtonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
+}
+
+
+void CoreConnectDlg::coreSessionProgress(quint32 val, quint32 max) {
+  ui.sessionProgress->setRange(0, max);
+  ui.sessionProgress->setValue(val);
+
+}
+
+void CoreConnectDlg::coreNetworksProgress(quint32 val, quint32 max) {
+  if(max == 0) {
+    ui.networksProgress->setFormat("0/0");
+    ui.networksProgress->setRange(0, 1);
+    ui.networksProgress->setValue(1);
   } else {
-    ui.connectionGroupBox->setTitle(tr("Connecting to %1").arg(ui.hostEdit->text()));
-    conninfo["Host"] = ui.hostEdit->text();
-    conninfo["Port"] = ui.port->value();
-  }
-  conninfo["User"] = ui.userEdit->text();
-  conninfo["Password"] = ui.passwdEdit->text();
-  ui.profileLabel->hide(); ui.guiProfile->hide();
-  ui.newGuiProfile->hide(); ui.alwaysUseProfile->hide();
-  ui.connectionProgress->show();
-  try {
-    Client::instance()->connectToCore(conninfo);
-  } catch(Exception e) {
-    QString msg;
-    //if(!e.msg().isEmpty()) msg = tr("<br>%1").arg(e.msg()); // FIXME throw more detailed (vulgo: any) error msg
-    coreConnectionError(tr("Invalid user or password. Pleasy try again.%1").arg(msg));
-    //QMessageBox::warning(this, tr("Unknown account"), tr("Invalid user or password. Pleasy try again.%1").arg(msg));
-    //cancelConnect();
-    return;
+    ui.networksProgress->setFormat("%v/%m");
+    ui.networksProgress->setRange(0, max);
+    ui.networksProgress->setValue(val);
   }
 }
 
-void CoreConnectDlg::cancelConnect() {
-  ui.stackedWidget->setCurrentIndex(0);
+void CoreConnectDlg::coreChannelsProgress(quint32 val, quint32 max) {
+  if(max == 0) {
+    ui.channelsProgress->setFormat("0/0");
+    ui.channelsProgress->setRange(0, 1);
+    ui.channelsProgress->setValue(1);
+  } else {
+    ui.channelsProgress->setFormat("%v/%m");
+    ui.channelsProgress->setRange(0, max);
+    ui.channelsProgress->setValue(val);
+  }
 }
 
-void CoreConnectDlg::setStartState() { /*
-  ui.hostName->show(); ui.hostPort->show(); ui.hostLabel->show(); ui.portLabel->show();
-  ui.statusText->setText(tr("Connect to Quassel Core running on:"));
-  ui.buttonBox->button(QDialogButtonBox::Ok)->show();
-  ui.hostName->setEnabled(true); ui.hostPort->setEnabled(true);
-  ui.hostName->setSelection(0, ui.hostName->text().length()); */
-  ui.stackedWidget->setCurrentIndex(0);
+void CoreConnectDlg::coreIrcUsersProgress(quint32 val, quint32 max) {
+  if(max == 0) {
+    ui.ircUsersProgress->setFormat("0/0");
+    ui.ircUsersProgress->setRange(0, 1);
+    ui.ircUsersProgress->setValue(1);
+  } else {
+    ui.ircUsersProgress->setFormat("%v/%m");
+    ui.ircUsersProgress->setRange(0, max);
+    ui.ircUsersProgress->setValue(val);
+  }
 }
 
-void CoreConnectDlg::hostEditChanged(QString /*txt*/) {
-  //ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(txt.length());
-}
+/*****************************************************************************************
+ * CoreAccountEditDlg
+ *****************************************************************************************/
 
-void CoreConnectDlg::hostSelected() { /*
-  ui.hostName->hide(); ui.hostPort->hide(); ui.hostLabel->hide(); ui.portLabel->hide();
-  ui.statusText->setText(tr("Connecting to %1:%2" ).arg(ui.hostName->text()).arg(ui.hostPort->value()));
-  ui.buttonBox->button(QDialogButtonBox::Ok)->hide();
-  connect(ClientProxy::instance(), SIGNAL(coreConnected()), this, SLOT(coreConnected()));
-  connect(ClientProxy::instance(), SIGNAL(coreConnectionError(QString)), this, SLOT(coreConnectionError(QString)));
-  Client::instance()->connectToCore(ui.hostName->text(), ui.hostPort->value());
-*/
+CoreAccountEditDlg::CoreAccountEditDlg(const QString &name, const QVariantMap &acct, const QStringList &_existing, QWidget *parent) : QDialog(parent) {
+  ui.setupUi(this);
+  existing = _existing;
+  account = acct;
+  if(!name.isEmpty()) {
+    existing.removeAll(name);
+    ui.host->setText(acct["Host"].toString());
+    ui.port->setValue(acct["Port"].toUInt());
+    ui.useInternal->setChecked(acct["UseInternal"].toBool());
+    ui.accountName->setText(name);
+  } else {
+    setWindowTitle(tr("Add Core Account"));
+  }
 }
 
-void CoreConnectDlg::coreConnected() { /*
-  ui.hostLabel->hide(); ui.hostName->hide(); ui.portLabel->hide(); ui.hostPort->hide();
-  ui.statusText->setText(tr("Synchronizing..."));
-  QSettings s;
-  s.setValue("GUI/CoreHost", ui.hostName->text());
-  s.setValue("GUI/CorePort", ui.hostPort->value());
-  s.setValue("GUI/CoreAutoConnect", ui.autoConnect->isChecked());
-  connect(ClientProxy::instance(), SIGNAL(recvPartialItem(quint32, quint32)), this, SLOT(updateProgressBar(quint32, quint32)));
-  connect(ClientProxy::instance(), SIGNAL(csCoreState(QVariant)), this, SLOT(recvCoreState(QVariant)));
-  ui.progressBar->show();
-  QVariantMap initmsg;
-  initmsg["GUIProtocol"] = GUI_PROTOCOL;
-  // FIXME guiProxy->send(GS_CLIENT_INIT, QVariant(initmsg)); */
-  ui.connectionStatus->setText(tr("Connected to core."));
-  accept();
+QString CoreAccountEditDlg::accountName() const {
+  return ui.accountName->text();
 }
 
-void CoreConnectDlg::coreConnectionError(QString err) {
-  ui.stackedWidget->setCurrentIndex(0);
-  show(); // just in case we started hidden
-  QMessageBox::warning(this, tr("Connection Error"), tr("<b>Could not connect to Quassel Core!</b><br>\n") + err, QMessageBox::Retry);
-  //disconnect(ClientProxy::instance(), 0, this, 0); FIXME?
-  //ui.autoConnect->setChecked(false);
-  setStartState();
+QVariantMap CoreAccountEditDlg::accountData() {
+  account["Host"] = ui.host->text();
+  account["Port"] = ui.port->value();
+  account["UseInternal"] = ui.useInternal->isChecked();
+  return account;
 }
 
-void CoreConnectDlg::updateProgressBar(uint partial, uint total) {
-  ui.connectionProgress->setMaximum(total);
-  ui.connectionProgress->setValue(partial);
-  //qDebug() << "progress:" << partial << total;
+void CoreAccountEditDlg::setWidgetStates() {
+  bool ok = !accountName().isEmpty() && !existing.contains(accountName()) && (ui.useInternal->isChecked() || !ui.host->text().isEmpty());
+  ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(ok);
 }
 
-void CoreConnectDlg::recvCoreState(QVariant state) {
-  //ui.progressBar->hide();
-  coreState = state;
-  accept();
+void CoreAccountEditDlg::on_host_textChanged(const QString &text) {
+  Q_UNUSED(text);
+  setWidgetStates();
 }
 
-QVariant CoreConnectDlg::getCoreState() {
-  return coreState;
+void CoreAccountEditDlg::on_accountName_textChanged(const QString &text) {
+  Q_UNUSED(text);
+  setWidgetStates();
 }
 
-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);
+void CoreAccountEditDlg::on_useRemote_toggled(bool state) {
+  Q_UNUSED(state);
+  setWidgetStates();
 }
index 3b6f584..4714a01 100644 (file)
@@ -1,5 +1,5 @@
 /***************************************************************************
- *   Copyright (C) 2005-08 by the Quassel Project                          *
+ *   Copyright (C) 2005-08 by the Quassel IRC Team                         *
  *   devel@quassel-irc.org                                                 *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
  ***************************************************************************/
 
-#ifndef _CORECONNECTDLG_H
-#define _CORECONNECTDLG_H
+#ifndef _CORECONNECTDLG_H_
+#define _CORECONNECTDLG_H_
+
+#include <QAbstractSocket>
 
 #include "ui_coreconnectdlg.h"
+#include "ui_coreaccounteditdlg.h"
+
+class ClientSyncer;
 
-class CoreConnectDlg: public QDialog {
+class CoreConnectDlg : public QDialog {
   Q_OBJECT
 
   public:
-    CoreConnectDlg(QWidget *parent, bool doAutoConnect = false);
+    CoreConnectDlg(QWidget *parent = 0, bool = false);
     ~CoreConnectDlg();
-    QVariant getCoreState();
-
-    bool willDoInternalAutoConnect();
-    
-  public slots:
-    void doAutoConnect();
 
   private slots:
-    void createAccount();
-    void removeAccount();
-    void accountChanged(const QString & = "");
-    void setAccountEditEnabled(bool);
-    void autoConnectToggled(bool);
-    bool checkInputValid();
-    void hostEditChanged(QString);
-    void hostSelected();
-    void doConnect();
-
-    void coreConnected();
-    void coreConnectionError(QString);
-    //void coreConnectionMsg(const QString &);
-    //void coreConnectionProgress(uint partial, uint total);
-    void updateProgressBar(uint partial, uint total);
-    void recvCoreState(QVariant);
-    
-    void showConfigWizard(const QVariantMap &coredata);
+
+    /*** Phase Null: Accounts ***/
+    void restartPhaseNull();
+
+    void on_accountList_itemSelectionChanged();
+    void on_autoConnect_clicked(bool);
+
+    void on_addAccount_clicked();
+    void on_editAccount_clicked();
+    void on_deleteAccount_clicked();
+
+    void on_accountList_itemDoubleClicked(QListWidgetItem *item);
+    void on_accountButtonBox_accepted();
+
+    void setAccountWidgetStates();
+
+    /*** Phase One: Connection ***/
+    void connectToCore();
+
+    void initPhaseError(const QString &error);
+    void initPhaseMsg(const QString &msg);
+    void initPhaseSocketState(QAbstractSocket::SocketState);
+
+    /*** Phase Two: Login ***/
+    void startLogin();
+    void doLogin();
+    void loginFailed(const QString &);
+
+    void setLoginWidgetStates();
+
+    /*** Phase Three: Sync ***/
+    void startSync();
+
+    void coreSessionProgress(quint32, quint32);
+    void coreNetworksProgress(quint32, quint32);
+    void coreChannelsProgress(quint32, quint32);
+    void coreIrcUsersProgress(quint32, quint32);
 
   private:
     Ui::CoreConnectDlg ui;
-    QVariant coreState;
 
-    void cancelConnect();
-    void setStartState();
-    QVariantMap accountData;
-    QString curacc;
+    QString autoConnectAccount;
+    QHash<QString, QVariantMap> accounts;
+    QVariantMap account;
+    QString accountName;
+
+    bool doingAutoConnect;
+
+    ClientSyncer *clientSyncer;
+};
+
+class CoreAccountEditDlg : public QDialog {
+  Q_OBJECT
+
+  public:
+    CoreAccountEditDlg(const QString &name, const QVariantMap &data, const QStringList &existing = QStringList(), QWidget *parent = 0);
+
+    QString accountName() const;
+    QVariantMap accountData();
+
+  private slots:
+    void on_host_textChanged(const QString &);
+    void on_accountName_textChanged(const QString &);
+    void on_useRemote_toggled(bool);
+
+    void setWidgetStates();
+
+  private:
+    Ui::CoreAccountEditDlg ui;
+
+    QStringList existing;
+    QVariantMap account;
 };
 
 #endif
index 6c63404..8aa0bb2 100644 (file)
@@ -129,7 +129,7 @@ void MainWin::init() {
   // attach the BufferWidget to the PropertyMapper
   Client::bufferModel()->mapProperty(0, NetworkModel::BufferIdRole, ui.bufferWidget, "currentBuffer");
   connect(Client::networkModel(), SIGNAL(bufferAboutToBeRemoved(BufferId)),
-         ui.bufferWidget, SLOT(removeBuffer(BufferId)));
+          ui.bufferWidget, SLOT(removeBuffer(BufferId)));
 
   // attach the NickList to the PropertyMapper
   Client::bufferModel()->mapProperty(0, NetworkModel::BufferIdRole, nickListWidget, "currentBuffer");
@@ -237,14 +237,14 @@ void MainWin::showCoreConnectionDlg(bool autoConnect) {
   coreConnectDlg = new CoreConnectDlg(this, autoConnect);
   connect(coreConnectDlg, SIGNAL(finished(int)), this, SLOT(coreConnectionDlgFinished(int)));
   coreConnectDlg->setModal(true);
-  if(!autoConnect || !coreConnectDlg->willDoInternalAutoConnect())
+  //if(!autoConnect || !coreConnectDlg->willDoInternalAutoConnect())
     coreConnectDlg->show(); // avoid flicker and show dlg only if we do remote connect, which needs a progress bar
-  if(autoConnect) coreConnectDlg->doAutoConnect();
+  //if(autoConnect) coreConnectDlg->doAutoConnect();
 }
 
 void MainWin::coreConnectionDlgFinished(int /*code*/) {
-
   coreConnectDlg->close();
+  //exit(1);
 }
 
 
index 1f91e79..5570020 100644 (file)
@@ -11,7 +11,7 @@ HDRS += bufferwidget.h chatline-old.h chatwidget.h configwizard.h \
         topicwidget.h debugconsole.h
 
 FORMNAMES = identitiesdlg.ui identitieseditdlg.ui networkeditdlg.ui mainwin.ui nickeditdlg.ui serverlistdlg.ui \
-            servereditdlg.ui coreconnectdlg.ui bufferviewwidget.ui bufferwidget.ui nicklistwidget.ui settingsdlg.ui \
+            servereditdlg.ui coreaccounteditdlg.ui coreconnectdlg.ui bufferviewwidget.ui bufferwidget.ui nicklistwidget.ui settingsdlg.ui \
             buffermgmtpage.ui connectionpage.ui usermgmtpage.ui topicwidget.ui debugconsole.ui
 
 for(ui, FORMNAMES) {
diff --git a/src/qtui/ui/coreaccounteditdlg.ui b/src/qtui/ui/coreaccounteditdlg.ui
new file mode 100644 (file)
index 0000000..4f056bc
--- /dev/null
@@ -0,0 +1,239 @@
+<ui version="4.0" >
+ <class>CoreAccountEditDlg</class>
+ <widget class="QDialog" name="CoreAccountEditDlg" >
+  <property name="geometry" >
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>395</width>
+    <height>242</height>
+   </rect>
+  </property>
+  <property name="windowTitle" >
+   <string>Edit Core Account</string>
+  </property>
+  <layout class="QVBoxLayout" >
+   <item>
+    <layout class="QVBoxLayout" >
+     <item>
+      <widget class="QGroupBox" name="groupBox" >
+       <property name="title" >
+        <string>Account Details</string>
+       </property>
+       <layout class="QVBoxLayout" >
+        <item>
+         <layout class="QHBoxLayout" >
+          <item>
+           <widget class="QLabel" name="label" >
+            <property name="text" >
+             <string>Account Name:</string>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QLineEdit" name="accountName" />
+          </item>
+         </layout>
+        </item>
+        <item>
+         <layout class="QGridLayout" >
+          <item row="0" column="0" >
+           <widget class="QRadioButton" name="useInternal" >
+            <property name="enabled" >
+             <bool>false</bool>
+            </property>
+            <property name="text" >
+             <string/>
+            </property>
+           </widget>
+          </item>
+          <item row="0" column="1" colspan="2" >
+           <widget class="QLabel" name="label_4" >
+            <property name="enabled" >
+             <bool>false</bool>
+            </property>
+            <property name="text" >
+             <string>Use built-in Quassel Core</string>
+            </property>
+            <property name="buddy" >
+             <cstring>useInternal</cstring>
+            </property>
+           </widget>
+          </item>
+          <item row="1" column="0" >
+           <widget class="QRadioButton" name="useRemote" >
+            <property name="text" >
+             <string/>
+            </property>
+            <property name="checked" >
+             <bool>true</bool>
+            </property>
+           </widget>
+          </item>
+          <item row="1" column="1" >
+           <widget class="QLabel" name="label_2" >
+            <property name="text" >
+             <string>Remote host:</string>
+            </property>
+            <property name="buddy" >
+             <cstring>useRemote</cstring>
+            </property>
+           </widget>
+          </item>
+          <item row="1" column="2" >
+           <widget class="QLabel" name="label_3" >
+            <property name="text" >
+             <string>Port:</string>
+            </property>
+           </widget>
+          </item>
+          <item row="2" column="1" >
+           <widget class="QLineEdit" name="host" />
+          </item>
+          <item row="2" column="2" >
+           <widget class="QSpinBox" name="port" >
+            <property name="minimum" >
+             <number>1</number>
+            </property>
+            <property name="maximum" >
+             <number>65535</number>
+            </property>
+            <property name="value" >
+             <number>4242</number>
+            </property>
+           </widget>
+          </item>
+          <item row="3" column="1" colspan="2" >
+           <widget class="QCheckBox" name="useSSL" >
+            <property name="enabled" >
+             <bool>false</bool>
+            </property>
+            <property name="text" >
+             <string>Use secure connection (SSL)</string>
+            </property>
+            <property name="icon" >
+             <iconset resource="../../icons/icons.qrc" >:/16x16/actions/oxygen/16x16/actions/document-encrypt.png</iconset>
+            </property>
+            <property name="checked" >
+             <bool>false</bool>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </item>
+        <item>
+         <spacer>
+          <property name="orientation" >
+           <enum>Qt::Vertical</enum>
+          </property>
+          <property name="sizeHint" >
+           <size>
+            <width>20</width>
+            <height>40</height>
+           </size>
+          </property>
+         </spacer>
+        </item>
+       </layout>
+      </widget>
+     </item>
+     <item>
+      <widget class="QDialogButtonBox" name="buttonBox" >
+       <property name="orientation" >
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="standardButtons" >
+        <set>QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+  </layout>
+ </widget>
+ <resources>
+  <include location="../../icons/icons.qrc" />
+ </resources>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>CoreAccountEditDlg</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel" >
+     <x>263</x>
+     <y>230</y>
+    </hint>
+    <hint type="destinationlabel" >
+     <x>157</x>
+     <y>207</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>CoreAccountEditDlg</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel" >
+     <x>331</x>
+     <y>230</y>
+    </hint>
+    <hint type="destinationlabel" >
+     <x>286</x>
+     <y>207</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>useInternal</sender>
+   <signal>toggled(bool)</signal>
+   <receiver>host</receiver>
+   <slot>setDisabled(bool)</slot>
+   <hints>
+    <hint type="sourcelabel" >
+     <x>30</x>
+     <y>79</y>
+    </hint>
+    <hint type="destinationlabel" >
+     <x>92</x>
+     <y>143</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>useInternal</sender>
+   <signal>toggled(bool)</signal>
+   <receiver>port</receiver>
+   <slot>setDisabled(bool)</slot>
+   <hints>
+    <hint type="sourcelabel" >
+     <x>39</x>
+     <y>78</y>
+    </hint>
+    <hint type="destinationlabel" >
+     <x>331</x>
+     <y>144</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>useRemote</sender>
+   <signal>clicked(bool)</signal>
+   <receiver>host</receiver>
+   <slot>setFocus()</slot>
+   <hints>
+    <hint type="sourcelabel" >
+     <x>26</x>
+     <y>113</y>
+    </hint>
+    <hint type="destinationlabel" >
+     <x>184</x>
+     <y>146</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
index a840031..91ce6ca 100644 (file)
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>462</width>
-    <height>249</height>
+    <width>511</width>
+    <height>389</height>
    </rect>
   </property>
-  <property name="sizePolicy" >
-   <sizepolicy vsizetype="MinimumExpanding" hsizetype="Preferred" >
-    <horstretch>0</horstretch>
-    <verstretch>0</verstretch>
-   </sizepolicy>
-  </property>
   <property name="windowTitle" >
    <string>Connect to Quassel Core</string>
   </property>
-  <property name="windowIcon" >
-   <iconset/>
-  </property>
-  <property name="modal" >
-   <bool>false</bool>
-  </property>
   <layout class="QVBoxLayout" >
-   <property name="spacing" >
-    <number>6</number>
-   </property>
-   <property name="leftMargin" >
-    <number>0</number>
-   </property>
-   <property name="topMargin" >
-    <number>0</number>
-   </property>
-   <property name="rightMargin" >
-    <number>0</number>
-   </property>
-   <property name="bottomMargin" >
-    <number>0</number>
-   </property>
    <item>
-    <widget class="QStackedWidget" name="stackedWidget" >
-     <property name="currentIndex" >
+    <layout class="QVBoxLayout" >
+     <property name="spacing" >
       <number>0</number>
      </property>
-     <widget class="QWidget" name="page" >
-      <layout class="QGridLayout" >
-       <item row="0" column="0" >
-        <widget class="QGroupBox" name="groupBox" >
-         <property name="title" >
-          <string>Account Settings</string>
-         </property>
-         <layout class="QGridLayout" >
-          <item rowspan="2" row="0" column="0" >
-           <widget class="QLabel" name="label_5" >
-            <property name="text" >
-             <string>Account:</string>
-            </property>
-           </widget>
-          </item>
-          <item rowspan="2" row="0" column="1" colspan="2" >
-           <widget class="QComboBox" name="accountList" >
-            <property name="editable" >
-             <bool>false</bool>
-            </property>
-            <property name="insertPolicy" >
-             <enum>QComboBox::InsertAlphabetically</enum>
-            </property>
-           </widget>
-          </item>
-          <item rowspan="2" row="0" column="3" >
-           <widget class="QToolButton" name="editAccount" >
-            <property name="text" >
-             <string>...</string>
-            </property>
-            <property name="icon" >
-             <iconset resource="../../icons/icons.qrc" >:/22x22/actions/oxygen/22x22/actions/configure.png</iconset>
-            </property>
-            <property name="iconSize" >
-             <size>
-              <width>22</width>
-              <height>22</height>
-             </size>
-            </property>
-           </widget>
-          </item>
-          <item rowspan="2" row="0" column="4" >
-           <widget class="QToolButton" name="newAccount" >
-            <property name="text" >
-             <string>...</string>
-            </property>
-            <property name="icon" >
-             <iconset resource="../../icons/icons.qrc" >:/22x22/actions/oxygen/22x22/actions/list-add.png</iconset>
-            </property>
-            <property name="iconSize" >
-             <size>
-              <width>22</width>
-              <height>22</height>
-             </size>
-            </property>
-           </widget>
-          </item>
-          <item rowspan="2" row="0" column="5" colspan="2" >
-           <widget class="QToolButton" name="delAccount" >
-            <property name="text" >
-             <string>...</string>
-            </property>
-            <property name="icon" >
-             <iconset resource="../../icons/icons.qrc" >:/22x22/actions/oxygen/22x22/actions/edit-delete.png</iconset>
-            </property>
-            <property name="iconSize" >
-             <size>
-              <width>22</width>
-              <height>22</height>
-             </size>
-            </property>
-           </widget>
-          </item>
-          <item row="1" column="6" >
-           <spacer>
-            <property name="orientation" >
-             <enum>Qt::Horizontal</enum>
-            </property>
-            <property name="sizeHint" >
-             <size>
-              <width>20</width>
-              <height>20</height>
-             </size>
-            </property>
-           </spacer>
-          </item>
-          <item row="2" column="0" >
-           <widget class="QLabel" name="label_2" >
-            <property name="text" >
-             <string>Host:</string>
-            </property>
-           </widget>
-          </item>
-          <item row="2" column="1" colspan="2" >
-           <widget class="QLineEdit" name="hostEdit" />
-          </item>
-          <item row="2" column="3" colspan="4" >
-           <widget class="QCheckBox" name="internalCore" >
-            <property name="enabled" >
-             <bool>false</bool>
-            </property>
-            <property name="text" >
-             <string>Use internal</string>
-            </property>
-            <property name="checked" >
-             <bool>false</bool>
-            </property>
-           </widget>
-          </item>
-          <item row="3" column="0" >
-           <widget class="QLabel" name="label" >
-            <property name="text" >
-             <string>Port:</string>
-            </property>
-           </widget>
-          </item>
-          <item row="3" column="1" >
-           <widget class="QSpinBox" name="port" >
-            <property name="minimum" >
-             <number>1024</number>
-            </property>
-            <property name="maximum" >
-             <number>65535</number>
-            </property>
-            <property name="value" >
-             <number>4242</number>
-            </property>
-           </widget>
-          </item>
-          <item row="3" column="2" >
-           <spacer>
-            <property name="orientation" >
-             <enum>Qt::Horizontal</enum>
-            </property>
-            <property name="sizeHint" >
-             <size>
-              <width>211</width>
-              <height>20</height>
-             </size>
-            </property>
-           </spacer>
-          </item>
-          <item row="4" column="0" >
-           <widget class="QLabel" name="label_3" >
-            <property name="text" >
-             <string>User:</string>
-            </property>
-           </widget>
-          </item>
-          <item row="4" column="1" colspan="2" >
-           <widget class="QLineEdit" name="userEdit" />
-          </item>
-          <item row="5" column="0" >
-           <widget class="QLabel" name="label_4" >
-            <property name="text" >
-             <string>Password:</string>
-            </property>
-           </widget>
-          </item>
-          <item row="5" column="1" colspan="2" >
-           <widget class="QLineEdit" name="passwdEdit" >
-            <property name="echoMode" >
-             <enum>QLineEdit::Password</enum>
-            </property>
-           </widget>
-          </item>
-          <item row="5" column="3" colspan="4" >
-           <widget class="QCheckBox" name="rememberPasswd" >
-            <property name="text" >
-             <string>Remember</string>
-            </property>
-           </widget>
-          </item>
-         </layout>
-        </widget>
-       </item>
-       <item row="1" column="0" >
-        <spacer>
-         <property name="orientation" >
-          <enum>Qt::Vertical</enum>
-         </property>
-         <property name="sizeHint" >
-          <size>
-           <width>20</width>
-           <height>40</height>
-          </size>
-         </property>
-        </spacer>
-       </item>
-       <item row="2" column="0" >
-        <layout class="QHBoxLayout" >
-         <property name="spacing" >
-          <number>6</number>
-         </property>
-         <property name="leftMargin" >
-          <number>0</number>
-         </property>
-         <property name="topMargin" >
-          <number>0</number>
-         </property>
-         <property name="rightMargin" >
-          <number>0</number>
-         </property>
-         <property name="bottomMargin" >
-          <number>0</number>
-         </property>
+     <item>
+      <widget class="QStackedWidget" name="stackedWidget" >
+       <property name="currentIndex" >
+        <number>2</number>
+       </property>
+       <widget class="QWidget" name="accountPage" >
+        <layout class="QVBoxLayout" >
          <item>
-          <widget class="QCheckBox" name="autoConnect" >
-           <property name="text" >
-            <string>Always use this account</string>
-           </property>
-           <property name="checked" >
-            <bool>false</bool>
+          <widget class="QGroupBox" name="groupBox" >
+           <property name="title" >
+            <string>Connect to Quassel Core</string>
            </property>
+           <layout class="QHBoxLayout" >
+            <item>
+             <widget class="QListWidget" name="accountList" >
+              <property name="sortingEnabled" >
+               <bool>true</bool>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <layout class="QVBoxLayout" >
+              <item>
+               <widget class="QPushButton" name="editAccount" >
+                <property name="text" >
+                 <string>Edit...</string>
+                </property>
+                <property name="icon" >
+                 <iconset resource="../../icons/icons.qrc" >:/16x16/actions/oxygen/16x16/actions/configure.png</iconset>
+                </property>
+               </widget>
+              </item>
+              <item>
+               <widget class="QPushButton" name="addAccount" >
+                <property name="text" >
+                 <string>Add...</string>
+                </property>
+                <property name="icon" >
+                 <iconset resource="../../icons/icons.qrc" >:/16x16/actions/oxygen/16x16/actions/list-add.png</iconset>
+                </property>
+               </widget>
+              </item>
+              <item>
+               <widget class="QPushButton" name="deleteAccount" >
+                <property name="text" >
+                 <string>Delete</string>
+                </property>
+                <property name="icon" >
+                 <iconset resource="../../icons/icons.qrc" >:/16x16/actions/oxygen/16x16/actions/list-remove.png</iconset>
+                </property>
+               </widget>
+              </item>
+              <item>
+               <spacer>
+                <property name="orientation" >
+                 <enum>Qt::Vertical</enum>
+                </property>
+                <property name="sizeHint" >
+                 <size>
+                  <width>20</width>
+                  <height>40</height>
+                 </size>
+                </property>
+               </spacer>
+              </item>
+             </layout>
+            </item>
+           </layout>
           </widget>
          </item>
          <item>
-          <spacer>
-           <property name="orientation" >
-            <enum>Qt::Horizontal</enum>
-           </property>
-           <property name="sizeHint" >
-            <size>
-             <width>101</width>
-             <height>31</height>
-            </size>
-           </property>
-          </spacer>
+          <layout class="QHBoxLayout" >
+           <item>
+            <widget class="QCheckBox" name="autoConnect" >
+             <property name="text" >
+              <string>Always use this account</string>
+             </property>
+            </widget>
+           </item>
+           <item>
+            <widget class="QDialogButtonBox" name="accountButtonBox" >
+             <property name="orientation" >
+              <enum>Qt::Horizontal</enum>
+             </property>
+             <property name="standardButtons" >
+              <set>QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set>
+             </property>
+            </widget>
+           </item>
+          </layout>
          </item>
+        </layout>
+       </widget>
+       <widget class="QWidget" name="loginPage" >
+        <layout class="QVBoxLayout" >
          <item>
-          <widget class="QDialogButtonBox" name="buttonBox1" >
-           <property name="orientation" >
-            <enum>Qt::Horizontal</enum>
+          <widget class="QGroupBox" name="groupBox_2" >
+           <property name="title" >
+            <string>Initializing your connection</string>
            </property>
+           <layout class="QHBoxLayout" >
+            <item>
+             <layout class="QVBoxLayout" >
+              <item>
+               <layout class="QGridLayout" >
+                <item row="0" column="0" >
+                 <widget class="QLabel" name="connectIcon" >
+                  <property name="text" >
+                   <string/>
+                  </property>
+                  <property name="pixmap" >
+                   <pixmap resource="../../icons/icons.qrc" >:/22x22/actions/network-disconnect</pixmap>
+                  </property>
+                 </widget>
+                </item>
+                <item row="0" column="1" >
+                 <widget class="QLabel" name="connectLabel" >
+                  <property name="text" >
+                   <string>Connected to apollo.mindpool.net.</string>
+                  </property>
+                  <property name="alignment" >
+                   <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+                  </property>
+                  <property name="wordWrap" >
+                   <bool>false</bool>
+                  </property>
+                 </widget>
+                </item>
+                <item row="0" column="2" >
+                 <spacer>
+                  <property name="orientation" >
+                   <enum>Qt::Horizontal</enum>
+                  </property>
+                  <property name="sizeHint" >
+                   <size>
+                    <width>358</width>
+                    <height>21</height>
+                   </size>
+                  </property>
+                 </spacer>
+                </item>
+                <item row="1" column="1" colspan="2" >
+                 <widget class="QLabel" name="coreInfoLabel" >
+                  <property name="text" >
+                   <string>Core Info</string>
+                  </property>
+                  <property name="alignment" >
+                   <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
+                  </property>
+                  <property name="wordWrap" >
+                   <bool>true</bool>
+                  </property>
+                 </widget>
+                </item>
+               </layout>
+              </item>
+              <item>
+               <spacer>
+                <property name="orientation" >
+                 <enum>Qt::Vertical</enum>
+                </property>
+                <property name="sizeHint" >
+                 <size>
+                  <width>20</width>
+                  <height>40</height>
+                 </size>
+                </property>
+               </spacer>
+              </item>
+              <item>
+               <widget class="QStackedWidget" name="loginStack" >
+                <property name="currentIndex" >
+                 <number>0</number>
+                </property>
+                <widget class="QWidget" name="loginCredentialsPage" >
+                 <layout class="QVBoxLayout" >
+                  <item>
+                   <layout class="QVBoxLayout" >
+                    <item>
+                     <spacer>
+                      <property name="orientation" >
+                       <enum>Qt::Vertical</enum>
+                      </property>
+                      <property name="sizeHint" >
+                       <size>
+                        <width>20</width>
+                        <height>40</height>
+                       </size>
+                      </property>
+                     </spacer>
+                    </item>
+                    <item>
+                     <widget class="QGroupBox" name="loginGroup" >
+                      <property name="title" >
+                       <string>Login</string>
+                      </property>
+                      <layout class="QGridLayout" >
+                       <property name="leftMargin" >
+                        <number>9</number>
+                       </property>
+                       <item row="1" column="0" >
+                        <widget class="QLabel" name="label_2" >
+                         <property name="text" >
+                          <string>User:</string>
+                         </property>
+                        </widget>
+                       </item>
+                       <item row="1" column="1" >
+                        <widget class="QLineEdit" name="user" >
+                         <property name="text" >
+                          <string/>
+                         </property>
+                        </widget>
+                       </item>
+                       <item row="2" column="0" >
+                        <widget class="QLabel" name="label_3" >
+                         <property name="text" >
+                          <string>Password:</string>
+                         </property>
+                        </widget>
+                       </item>
+                       <item row="2" column="1" >
+                        <widget class="QLineEdit" name="password" >
+                         <property name="echoMode" >
+                          <enum>QLineEdit::Password</enum>
+                         </property>
+                        </widget>
+                       </item>
+                       <item row="3" column="1" >
+                        <widget class="QCheckBox" name="rememberPasswd" >
+                         <property name="text" >
+                          <string>Remember</string>
+                         </property>
+                        </widget>
+                       </item>
+                      </layout>
+                     </widget>
+                    </item>
+                   </layout>
+                  </item>
+                 </layout>
+                </widget>
+                <widget class="QWidget" name="loginEmptyPage" />
+               </widget>
+              </item>
+             </layout>
+            </item>
+           </layout>
+          </widget>
+         </item>
+         <item>
+          <widget class="QDialogButtonBox" name="loginButtonBox" >
            <property name="standardButtons" >
             <set>QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set>
            </property>
           </widget>
          </item>
         </layout>
-       </item>
-      </layout>
-     </widget>
-     <widget class="QWidget" name="page_2" >
-      <layout class="QVBoxLayout" >
-       <item>
-        <widget class="QGroupBox" name="connectionGroupBox" >
-         <property name="title" >
-          <string>Connecting to...</string>
-         </property>
-         <layout class="QVBoxLayout" >
-          <item>
-           <widget class="QLabel" name="connectionStatus" >
-            <property name="text" >
-             <string>Connecting...</string>
-            </property>
-           </widget>
-          </item>
-          <item>
-           <widget class="QProgressBar" name="connectionProgress" >
-            <property name="value" >
-             <number>0</number>
-            </property>
-            <property name="orientation" >
-             <enum>Qt::Horizontal</enum>
-            </property>
-           </widget>
-          </item>
-          <item>
-           <layout class="QHBoxLayout" >
-            <item>
-             <widget class="QLabel" name="profileLabel" >
-              <property name="text" >
-               <string>GUI Profile:</string>
-              </property>
-             </widget>
-            </item>
-            <item>
-             <widget class="QComboBox" name="guiProfile" >
-              <property name="sizePolicy" >
-               <sizepolicy vsizetype="Fixed" hsizetype="MinimumExpanding" >
-                <horstretch>0</horstretch>
-                <verstretch>0</verstretch>
-               </sizepolicy>
-              </property>
-             </widget>
-            </item>
+       </widget>
+       <widget class="QWidget" name="syncPage" >
+        <layout class="QVBoxLayout" >
+         <item>
+          <widget class="QGroupBox" name="groupBox_3" >
+           <property name="title" >
+            <string>Initializing your session...</string>
+           </property>
+           <layout class="QVBoxLayout" >
             <item>
-             <widget class="QPushButton" name="newGuiProfile" >
-              <property name="sizePolicy" >
-               <sizepolicy vsizetype="Fixed" hsizetype="Maximum" >
-                <horstretch>0</horstretch>
-                <verstretch>0</verstretch>
-               </sizepolicy>
-              </property>
-              <property name="text" >
-               <string>New...</string>
-              </property>
-             </widget>
+             <layout class="QVBoxLayout" >
+              <item>
+               <widget class="QLabel" name="label_6" >
+                <property name="text" >
+                 <string>&lt;b>Please be patient while your client synchronizes with the Quassel Core!&lt;/b></string>
+                </property>
+                <property name="alignment" >
+                 <set>Qt::AlignHCenter|Qt::AlignTop</set>
+                </property>
+                <property name="wordWrap" >
+                 <bool>true</bool>
+                </property>
+               </widget>
+              </item>
+              <item>
+               <layout class="QGridLayout" >
+                <item row="0" column="0" >
+                 <widget class="QLabel" name="progressLabel" >
+                  <property name="text" >
+                   <string>Session state:</string>
+                  </property>
+                 </widget>
+                </item>
+                <item row="0" column="1" >
+                 <widget class="QProgressBar" name="sessionProgress" >
+                  <property name="maximum" >
+                   <number>1</number>
+                  </property>
+                  <property name="value" >
+                   <number>0</number>
+                  </property>
+                 </widget>
+                </item>
+                <item row="1" column="0" >
+                 <widget class="QLabel" name="label" >
+                  <property name="text" >
+                   <string>Network states:</string>
+                  </property>
+                 </widget>
+                </item>
+                <item row="1" column="1" >
+                 <widget class="QProgressBar" name="networksProgress" >
+                  <property name="maximum" >
+                   <number>1</number>
+                  </property>
+                  <property name="value" >
+                   <number>0</number>
+                  </property>
+                  <property name="format" >
+                   <string>0/0</string>
+                  </property>
+                 </widget>
+                </item>
+                <item row="2" column="0" >
+                 <widget class="QLabel" name="label_4" >
+                  <property name="text" >
+                   <string>Channel states:</string>
+                  </property>
+                 </widget>
+                </item>
+                <item row="2" column="1" >
+                 <widget class="QProgressBar" name="channelsProgress" >
+                  <property name="maximum" >
+                   <number>1</number>
+                  </property>
+                  <property name="value" >
+                   <number>0</number>
+                  </property>
+                  <property name="format" >
+                   <string>0/0</string>
+                  </property>
+                 </widget>
+                </item>
+                <item row="3" column="0" >
+                 <widget class="QLabel" name="label_5" >
+                  <property name="text" >
+                   <string>User states:</string>
+                  </property>
+                 </widget>
+                </item>
+                <item row="3" column="1" >
+                 <widget class="QProgressBar" name="ircUsersProgress" >
+                  <property name="minimum" >
+                   <number>0</number>
+                  </property>
+                  <property name="maximum" >
+                   <number>1</number>
+                  </property>
+                  <property name="value" >
+                   <number>0</number>
+                  </property>
+                  <property name="format" >
+                   <string>0/0</string>
+                  </property>
+                 </widget>
+                </item>
+               </layout>
+              </item>
+              <item>
+               <spacer>
+                <property name="orientation" >
+                 <enum>Qt::Vertical</enum>
+                </property>
+                <property name="sizeHint" >
+                 <size>
+                  <width>483</width>
+                  <height>61</height>
+                 </size>
+                </property>
+               </spacer>
+              </item>
+             </layout>
             </item>
            </layout>
-          </item>
-          <item>
-           <widget class="QCheckBox" name="alwaysUseProfile" >
-            <property name="text" >
-             <string>Always use this profile</string>
-            </property>
-           </widget>
-          </item>
-         </layout>
-        </widget>
-       </item>
-       <item>
-        <spacer>
-         <property name="orientation" >
-          <enum>Qt::Vertical</enum>
-         </property>
-         <property name="sizeHint" >
-          <size>
-           <width>20</width>
-           <height>31</height>
-          </size>
-         </property>
-        </spacer>
-       </item>
-       <item>
-        <layout class="QHBoxLayout" >
-         <item>
-          <spacer>
-           <property name="orientation" >
-            <enum>Qt::Horizontal</enum>
-           </property>
-           <property name="sizeHint" >
-            <size>
-             <width>40</width>
-             <height>20</height>
-            </size>
-           </property>
-          </spacer>
+          </widget>
          </item>
          <item>
-          <widget class="QDialogButtonBox" name="buttonBox2" >
+          <widget class="QDialogButtonBox" name="syncButtonBox" >
            <property name="standardButtons" >
-            <set>QDialogButtonBox::Abort|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set>
+            <set>QDialogButtonBox::Abort</set>
+           </property>
+           <property name="centerButtons" >
+            <bool>true</bool>
            </property>
           </widget>
          </item>
         </layout>
-       </item>
-      </layout>
-     </widget>
-    </widget>
+       </widget>
+      </widget>
+     </item>
+    </layout>
    </item>
   </layout>
  </widget>
+ <tabstops>
+  <tabstop>accountButtonBox</tabstop>
+  <tabstop>accountList</tabstop>
+  <tabstop>editAccount</tabstop>
+  <tabstop>addAccount</tabstop>
+  <tabstop>deleteAccount</tabstop>
+  <tabstop>autoConnect</tabstop>
+  <tabstop>loginButtonBox</tabstop>
+  <tabstop>user</tabstop>
+  <tabstop>password</tabstop>
+  <tabstop>rememberPasswd</tabstop>
+  <tabstop>syncButtonBox</tabstop>
+ </tabstops>
  <resources>
-  <include location="../../images/icons.qrc" />
   <include location="../../icons/icons.qrc" />
  </resources>
  <connections>
   <connection>
-   <sender>buttonBox1</sender>
+   <sender>accountButtonBox</sender>
    <signal>rejected()</signal>
    <receiver>CoreConnectDlg</receiver>
    <slot>reject()</slot>
    <hints>
     <hint type="sourcelabel" >
-     <x>507</x>
-     <y>273</y>
+     <x>279</x>
+     <y>434</y>
     </hint>
     <hint type="destinationlabel" >
-     <x>297</x>
-     <y>151</y>
+     <x>286</x>
+     <y>237</y>
     </hint>
    </hints>
   </connection>
index 8c892e8..dbc3b46 100644 (file)
@@ -5,15 +5,15 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>430</width>
-    <height>444</height>
+    <width>465</width>
+    <height>482</height>
    </rect>
   </property>
   <property name="windowTitle" >
    <string>Server List</string>
   </property>
   <property name="windowIcon" >
-   <iconset resource="../images/icons.qrc" >:/default/server.png</iconset>
+   <iconset/>
   </property>
   <property name="sizeGripEnabled" >
    <bool>false</bool>
    <bool>false</bool>
   </property>
   <layout class="QVBoxLayout" >
-   <property name="margin" >
-    <number>8</number>
-   </property>
    <property name="spacing" >
     <number>6</number>
    </property>
+   <property name="leftMargin" >
+    <number>8</number>
+   </property>
+   <property name="topMargin" >
+    <number>8</number>
+   </property>
+   <property name="rightMargin" >
+    <number>8</number>
+   </property>
+   <property name="bottomMargin" >
+    <number>8</number>
+   </property>
    <item>
-    <layout class="QHBoxLayout" >
-     <property name="margin" >
-      <number>0</number>
+    <widget class="QLabel" name="label" >
+     <property name="text" >
+      <string>&lt;html>&lt;head>&lt;meta name="qrichtext" content="1" />&lt;style type="text/css">
+p, li { white-space: pre-wrap; }
+&lt;/style>&lt;/head>&lt;body style=" font-family:'DejaVu Sans'; font-size:11pt; font-weight:400; font-style:normal;">
+&lt;p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">&lt;span style=" font-size:14pt; font-weight:600; color:#ff0000;">Big Fat Warning: &lt;/span>&lt;span style=" font-size:14pt; color:#000000;">The settings in here now need a Core restart in order to take effect! This dialog is doomed and will go away as soon as its replacement is finished.&lt;/span>&lt;/p>&lt;/body>&lt;/html></string>
      </property>
+     <property name="alignment" >
+      <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
+     </property>
+     <property name="wordWrap" >
+      <bool>true</bool>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" >
      <property name="spacing" >
       <number>6</number>
      </property>
+     <property name="leftMargin" >
+      <number>0</number>
+     </property>
+     <property name="topMargin" >
+      <number>0</number>
+     </property>
+     <property name="rightMargin" >
+      <number>0</number>
+     </property>
+     <property name="bottomMargin" >
+      <number>0</number>
+     </property>
      <item>
       <widget class="QTreeWidget" name="networkTree" >
        <property name="dragEnabled" >
        <property name="sortingEnabled" >
         <bool>false</bool>
        </property>
+       <column>
+        <property name="text" >
+         <string>1</string>
+        </property>
+       </column>
       </widget>
      </item>
      <item>
       <layout class="QVBoxLayout" >
-       <property name="margin" >
-        <number>0</number>
-       </property>
        <property name="spacing" >
         <number>6</number>
        </property>
+       <property name="leftMargin" >
+        <number>0</number>
+       </property>
+       <property name="topMargin" >
+        <number>0</number>
+       </property>
+       <property name="rightMargin" >
+        <number>0</number>
+       </property>
+       <property name="bottomMargin" >
+        <number>0</number>
+       </property>
        <item>
         <widget class="QPushButton" name="addButton" >
          <property name="text" >
           <string>&amp;Add...</string>
          </property>
          <property name="icon" >
-          <iconset resource="../images/icons.qrc" >:/default/edit_add.png</iconset>
+          <iconset/>
          </property>
         </widget>
        </item>
           <string>&amp;Edit...</string>
          </property>
          <property name="icon" >
-          <iconset resource="../images/icons.qrc" >:/default/edit.png</iconset>
+          <iconset/>
          </property>
         </widget>
        </item>
           <string>&amp;Delete</string>
          </property>
          <property name="icon" >
-          <iconset resource="../images/icons.qrc" >:/default/edit_remove.png</iconset>
+          <iconset/>
          </property>
         </widget>
        </item>
    </item>
    <item>
     <layout class="QHBoxLayout" >
-     <property name="margin" >
-      <number>0</number>
-     </property>
      <property name="spacing" >
       <number>6</number>
      </property>
+     <property name="leftMargin" >
+      <number>0</number>
+     </property>
+     <property name="topMargin" >
+      <number>0</number>
+     </property>
+     <property name="rightMargin" >
+      <number>0</number>
+     </property>
+     <property name="bottomMargin" >
+      <number>0</number>
+     </property>
      <item>
       <widget class="QCheckBox" name="showOnStartup" >
        <property name="text" >
         <string>&amp;Connect</string>
        </property>
        <property name="icon" >
-        <iconset resource="../images/icons.qrc" >:/default/connect_creating.png</iconset>
+        <iconset/>
        </property>
        <property name="default" >
         <bool>false</bool>
         <string>C&amp;lose</string>
        </property>
        <property name="icon" >
-        <iconset resource="../images/icons.qrc" >:/default/button_cancel.png</iconset>
+        <iconset/>
        </property>
        <property name="default" >
         <bool>true</bool>
diff --git a/version.inc b/version.inc
new file mode 100644 (file)
index 0000000..653864e
--- /dev/null
@@ -0,0 +1,18 @@
+// Versioning, should be kept current :)
+// This is included in main.cpp
+
+{ using namespace Global;
+
+  quasselVersion = "0.2.0-pre";
+  quasselDate = "2008-01-12";
+  quasselBuild = 344;
+
+  //! Minimum client build number the core needs
+  clientBuildNeeded = 344;
+  clientVersionNeeded = quasselVersion;
+
+  //! Minimum core build number the client needs
+  coreBuildNeeded = 344;
+  coreVersionNeeded = quasselVersion;
+
+}