diff --git a/core/account.cpp b/core/account.cpp index ebcfd38..31025a8 100644 --- a/core/account.cpp +++ b/core/account.cpp @@ -18,7 +18,11 @@ Account::Account(const QString& p_login, const QString& p_server, const QString& QXmppRosterManager& rm = client.rosterManager(); + QObject::connect(&rm, SIGNAL(rosterReceived()), this, SLOT(onRosterReceived())); + QObject::connect(&rm, SIGNAL(itemAdded(const QString&)), this, SLOT(onRosterItemAdded(const QString&))); + QObject::connect(&rm, SIGNAL(itemRemoved(const QString&)), this, SLOT(onRosterItemRemoved(const QString&))); + QObject::connect(&rm, SIGNAL(itemChanged(const QString&)), this, SLOT(onRosterItemChanged(const QString&))); } Account::~Account() @@ -30,7 +34,6 @@ Shared::ConnectionState Core::Account::getState() const return state; } - void Core::Account::connect() { if (state == Shared::disconnected) { @@ -97,24 +100,107 @@ void Core::Account::onRosterReceived() QStringList bj = rm.getRosterBareJids(); for (int i = 0; i < bj.size(); ++i) { const QString& jid = bj[i]; - QXmppRosterIq::Item re = rm.getRosterEntry(jid); - QSet gr = re.groups(); - int grCount = 0; - for (QSet::const_iterator itr = gr.begin(), end = gr.end(); itr != end; ++itr) { - const QString& groupName = *itr; - std::map::iterator gItr = groups.find(groupName); - if (gItr == groups.end()) { - gItr = groups.insert(std::make_pair(groupName, 0)).first; - emit addGroup(groupName); - } - gItr->second++; - emit addContact(jid, re.name(), groupName); - grCount++; - } - - if (grCount == 0) { - emit addContact(jid, re.name(), ""); - } + addedAccount(jid); + } +} + +void Core::Account::onRosterItemAdded(const QString& bareJid) +{ + addedAccount(bareJid); +} + +void Core::Account::onRosterItemChanged(const QString& bareJid) +{ + QXmppRosterManager& rm = client.rosterManager(); + QXmppRosterIq::Item re = rm.getRosterEntry(bareJid); + QSet newGroups = re.groups(); + QSet oldGroups; + + emit changeContact(bareJid, re.name()); + + for (std::map>::iterator itr = groups.begin(), end = groups.end(); itr != end; ++itr) { + std::set& contacts = itr->second; + std::set::const_iterator cItr = contacts.find(bareJid); + if (cItr != contacts.end()) { + oldGroups.insert(itr->first); + } + } + + QSet toRemove = oldGroups - newGroups; + QSet toAdd = newGroups - oldGroups; + + QSet removeGroups; + for (QSet::iterator itr = toRemove.begin(), end = toRemove.end(); itr != end; ++itr) { + const QString& groupName = *itr; + std::set& contacts = groups.find(groupName)->second; + contacts.erase(bareJid); + emit removeContact(bareJid, groupName); + if (contacts.size() == 0) { + removeGroups.insert(groupName); + } + } + + for (QSet::iterator itr = toAdd.begin(), end = toAdd.end(); itr != end; ++itr) { + const QString& groupName = *itr; + std::map>::iterator cItr = groups.find(groupName); + if (cItr == groups.end()) { + cItr = groups.insert(std::make_pair(groupName, std::set())).first; + emit addGroup(groupName); + } + cItr->second.insert(bareJid); + emit addContact(bareJid, re.name(), groupName); + } + + for (QSet::iterator itr = removeGroups.begin(), end = removeGroups.end(); itr != end; ++itr) { + const QString& groupName = *itr; + emit removeGroup(groupName); + groups.erase(groupName); + } +} + +void Core::Account::onRosterItemRemoved(const QString& bareJid) +{ + emit removeContact(bareJid); + + QSet toRemove; + for (std::map>::iterator itr = groups.begin(), end = groups.end(); itr != end; ++itr) { + std::set contacts = itr->second; + std::set::const_iterator cItr = contacts.find(bareJid); + if (cItr != contacts.end()) { + contacts.erase(cItr); + if (contacts.size() == 0) { + toRemove.insert(itr->first); + } + } + } + + for (QSet::iterator itr = toRemove.begin(), end = toRemove.end(); itr != end; ++itr) { + const QString& groupName = *itr; + emit removeGroup(groupName); + groups.erase(groupName); + } +} + +void Core::Account::addedAccount(const QString& jid) +{ + QXmppRosterManager& rm = client.rosterManager(); + QXmppRosterIq::Item re = rm.getRosterEntry(jid); + QSet gr = re.groups(); + int grCount = 0; + for (QSet::const_iterator itr = gr.begin(), end = gr.end(); itr != end; ++itr) { + const QString& groupName = *itr; + std::map>::iterator gItr = groups.find(groupName); + if (gItr == groups.end()) { + gItr = groups.insert(std::make_pair(groupName, std::set())).first; + emit addGroup(groupName); + } + gItr->second.insert(jid); + emit addContact(jid, re.name(), groupName); + grCount++; + } + + if (grCount == 0) { + emit addContact(jid, re.name(), ""); } } diff --git a/core/account.h b/core/account.h index 13d4ec4..000fb11 100644 --- a/core/account.h +++ b/core/account.h @@ -3,6 +3,7 @@ #include #include +#include #include #include "../global.h" @@ -31,6 +32,9 @@ signals: void addGroup(const QString& name); void removeGroup(const QString& name); void addContact(const QString& jid, const QString& name, const QString& group); + void removeContact(const QString& jid); + void removeContact(const QString& jid, const QString& group); + void changeContact(const QString& jid, const QString& name); private: QString name; @@ -39,13 +43,18 @@ private: QString password; QXmppClient client; Shared::ConnectionState state; - std::map groups; + std::map> groups; private slots: void onClientConnected(); void onClientDisconnected(); void onRosterReceived(); - + void onRosterItemAdded(const QString &bareJid); + void onRosterItemChanged(const QString &bareJid); + void onRosterItemRemoved(const QString &bareJid); + +private: + void addedAccount(const QString &bareJid); }; } diff --git a/core/squawk.cpp b/core/squawk.cpp index a1644ad..dc76170 100644 --- a/core/squawk.cpp +++ b/core/squawk.cpp @@ -77,6 +77,9 @@ void Core::Squawk::addAccount(const QString& login, const QString& server, const connect(acc, SIGNAL(addContact(const QString&, const QString&, const QString&)), this, SLOT(onAccountAddContact(const QString&, const QString&, const QString&))); connect(acc, SIGNAL(addGroup(const QString&)), this, SLOT(onAccountAddGroup(const QString&))); connect(acc, SIGNAL(removeGroup(const QString&)), this, SLOT(onAccountRemoveGroup(const QString&))); + connect(acc, SIGNAL(removeContact(const QString&)), this, SLOT(onAccountRemoveContact(const QString&))); + connect(acc, SIGNAL(removeContact(const QString&, const QString&)), this, SLOT(onAccountRemoveContact(const QString&, const QString&))); + connect(acc, SIGNAL(changeContact(const QString&, const QString&)), this, SLOT(onAccountChangeContact(const QString&, const QString&))); QMap map = { {"login", login}, @@ -132,3 +135,21 @@ void Core::Squawk::onAccountRemoveGroup(const QString& name) Account* acc = static_cast(sender()); emit removeGroup(acc->getName(), name); } + +void Core::Squawk::onAccountChangeContact(const QString& jid, const QString& name) +{ + Account* acc = static_cast(sender()); + emit changeContact(acc->getName(), jid, name); +} + +void Core::Squawk::onAccountRemoveContact(const QString& jid) +{ + Account* acc = static_cast(sender()); + emit removeContact(acc->getName(), jid); +} + +void Core::Squawk::onAccountRemoveContact(const QString& jid, const QString& group) +{ + Account* acc = static_cast(sender()); + emit removeContact(acc->getName(), jid, group); +} diff --git a/core/squawk.h b/core/squawk.h index fb37985..c518d87 100644 --- a/core/squawk.h +++ b/core/squawk.h @@ -28,6 +28,9 @@ signals: void addGroup(const QString& account, const QString& name); void removeGroup(const QString& account, const QString& name); void addContact(const QString& account, const QString& jid, const QString& name, const QString& group); + void removeContact(const QString& account, const QString& jid); + void removeContact(const QString& account, const QString& jid, const QString& group); + void changeContact(const QString& account, const QString& jid, const QString& name); public slots: void start(); @@ -51,6 +54,9 @@ private slots: void onAccountAddGroup(const QString& name); void onAccountRemoveGroup(const QString& name); void onAccountAddContact(const QString& jid, const QString& name, const QString& group); + void onAccountRemoveContact(const QString& jid); + void onAccountRemoveContact(const QString& jid, const QString& group); + void onAccountChangeContact(const QString& jid, const QString& name); }; } diff --git a/main.cpp b/main.cpp index c5e8d0b..0cbe020 100644 --- a/main.cpp +++ b/main.cpp @@ -38,6 +38,9 @@ int main(int argc, char *argv[]) &w, SLOT(addContact(const QString&, const QString&, const QString&, const QString&))); QObject::connect(squawk, SIGNAL(addGroup(const QString&, const QString&)), &w, SLOT(addGroup(const QString&, const QString&))); QObject::connect(squawk, SIGNAL(removeGroup(const QString&, const QString&)), &w, SLOT(removeGroup(const QString&, const QString&))); + QObject::connect(squawk, SIGNAL(removeContact(const QString&, const QString&)), &w, SLOT(removeContact(const QString&, const QString&))); + QObject::connect(squawk, SIGNAL(removeContact(const QString&, const QString&, const QString&)), &w, SLOT(removeContact(const QString&, const QString&, const QString&))); + QObject::connect(squawk, SIGNAL(changeContact(const QString&, const QString&, const QString&)), &w, SLOT(changeContact(const QString&, const QString&, const QString&))); coreThread->start(); diff --git a/ui/models/roster.cpp b/ui/models/roster.cpp index 69fe040..167eba4 100644 --- a/ui/models/roster.cpp +++ b/ui/models/roster.cpp @@ -332,7 +332,7 @@ void Models::Roster::removeGroup(const QString& account, const QString& name) Item* parent = item->parentItem(); int row = item->row(); - beginRemoveRows(createIndex(parent->row(), 1, parent), row, row); + beginRemoveRows(createIndex(parent->row(), 0, parent), row, row); parent->removeChild(row); endRemoveRows(); @@ -372,3 +372,76 @@ void Models::Roster::removeGroup(const QString& account, const QString& name) delete item; } +void Models::Roster::changeContact(const QString& account, const QString& jid, const QString& name) +{ + ElId id(account, jid); + std::multimap::iterator cBeg = contacts.lower_bound(id); + std::multimap::iterator cEnd = contacts.upper_bound(id); + + for (; cBeg != cEnd; ++cBeg) { + cBeg->second->setName(name); + } +} + +void Models::Roster::removeContact(const QString& account, const QString& jid) +{ + ElId id(account, jid); + std::multimap::iterator cBeg = contacts.lower_bound(id); + std::multimap::iterator cEnd = contacts.upper_bound(id); + + QSet toRemove; + for (; cBeg != cEnd; ++cBeg) { + Contact* contact = cBeg->second; + Item* parent = contact->parentItem(); + if (parent->type == Item::group && parent->childCount() == 1) { + toRemove.insert(parent->getName()); + } + int row = contact->row(); + beginRemoveRows(createIndex(parent->row(), 0, parent), row, row); + parent->removeChild(row); + endRemoveRows(); + delete contact; + } + + for (QSet::const_iterator itr = toRemove.begin(), end = toRemove.end(); itr != end; ++itr) { + removeGroup(account, *itr); + } +} + +void Models::Roster::removeContact(const QString& account, const QString& jid, const QString& group) +{ + ElId contactId(account, jid); + ElId groupId(account, group); + + std::map::iterator gItr = groups.find(groupId); + if (gItr == groups.end()) { + qDebug() << "An attempt to remove contact " << jid << " from non existing group " << group << " of account " << account <<", skipping"; + return; + } + Item* gr = gItr->second; + Contact* cont = 0; + + std::multimap::iterator cBeg = contacts.lower_bound(contactId); + std::multimap::iterator cEnd = contacts.upper_bound(contactId); + for (;cBeg != cEnd; ++cBeg) { + if (cBeg->second->parentItem() == gr) { + cont = cBeg->second; + break; + } + } + + if (cont == 0) { + qDebug() << "An attempt to remove contact " << jid << " of account " << account << " from group " << group <<", but there is no such contact in that group, skipping"; + return; + } + + int row = cont->row(); + beginRemoveRows(createIndex(gr->row(), 0, gr), row, row); + gr->removeChild(row); + endRemoveRows(); + delete cont; + + if (gr->childCount() == 0) { + removeGroup(account, group); + } +} diff --git a/ui/models/roster.h b/ui/models/roster.h index 7f511c0..f60a5e9 100644 --- a/ui/models/roster.h +++ b/ui/models/roster.h @@ -27,6 +27,9 @@ public: void addGroup(const QString& account, const QString& name); void removeGroup(const QString& account, const QString& name); void addContact(const QString& account, const QString& jid, const QString& name, const QString& group); + void removeContact(const QString& account, const QString& jid, const QString& group); + void removeContact(const QString& account, const QString& jid); + void changeContact(const QString& account, const QString& jid, const QString& name); QVariant data ( const QModelIndex& index, int role ) const override; Qt::ItemFlags flags(const QModelIndex &index) const override; diff --git a/ui/squawk.cpp b/ui/squawk.cpp index 21048fd..8ebdbc2 100644 --- a/ui/squawk.cpp +++ b/ui/squawk.cpp @@ -98,8 +98,23 @@ void Squawk::addGroup(const QString& account, const QString& name) void Squawk::removeGroup(const QString& account, const QString& name) { + rosterModel.removeGroup(account, name); +} + +void Squawk::changeContact(const QString& account, const QString& jid, const QString& name) +{ + rosterModel.changeContact(account, jid, name); +} + +void Squawk::removeContact(const QString& account, const QString& jid) +{ + rosterModel.removeContact(account, jid); +} + +void Squawk::removeContact(const QString& account, const QString& jid, const QString& group) +{ + rosterModel.removeContact(account, jid, group); } - diff --git a/ui/squawk.h b/ui/squawk.h index 481c0b5..a573fee 100644 --- a/ui/squawk.h +++ b/ui/squawk.h @@ -35,6 +35,9 @@ public slots: void addGroup(const QString& account, const QString& name); void removeGroup(const QString& account, const QString& name); void addContact(const QString& account, const QString& jid, const QString& name, const QString& group); + void removeContact(const QString& account, const QString& jid, const QString& group); + void removeContact(const QString& account, const QString& jid); + void changeContact(const QString& account, const QString& jid, const QString& name); private: QScopedPointer m_ui;