Yet another protocol break (I warned you...).
authorMarcus Eggenberger <egs@quassel-irc.org>
Sat, 1 Mar 2008 22:08:48 +0000 (22:08 +0000)
committerMarcus Eggenberger <egs@quassel-irc.org>
Sat, 1 Mar 2008 22:08:48 +0000 (22:08 +0000)
Major speed improvement when joining channels.
Please let me know if you notice any weird issues.

12 files changed:
src/client/networkmodel.cpp
src/client/networkmodel.h
src/client/treemodel.cpp
src/client/treemodel.h
src/common/ircchannel.cpp
src/common/ircchannel.h
src/common/ircuser.cpp
src/common/ircuser.h
src/common/network.cpp
src/common/network.h
src/core/ircserverhandler.cpp
version.inc

index 94d90b8..0582d44 100644 (file)
@@ -131,8 +131,8 @@ void BufferItem::attachIrcChannel(IrcChannel *ircChannel) {
 
   connect(ircChannel, SIGNAL(topicSet(QString)),
          this, SLOT(setTopic(QString)));
-  connect(ircChannel, SIGNAL(ircUserJoined(IrcUser *)),
-         this, SLOT(join(IrcUser *)));
+  connect(ircChannel, SIGNAL(ircUsersJoined(QList<IrcUser *>)),
+         this, SLOT(join(QList<IrcUser *>)));
   connect(ircChannel, SIGNAL(ircUserParted(IrcUser *)),
          this, SLOT(part(IrcUser *)));
   connect(ircChannel, SIGNAL(destroyed()),
@@ -146,9 +146,7 @@ void BufferItem::attachIrcChannel(IrcChannel *ircChannel) {
 
   if(!ircChannel->ircUsers().isEmpty()) {
     qWarning() << "Channel" << ircChannel->name() << "has already users which is quite surprising :)";
-    foreach(IrcUser *ircUser, ircChannel->ircUsers()) {
-      join(ircUser);
-    }
+    join(ircChannel->ircUsers());
   }
   
   emit dataChanged();
@@ -200,30 +198,41 @@ void BufferItem::setTopic(const QString &topic) {
   emit dataChanged(1);
 }
 
-void BufferItem::join(IrcUser *ircUser) {
-  if(!ircUser)
-    return;
+void BufferItem::join(const QList<IrcUser *> &ircUsers) {
+  addUsersToCategory(ircUsers);
 
-  addUserToCategory(ircUser);
-  connect(ircUser, SIGNAL(destroyed()),
-         this, SLOT(ircUserDestroyed()));
+  foreach(IrcUser *ircUser, ircUsers) {
+    if(!ircUser)
+      continue;
+    connect(ircUser, SIGNAL(destroyed()), this, SLOT(ircUserDestroyed()));
+  }
+  
   emit dataChanged(2);
 }
 
 void BufferItem::addUserToCategory(IrcUser *ircUser) {
+  addUsersToCategory(QList<IrcUser *>() << ircUser);
+}
+
+void BufferItem::addUsersToCategory(const QList<IrcUser *> &ircUsers) {
   Q_ASSERT(_ircChannel);
 
-  UserCategoryItem *categoryItem;
-  int categoryId = UserCategoryItem::categoryFromModes(_ircChannel->userModes(ircUser));
-  if(!(categoryItem = qobject_cast<UserCategoryItem *>(childById(qHash(categoryId))))) {
-    categoryItem = new UserCategoryItem(categoryId, this);
-    newChild(categoryItem);
+  QHash<UserCategoryItem *, QList<IrcUser *> > categories;
+  foreach(IrcUser *ircUser, ircUsers) {
+    UserCategoryItem *categoryItem;
+    int categoryId = UserCategoryItem::categoryFromModes(_ircChannel->userModes(ircUser));
+    if(!(categoryItem = qobject_cast<UserCategoryItem *>(childById(qHash(categoryId))))) {
+      categoryItem = new UserCategoryItem(categoryId, this);
+      categories[categoryItem] = QList<IrcUser *>();
+      newChild(categoryItem);
+    }
+    categories[categoryItem] << ircUser;
   }
-  categoryItem->addUser(ircUser);
 
-  int totalusers = 0;
-  for(int i = 0; i < childCount(); i++) {
-    totalusers += child(i)->childCount();
+  QHash<UserCategoryItem *, QList<IrcUser *> >::const_iterator catIter = categories.constBegin();
+  while(catIter != categories.constEnd()) {
+    catIter.key()->addUsers(catIter.value());
+    catIter++;
   }
 }
 
@@ -267,11 +276,6 @@ void BufferItem::removeUserFromCategory(IrcUser *ircUser) {
     qDebug() << "==== End Of Childlist for Item:" << this << id() << bufferName() << "====";
   }
   Q_ASSERT(success);
-
-  int totalusers = 0;
-  for(int i = 0; i < childCount(); i++) {
-    totalusers += child(i)->childCount();
-  }
 }
 
 void BufferItem::userModeChanged(IrcUser *ircUser) {
@@ -496,8 +500,11 @@ quint64 UserCategoryItem::id() const {
   return qHash(_category);
 }
 
-void UserCategoryItem::addUser(IrcUser *ircUser) {
-  newChild(new IrcUserItem(ircUser, this));
+void UserCategoryItem::addUsers(const QList<IrcUser *> &ircUsers) {
+  QList<AbstractTreeItem *> userItems;
+  foreach(IrcUser *ircUser, ircUsers)
+    userItems << new IrcUserItem(ircUser, this);
+  newChilds(userItems);
 }
 
 bool UserCategoryItem::removeUser(IrcUser *ircUser) {
index 208503c..d9598c9 100644 (file)
@@ -81,10 +81,11 @@ public:
 
 public slots:
   void setTopic(const QString &topic);
-  void join(IrcUser *ircUser);
+  void join(const QList<IrcUser *> &ircUsers);
   void part(IrcUser *ircUser);
 
   void addUserToCategory(IrcUser *ircUser);
+  void addUsersToCategory(const QList<IrcUser *> &ircUser);
   void removeUserFromCategory(IrcUser *ircUser);
   void userModeChanged(IrcUser *ircUser);
 
@@ -152,7 +153,7 @@ public:
   virtual quint64 id() const;
   virtual QVariant data(int column, int role) const;
   
-  void addUser(IrcUser *ircUser);
+  void addUsers(const QList<IrcUser *> &ircUser);
   bool removeUser(IrcUser *ircUser);
 
   static int categoryFromModes(const QString &modes);
index 9a01abf..d66cc3a 100644 (file)
@@ -51,6 +51,35 @@ bool AbstractTreeItem::newChild(AbstractTreeItem *item) {
   return true;
 }
 
+bool AbstractTreeItem::newChilds(const QList<AbstractTreeItem *> &items) {
+  if(items.isEmpty())
+    return false;
+  
+  QList<AbstractTreeItem *>::const_iterator itemIter = items.constBegin();
+  AbstractTreeItem *item;
+  while(itemIter != items.constEnd()) {
+    item = *itemIter;
+    if(childById(item->id()) != 0) {
+      qWarning() << "AbstractTreeItem::newChilds(): received child that is already attached" << item << item->id();
+      return false;
+    }
+    itemIter++;
+  }
+
+  int nextRow = childCount();
+  int lastRow = nextRow + items.count() - 1;
+
+  emit beginAppendChilds(nextRow, lastRow);
+  itemIter = items.constBegin();
+  while(itemIter != items.constEnd()) {
+    _childItems.append(*itemIter);
+    itemIter++;
+  }
+  emit endAppendChilds();
+
+  return true;
+}
+
 bool AbstractTreeItem::removeChild(int row) {
   if(childCount() <= row)
     return false;
index 6eef89f..3a1c144 100644 (file)
@@ -41,6 +41,7 @@ public:
   virtual ~AbstractTreeItem();
 
   bool newChild(AbstractTreeItem *child);
+  bool newChilds(const QList<AbstractTreeItem *> &items);
 
   bool removeChild(int row);
   bool removeChildById(const quint64 &id);
index 832a5a9..eb63dd5 100644 (file)
@@ -125,21 +125,62 @@ void IrcChannel::setPassword(const QString &password) {
   emit passwordSet(password);
 }
 
-void IrcChannel::join(IrcUser *ircuser) {
-  if(!_userModes.contains(ircuser) && ircuser) {
-    _userModes[ircuser] = QString();
+void IrcChannel::joinIrcUsers(const QList<IrcUser *> &users, const QStringList &modes) {
+  if(users.isEmpty())
+    return;
+
+  if(users.count() != modes.count()) {
+    qWarning() << "IrcChannel::addUsers(): number of nicks does not match number of modes!";
+    return;
+  }
+
+  QStringList newNicks;
+  QStringList newModes;
+  QList<IrcUser *> newUsers;
+
+  IrcUser *ircuser;
+  for(int i = 0; i < users.count(); i++) {
+    ircuser = users[i];
+    if(!ircuser || _userModes.contains(ircuser))
+      continue;
+
+    _userModes[ircuser] = modes[i];
     ircuser->joinChannel(this);
     //qDebug() << "JOIN" << name() << ircuser->nick() << ircUsers().count();
     connect(ircuser, SIGNAL(nickSet(QString)), this, SLOT(ircUserNickSet(QString)));
     connect(ircuser, SIGNAL(destroyed()), this, SLOT(ircUserDestroyed()));
     // if you wonder why there is no counterpart to ircUserJoined:
     // the joines are propagted by the ircuser. the signal ircUserJoined is only for convenience
-    emit ircUserJoined(ircuser);
+
+    newNicks << ircuser->nick();
+    newModes << modes[i];
+    newUsers << ircuser;
   }
+
+  if(newNicks.isEmpty())
+    return;
+  
+  emit ircUsersJoined(newUsers);
+  emit ircUsersJoined(newNicks, newModes);
+}
+
+void IrcChannel::joinIrcUsers(const QStringList &nicks, const QStringList &modes) {
+  QList<IrcUser *> users;
+  foreach(QString nick, nicks)
+    users << network->newIrcUser(nick);
+  joinIrcUsers(users, modes);
+}
+                     
+void IrcChannel::joinIrcUsers(IrcUser *ircuser) {
+  QList <IrcUser *> users;
+  users << ircuser;
+  QStringList modes;
+  modes << QString();
+  joinIrcUsers(users, modes);
 }
 
-void IrcChannel::join(const QString &nick) {
-  join(network->ircUser(nick));
+void IrcChannel::joinIrcUsers(const QString &nick) {
+  joinIrcUsers(network->newIrcUser(nick));
 }
 
 void IrcChannel::part(IrcUser *ircuser) {
index dfc8de0..26340ce 100644 (file)
@@ -69,8 +69,10 @@ public slots:
   void setTopic(const QString &topic);
   void setPassword(const QString &password);
 
-  void join(IrcUser *ircuser);
-  void join(const QString &nick);
+  void joinIrcUsers(const QList<IrcUser *> &users, const QStringList &modes);
+  void joinIrcUsers(const QStringList &nicks, const QStringList &modes);
+  void joinIrcUsers(IrcUser *ircuser);
+  void joinIrcUsers(const QString &nick);
 
   void part(IrcUser *ircuser);
   void part(const QString &nick);
@@ -100,7 +102,8 @@ signals:
   void userModeRemoved(QString nick, QString mode);
   //void userModeRemoved(IrcUser *ircuser, QString mode);
 
-  void ircUserJoined(IrcUser *ircuser);
+  void ircUsersJoined(QList<IrcUser *> ircusers);
+  void ircUsersJoined(QStringList nicks, QStringList modes);
   void ircUserParted(IrcUser *ircuser);
   void ircUserNickSet(IrcUser *ircuser, QString nick);
   void ircUserModeAdded(IrcUser *ircuser, QString mode);
index efa7541..4c12580 100644 (file)
@@ -243,9 +243,8 @@ void IrcUser::joinChannel(IrcChannel *channel) {
   Q_ASSERT(channel);
   if(!_channels.contains(channel)) {
     _channels.insert(channel);
-    channel->join(this);
+    channel->joinIrcUsers(this);
     connect(channel, SIGNAL(destroyed()), this, SLOT(channelDestroyed()));
-    emit channelJoined(channel->name());
   }
 }
 
@@ -259,7 +258,7 @@ void IrcUser::partChannel(IrcChannel *channel) {
     disconnect(channel, 0, this, 0);
     channel->part(this);
     emit channelParted(channel->name());
-    if(_channels.isEmpty())
+    if(_channels.isEmpty() && network()->isMe(this))
       deleteLater();
   }
 }
@@ -278,6 +277,8 @@ void IrcUser::channelDestroyed() {
   IrcChannel *channel = static_cast<IrcChannel*>(sender());
   if(_channels.contains(channel)) {
     _channels.remove(channel);
+    if(_channels.isEmpty())
+      deleteLater();
   }
 }
 
index 3235158..176e36e 100644 (file)
@@ -123,7 +123,7 @@ signals:
 
   void userModesSet(QString modes);
 
-  void channelJoined(QString channel);
+  // void channelJoined(QString channel);
   void channelParted(QString channel);
 
   void userModeAdded(QString mode);
index c7343ca..2fbde1e 100644 (file)
@@ -290,6 +290,7 @@ IrcUser *Network::newIrcUser(const QString &hostmask) {
     
     connect(ircuser, SIGNAL(nickSet(QString)), this, SLOT(ircUserNickChanged(QString)));
     connect(ircuser, SIGNAL(initDone()), this, SLOT(ircUserInitDone()));
+    connect(ircuser, SIGNAL(destroyed()), this, SLOT(ircUserDestroyed()));
     _ircUsers[nick] = ircuser;
     emit ircUserAdded(hostmask);
     emit ircUserAdded(ircuser);
index 2bdda21..d065306 100644 (file)
@@ -181,6 +181,7 @@ public slots:
   void removeSupport(const QString &param);
 
   inline void addIrcUser(const QString &hostmask) { newIrcUser(hostmask); }
+  inline void addIrcChannel(const QString &channel) { newIrcChannel(channel); }
   void removeIrcUser(const QString &nick);
   void removeIrcChannel(const QString &channel);
 
index e46bb73..ae92b09 100644 (file)
@@ -558,6 +558,15 @@ void IrcServerHandler::handle353(const QString &prefix, const QList<QByteArray>
   // we don't use this information at the time beeing
   QString channelname = serverDecode(params[1]);
 
+  IrcChannel *channel = network()->ircChannel(channelname);
+  if(!channel) {
+    qWarning() << "IrcServerHandler::handle353(): received unknown target channel:" << channelname;
+    return;
+  }
+
+  QStringList nicks;
+  QStringList modes;
+  
   foreach(QString nick, serverDecode(params[2]).split(' ')) {
     QString mode = QString();
 
@@ -566,12 +575,11 @@ void IrcServerHandler::handle353(const QString &prefix, const QList<QByteArray>
       nick = nick.mid(1);
     }
 
-    IrcUser *ircuser = network()->newIrcUser(nick);
-    ircuser->joinChannel(channelname);
-
-    if(!mode.isNull())
-      network()->ircChannel(channelname)->addUserMode(ircuser, mode);
+    nicks << nick;
+    modes << mode;
   }
+  
+  channel->joinIrcUsers(nicks, modes);
 }
 
 /*  RPL_ENDOFWHOWAS - "<nick> :End of WHOWAS" */
index 7f0c146..116c53b 100644 (file)
@@ -5,7 +5,7 @@
 
   quasselVersion = "0.2.0-alpha3-pre";
   quasselDate = "2008-03-01";
-  quasselBuild = 606;
+  quasselBuild = 608;
 
   //! Minimum client build number the core needs
   clientBuildNeeded = 605;