X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fclient%2Fnickmodel.cpp;h=d7e4248c35869d0b7fb497c92c367c7a8ead9448;hp=ad1884cad653bfa982b05bce2d901483a7e228e5;hb=e671e9da1edaab37ec403f575979f9a92a766e9a;hpb=b173301cf898a31c19835f0512883b3ac15cdf55 diff --git a/src/client/nickmodel.cpp b/src/client/nickmodel.cpp index ad1884ca..d7e4248c 100644 --- a/src/client/nickmodel.cpp +++ b/src/client/nickmodel.cpp @@ -21,12 +21,16 @@ #include "nickmodel.h" #include "ircchannel.h" +#include "ircuser.h" +#include -NickModel::NickModel(IrcChannel *channel) : QAbstractItemModel(channel) { - //QStringList list; list << "test1" << "test2"; - //setStringList(list); +NickModel::NickModel(IrcChannel *channel, QObject *parent) : QAbstractItemModel(parent) { + // we support 6 categories: q, a, o, h, v and standard + users = QVector >(6); + if(channel) setIrcChannel(channel); + else _ircChannel = 0; } NickModel::~NickModel() { @@ -34,3 +38,189 @@ NickModel::~NickModel() { } +IrcChannel *NickModel::ircChannel() const { + return _ircChannel; +} + +void NickModel::setIrcChannel(IrcChannel *channel) { + if(_ircChannel) { + disconnect(_ircChannel, 0, this, 0); + } + foreach(QList l, users) l.clear(); + _ircChannel = channel; + reset(); + if(_ircChannel) { + connect(channel, SIGNAL(ircUserJoined(IrcUser *)), this, SLOT(addUser(IrcUser *))); + connect(channel, SIGNAL(ircUserParted(IrcUser *)), this, SLOT(removeUser(IrcUser *))); + connect(channel, SIGNAL(ircUserNickSet(IrcUser *, QString)), this, SLOT(renameUser(IrcUser *))); + connect(channel, SIGNAL(ircUserModesSet(IrcUser *, QString)), this, SLOT(changeUserModes(IrcUser *))); + + foreach(IrcUser *ircuser, channel->ircUsers()) { + // TODO: make this efficient by sorting after everything is appended instead! + addUser(ircuser); + } + } + +} + +QVariant NickModel::headerData(int section, Qt::Orientation orientation, int role) const { + if(section == 0 && role == Qt::DisplayRole) { + if(ircChannel()) return ircChannel()->name(); + else return "No channel"; + } + return QAbstractItemModel::headerData(section, orientation, role); +} + +QModelIndex NickModel::index(int row, int column, const QModelIndex &parent) const { + if(!parent.isValid()) { // Top-level item, i.e. a nick category + if(column > 0) return QModelIndex(); + //int r = 0; + //for(int i = 0; i < row; i++) { // we need to skip empty categories + if(row > users.count()) { + qDebug() << "invalid model index!"; + return QModelIndex(); + } + return createIndex(row, column, 0); + } + // Second-level item, i.e. a nick. internalId() contains the parent category (starting at 1). + int cat = parent.row() + 1; + if(row > users[cat-1].count()) { + qDebug() << "invalid model index!"; + return QModelIndex(); + } + return createIndex(row, column, cat); +} + +QModelIndex NickModel::indexOfUser(IrcUser *user) const { + int idx = -1; int cat; + for(cat = users.count()-1; cat >= 0; cat--) { + // we count backwards, since most users will usually be in the last category + idx = users[cat].indexOf(user); + if(idx >=0) break; + } + if(idx < 0) { + qWarning("NickModel: Index of unknown user requested!"); + return QModelIndex(); + } + return createIndex(idx, 0, cat+1); +} + +QModelIndex NickModel::parent(const QModelIndex &index) const { + if(!index.isValid()) return QModelIndex(); + int cat = index.internalId(); + if(cat) return createIndex(cat-1, 0, 0); + else return QModelIndex(); +} + +int NickModel::rowCount(const QModelIndex &parent) const { + if(!parent.isValid()) { + if(!ircChannel()) return 1; // informative text + return users.count(); + } + int cat = parent.internalId(); + if(!cat) { // top-level item (category) + return users[parent.row()].count(); + } + return 0; // second-level items don't have children +} + +int NickModel::columnCount(const QModelIndex &) const { + //if(!ircChannel()) return 0; + return 1; // all our items have exactly one column +} + +QVariant NickModel::data(const QModelIndex &index, int role) const { + if(!index.isValid()) return QVariant(); + if(!ircChannel()) { + // we show one item with informative text + switch(role) { + case Qt::DisplayRole: return tr("Not in channel"); + default: return QVariant(); + } + } + int cat = index.internalId(); + if(!cat) { // top-level item (category) + if(role == Qt::DisplayRole) { + QString title; + switch(index.row()) { + case 0: title = tr("%n Owner(s)", "", users[index.row()].count()); break; + case 1: title = tr("%n Admin(s)", "", users[index.row()].count()); break; + case 2: title = tr("%n Operator(s)", "", users[index.row()].count()); break; + case 3: title = tr("%n Half-Op(s)", "", users[index.row()].count()); break; + case 4: title = tr("%n Voiced", "", users[index.row()].count()); break; + case 5: title = tr("%n User(s)", "", users[index.row()].count()); break; + default: + qDebug() << "invalid model index"; return QVariant(); + } + return title; + } else return QVariant(); + } else { + IrcUser *user = users[cat-1][index.row()]; + switch(role) { + case Qt::DisplayRole: + return user->nick(); + default: + return QVariant(); + } + } +} + +int NickModel::userCategory(IrcUser *user) const { + return categoryFromModes(ircChannel()->userModes(user)); +} + +int NickModel::categoryFromModes(const QString &modes) const { + int cat; + // we hardcode this even though we have PREFIX in networkinfo... but that wouldn't help with mapping modes to + // category strings anyway. + if(modes.contains('q')) cat = 1; + else if(modes.contains('a')) cat = 2; + else if(modes.contains('o')) cat = 3; + else if(modes.contains('h')) cat = 4; + else if(modes.contains('v')) cat = 5; + else cat = 6; + return cat; +} + +int NickModel::categoryFromIndex(const QModelIndex &index) const { + if(!index.isValid()) return -1; + return index.internalId(); +} + +void NickModel::addUser(IrcUser *user) { + int cat = userCategory(user); + beginInsertRows(createIndex(cat-1, 0, 0), 0, 0); + users[cat-1].prepend(user); + endInsertRows(); +} + +void NickModel::removeUser(IrcUser *user) { + // we don't know for sure which category this user was in, so we have to search + QModelIndex index = indexOfUser(user); + removeUser(index); +} + +void NickModel::removeUser(const QModelIndex &index) { + if(!index.isValid()) return; + beginRemoveRows(index.parent(), index.row(), index.row()); + users[index.internalId()-1].removeAt(index.row()); + endRemoveRows(); +} + +void NickModel::renameUser(IrcUser *user) { + QModelIndex index = indexOfUser(user); + emit dataChanged(index, index); +} + +void NickModel::changeUserModes(IrcUser *user) { + QModelIndex oldindex = indexOfUser(user); + if(categoryFromIndex(oldindex) == categoryFromModes(ircChannel()->userModes(user))) { + // User is still in same category, no change necessary + emit dataChanged(oldindex, oldindex); + } else { + removeUser(oldindex); + addUser(user); + } +} + +