diff --git a/ui/models/account.cpp b/ui/models/account.cpp index a60315c..00dd6b2 100644 --- a/ui/models/account.cpp +++ b/ui/models/account.cpp @@ -17,6 +17,8 @@ */ #include "account.h" +#include "contact.h" +#include "reference.h" #include Models::Account::Account(const QMap& data, Models::Item* parentItem): @@ -267,4 +269,3 @@ void Models::Account::setPasswordType(unsigned int pt) { setPasswordType(Shared::Global::fromInt(pt)); } - diff --git a/ui/models/account.h b/ui/models/account.h index d2bb79f..2563382 100644 --- a/ui/models/account.h +++ b/ui/models/account.h @@ -28,6 +28,9 @@ #include namespace Models { + class Contact; + class Reference; + class Account : public Item { Q_OBJECT public: diff --git a/ui/models/contact.cpp b/ui/models/contact.cpp index 9cd011a..cc3caba 100644 --- a/ui/models/contact.cpp +++ b/ui/models/contact.cpp @@ -17,10 +17,11 @@ */ #include "contact.h" +#include "account.h" #include -Models::Contact::Contact(const QString& p_jid ,const QMap &data, Item *parentItem): +Models::Contact::Contact(const Account* acc, const QString& p_jid ,const QMap &data, Item *parentItem): Item(Item::contact, data, parentItem), jid(p_jid), availability(Shared::Availability::offline), @@ -30,7 +31,8 @@ Models::Contact::Contact(const QString& p_jid ,const QMap &da messages(), childMessages(0), status(), - avatarPath() + avatarPath(), + account(acc) { QMap::const_iterator itr = data.find("state"); if (itr != data.end()) { @@ -368,7 +370,8 @@ Models::Contact::Contact(const Models::Contact& other): state(other.state), presences(), messages(other.messages), - childMessages(0) + childMessages(0), + account(other.account) { for (const Presence* pres : other.presences) { Presence* pCopy = new Presence(*pres); @@ -415,3 +418,9 @@ void Models::Contact::setAvatarState(unsigned int p_state) qDebug() << "An attempt to set invalid avatar state" << p_state << "to the contact" << jid << ", skipping"; } } + +const Models::Account * Models::Contact::getParentAccount() const +{ + return account; +} + diff --git a/ui/models/contact.h b/ui/models/contact.h index eb2be6b..39418ae 100644 --- a/ui/models/contact.h +++ b/ui/models/contact.h @@ -31,13 +31,14 @@ #include namespace Models { +class Account; class Contact : public Item { Q_OBJECT public: typedef std::deque Messages; - Contact(const QString& p_jid, const QMap &data, Item *parentItem = 0); + Contact(const Account* acc, const QString& p_jid, const QMap &data, Item *parentItem = 0); Contact(const Contact& other); ~Contact(); @@ -72,6 +73,7 @@ public: protected: void _removeChild(int index) override; bool columnInvolvedInDisplay(int col) override; + const Account* getParentAccount() const override; protected slots: void refresh(); @@ -98,6 +100,7 @@ private: unsigned int childMessages; QString status; QString avatarPath; + const Account* account; }; } diff --git a/ui/models/group.cpp b/ui/models/group.cpp index 76dc03e..5cf411b 100644 --- a/ui/models/group.cpp +++ b/ui/models/group.cpp @@ -18,6 +18,7 @@ #include "group.h" #include "contact.h" +#include "reference.h" Models::Group::Group(const QMap& data, Models::Item* parentItem): Item(group, data, parentItem), @@ -103,16 +104,3 @@ unsigned int Models::Group::getOnlineContacts() const return amount; } - -bool Models::Group::hasContact(const QString& jid) const -{ - for (Models::Item* item : childItems) { - if (item->type == Item::contact) { - const Contact* cnt = static_cast(item); - if (cnt->getJid() == jid) { - return true; - } - } - } - return false; -} diff --git a/ui/models/group.h b/ui/models/group.h index c2f4bfe..7343b63 100644 --- a/ui/models/group.h +++ b/ui/models/group.h @@ -23,6 +23,8 @@ namespace Models { +class Contact; + class Group : public Models::Item { Q_OBJECT @@ -36,8 +38,6 @@ public: unsigned int getUnreadMessages() const; unsigned int getOnlineContacts() const; - - bool hasContact(const QString& jid) const; protected: void _removeChild(int index) override; diff --git a/ui/models/item.cpp b/ui/models/item.cpp index b653702..566c26a 100644 --- a/ui/models/item.cpp +++ b/ui/models/item.cpp @@ -18,6 +18,8 @@ #include "item.h" #include "account.h" +#include "reference.h" +#include "contact.h" #include @@ -46,11 +48,16 @@ Models::Item::Item(const Models::Item& other): Models::Item::~Item() { - std::deque::const_iterator itr = childItems.begin(); - std::deque::const_iterator end = childItems.end(); + for (Reference* ref : references) { + Item* parent = ref->parentItem(); + if (parent != nullptr) { + parent->removeChild(ref->row()); + } + delete ref; + } - for (;itr != end; ++itr) { - delete (*itr); + for (Item* child : childItems) { + delete child; } } @@ -67,18 +74,26 @@ void Models::Item::appendChild(Models::Item* child) bool moving = false; int newRow = 0; std::deque::const_iterator before = childItems.begin(); + Type ct = child->type; + if (ct == reference) { + ct = static_cast(child)->dereference()->type; + } while (before != childItems.end()) { Item* bfr = *before; - if (bfr->type > child->type) { + Type bt = bfr->type; + if (bt == reference) { + bt = static_cast(bfr)->dereference()->type; + } + if (bt > ct) { break; - } else if (bfr->type == child->type && bfr->getDisplayedName() > child->getDisplayedName()) { + } else if (bt == ct && bfr->getDisplayedName() > child->getDisplayedName()) { break; } newRow++; before++; } - if (child->parent != 0) { + if (child->parent != nullptr) { int oldRow = child->row(); moving = true; emit childIsAboutToBeMoved(child->parent, oldRow, oldRow, this, newRow); @@ -116,7 +131,7 @@ int Models::Item::childCount() const int Models::Item::row() const { - if (parent != 0) { + if (parent != nullptr) { std::deque::const_iterator itr = parent->childItems.begin(); std::deque::const_iterator end = parent->childItems.end(); @@ -127,7 +142,7 @@ int Models::Item::row() const } } - return 0; //TODO not sure how it helps, i copy-pasted it from the example + return -1; //TODO not sure how it helps } Models::Item * Models::Item::parentItem() @@ -178,13 +193,13 @@ void Models::Item::_removeChild(int index) QObject::disconnect(child, &Item::childMoved, this, &Item::childMoved); childItems.erase(childItems.begin() + index); - child->parent = 0; + child->parent = nullptr; } void Models::Item::changed(int col) { - if (parent != 0) { + if (parent != nullptr) { emit childChanged(this, row(), col); } } @@ -197,21 +212,21 @@ void Models::Item::toOfflineState() } } -const Models::Item * Models::Item::getParentAccount() const +const Models::Account * Models::Item::getParentAccount() const { const Item* p = this; - while (p != 0 && p->type != Item::account) { + while (p != nullptr && p->type != Item::account) { p = p->parentItemConst(); } - return p; + return static_cast(p); } QString Models::Item::getAccountJid() const { - const Account* acc = static_cast(getParentAccount()); - if (acc == 0) { + const Account* acc = getParentAccount(); + if (acc == nullptr) { return ""; } return acc->getLogin() + "@" + acc->getServer(); @@ -219,8 +234,8 @@ QString Models::Item::getAccountJid() const QString Models::Item::getAccountResource() const { - const Account* acc = static_cast(getParentAccount()); - if (acc == 0) { + const Account* acc = getParentAccount(); + if (acc == nullptr) { return ""; } return acc->getResource(); @@ -228,8 +243,8 @@ QString Models::Item::getAccountResource() const QString Models::Item::getAccountName() const { - const Account* acc = static_cast(getParentAccount()); - if (acc == 0) { + const Account* acc = getParentAccount(); + if (acc == nullptr) { return ""; } return acc->getName(); @@ -237,8 +252,8 @@ QString Models::Item::getAccountName() const Shared::Availability Models::Item::getAccountAvailability() const { - const Account* acc = static_cast(getParentAccount()); - if (acc == 0) { + const Account* acc = getParentAccount(); + if (acc == nullptr) { return Shared::Availability::offline; } return acc->getAvailability(); @@ -246,8 +261,8 @@ Shared::Availability Models::Item::getAccountAvailability() const Shared::ConnectionState Models::Item::getAccountConnectionState() const { - const Account* acc = static_cast(getParentAccount()); - if (acc == 0) { + const Account* acc = getParentAccount(); + if (acc == nullptr) { return Shared::ConnectionState::disconnected; } return acc->getState(); @@ -261,15 +276,24 @@ QString Models::Item::getDisplayedName() const void Models::Item::onChildChanged(Models::Item* item, int row, int col) { Item* parent = item->parentItem(); - if (parent != 0 && parent == this) { + if (parent != nullptr && parent == this) { if (item->columnInvolvedInDisplay(col)) { int newRow = 0; std::deque::const_iterator before = childItems.begin(); + + Type ct = item->type; + if (ct == reference) { + ct = static_cast(item)->dereference()->type; + } while (before != childItems.end()) { Item* bfr = *before; - if (bfr->type > item->type) { + Type bt = bfr->type; + if (bt == reference) { + bt = static_cast(bfr)->dereference()->type; + } + if (bt > ct) { break; - } else if (bfr->type == item->type && bfr->getDisplayedName() > item->getDisplayedName()) { + } else if (bt == ct && bfr->getDisplayedName() > item->getDisplayedName()) { break; } newRow++; @@ -293,3 +317,42 @@ bool Models::Item::columnInvolvedInDisplay(int col) { return col == 0; } + +void Models::Item::addReference(Models::Reference* ref) +{ + references.insert(ref); +} + +void Models::Item::removeReference(Models::Reference* ref) +{ + std::set::const_iterator itr = references.find(ref); + if (itr != references.end()) { + references.erase(itr); + } +} + +int Models::Item::getContact(const QString& jid) const +{ + int index = -1; + for (std::deque::size_type i = 0; i < childItems.size(); ++i) { + const Models::Item* item = childItems[i]; + const Contact* cnt = nullptr; + if (item->type == Item::reference) { + item = static_cast(item)->dereferenceConst(); + } + + if (item->type == Item::contact) { + cnt = static_cast(item); + if (cnt->getJid() == jid) { + index = i; + break; + } + } + } + return index; +} + +std::set::size_type Models::Item::referencesCount() const +{ + return references.size(); +} diff --git a/ui/models/item.h b/ui/models/item.h index 77f2824..76f1780 100644 --- a/ui/models/item.h +++ b/ui/models/item.h @@ -24,11 +24,14 @@ #include #include +#include #include "shared/enums.h" namespace Models { class Reference; +class Contact; +class Account; class Item : public QObject{ friend class Reference; @@ -82,11 +85,17 @@ class Item : public QObject{ const Type type; + int getContact(const QString& jid) const; + std::set::size_type referencesCount() const; + + void addReference(Reference* ref); + void removeReference(Reference* ref); + protected: virtual void changed(int col); virtual void _removeChild(int index); virtual bool columnInvolvedInDisplay(int col); - const Item* getParentAccount() const; + virtual const Account* getParentAccount() const; protected slots: void onChildChanged(Models::Item* item, int row, int col); @@ -95,7 +104,7 @@ class Item : public QObject{ QString name; std::deque childItems; Item* parent; - std::deque references; + std::set references; protected slots: virtual void toOfflineState(); diff --git a/ui/models/reference.cpp b/ui/models/reference.cpp index 4ead77f..26d6b94 100644 --- a/ui/models/reference.cpp +++ b/ui/models/reference.cpp @@ -17,39 +17,37 @@ */ #include "reference.h" +#include using namespace Models; Models::Reference::Reference(Models::Item* original, Models::Item* parent): Models::Item(reference, {}, parent), - original(original) + original(original), + ax(-1), + bx(-1), + cx(-1), + c(false) { - original->references.push_back(this); + connect(original, &Item::childChanged, this, &Reference::onChildChanged); + connect(original, &Item::childIsAboutToBeInserted, this, &Reference::onChildIsAboutToBeInserted); + connect(original, &Item::childInserted, this, &Reference::onChildInserted); + connect(original, &Item::childIsAboutToBeRemoved, this, &Reference::onChildIsAboutToBeRemoved); + connect(original, &Item::childRemoved, this, &Reference::onChildRemoved); + connect(original, &Item::childIsAboutToBeMoved, this, &Reference::onChildIsAboutToBeMoved); + connect(original, &Item::childMoved, this, &Reference::onChildMoved); - connect(original, &Item::childChanged, this, &Item::childChanged); - connect(original, &Item::childIsAboutToBeInserted, this, &Item::childIsAboutToBeInserted); - connect(original, &Item::childInserted, this, &Item::childInserted); - connect(original, &Item::childIsAboutToBeRemoved, this, &Item::childIsAboutToBeRemoved); - connect(original, &Item::childRemoved, this, &Item::childRemoved); - connect(original, &Item::childIsAboutToBeMoved, this, &Item::childIsAboutToBeMoved); - connect(original, &Item::childMoved, this, &Item::childMoved); + original->addReference(this); } Models::Reference::~Reference() { - disconnect(original, &Item::childIsAboutToBeInserted, this, &Item::childIsAboutToBeInserted); - disconnect(original, &Item::childInserted, this, &Item::childInserted); - disconnect(original, &Item::childIsAboutToBeRemoved, this, &Item::childIsAboutToBeRemoved); - disconnect(original, &Item::childRemoved, this, &Item::childRemoved); - disconnect(original, &Item::childIsAboutToBeMoved, this, &Item::childIsAboutToBeMoved); - disconnect(original, &Item::childMoved, this, &Item::childMoved); - - for (std::deque::const_iterator itr = original->references.begin(), end = original->references.end(); itr != end; itr++) { - if (*itr == this) { - original->references.erase(itr); - break; - } - } + disconnect(original, &Item::childIsAboutToBeInserted, this, &Reference::onChildIsAboutToBeInserted); + disconnect(original, &Item::childInserted, this, &Reference::onChildInserted); + disconnect(original, &Item::childIsAboutToBeRemoved, this, &Reference::onChildIsAboutToBeRemoved); + disconnect(original, &Item::childRemoved, this, &Reference::onChildRemoved); + disconnect(original, &Item::childIsAboutToBeMoved, this, &Reference::onChildIsAboutToBeMoved); + disconnect(original, &Item::childMoved, this, &Reference::onChildMoved); } int Models::Reference::columnCount() const @@ -91,3 +89,79 @@ void Models::Reference::toOfflineState() { original->toOfflineState(); } + +void Models::Reference::onChildChanged(Models::Item* item, int row, int col) +{ + if (item == original) { + emit childChanged(this, row, col); + } +} + +void Models::Reference::onChildIsAboutToBeInserted(Models::Item* parent, int first, int last) +{ + if (parent == original) { + ax = first; + bx = last; + } +} + +void Models::Reference::onChildInserted() +{ + if (ax != -1 && bx != -1) { + for (int i = ax; i <= bx; ++i) { + Reference* ref = new Reference(original->child(i)); + Item::appendChild(ref); + } + ax = -1; + bx = -1; + } +} + +void Models::Reference::onChildIsAboutToBeRemoved(Models::Item* parent, int first, int last) +{ + if (parent == original) { + for (int i = first; i <= last; ++i) { + Reference* ref = static_cast(childItems[i]); + Item* orig = original->child(i); + orig->removeReference(ref); + Item::removeChild(i); + delete ref; + } + } +} + +void Models::Reference::onChildRemoved() +{ +} + +void Models::Reference::onChildIsAboutToBeMoved(Models::Item* source, int first, int last, Models::Item* destination, int newIndex) +{ + if (destination == original) { + if (source != original) { + c = true; + ax = first; + bx = last; + cx = newIndex; + emit childIsAboutToBeMoved(source, first, last, destination, newIndex); + } else { + ax = newIndex; + bx = newIndex + last - first + 1; + } + } +} + +void Models::Reference::onChildMoved() +{ + if (c) { + std::deque::const_iterator beg = childItems.begin() + ax; + std::deque::const_iterator end = childItems.begin() + bx + 1; + std::deque::const_iterator tgt = childItems.begin() + cx; + std::deque temp; + temp.insert(temp.end(), beg, end); + childItems.erase(beg, end); + childItems.insert(tgt, temp.begin(), temp.end()); + emit childMoved(); + } else { + onChildInserted(); + } +} diff --git a/ui/models/reference.h b/ui/models/reference.h index 84d0b07..8ec5352 100644 --- a/ui/models/reference.h +++ b/ui/models/reference.h @@ -30,7 +30,7 @@ class Reference : public Models::Item { Q_OBJECT public: - Reference(Models::Item* original, Models::Item* parent); + Reference(Models::Item* original, Models::Item* parent = 0); ~Reference(); int columnCount() const override; @@ -44,9 +44,21 @@ public: protected slots: void toOfflineState() override; +private slots: + void onChildChanged(Models::Item* item, int row, int col); + void onChildIsAboutToBeInserted(Item* parent, int first, int last); + void onChildInserted(); + void onChildIsAboutToBeRemoved(Item* parent, int first, int last); + void onChildRemoved(); + void onChildIsAboutToBeMoved(Item* source, int first, int last, Item* destination, int newIndex); + void onChildMoved(); + private: Models::Item* original; - + int ax; + int bx; + int cx; + bool c; }; } diff --git a/ui/models/roster.cpp b/ui/models/roster.cpp index f1e6efa..91f1f74 100644 --- a/ui/models/roster.cpp +++ b/ui/models/roster.cpp @@ -62,6 +62,9 @@ QVariant Models::Roster::data (const QModelIndex& index, int role) const QVariant result; Item *item = static_cast(index.internalPointer()); + if (item->type == Item::reference) { + item = static_cast(item)->dereference(); + } switch (role) { case Qt::DisplayRole: { @@ -430,7 +433,8 @@ void Models::Roster::addContact(const QString& account, const QString& jid, cons { Item* parent; Account* acc; - Contact* sample = 0; + Contact* contact; + Reference* ref = 0; ElId id(account, jid); { @@ -442,13 +446,18 @@ void Models::Roster::addContact(const QString& account, const QString& jid, cons acc = itr->second; } - for (std::multimap::iterator itr = contacts.lower_bound(id), eItr = contacts.upper_bound(id); itr != eItr; ++itr) { - sample = itr->second; //need to find if this contact is already added somewhere - break; //so one iteration is enough + { + std::map::iterator itr = contacts.find(id); + if (itr == contacts.end()) { + contact = new Contact(acc, jid, data); + contacts.insert(std::make_pair(id, contact)); + } else { + contact = itr->second; + } } - if (group == "") { //this means this contact is already added somewhere and there is no sense to add it ungrouped - if (sample != 0) { + if (group == "") { + if (acc->getContact(jid) != -1) { qDebug() << "An attempt to add a contact" << jid << "to the ungrouped contact set of account" << account << "for the second time, skipping"; return; } else { @@ -464,41 +473,26 @@ void Models::Roster::addContact(const QString& account, const QString& jid, cons parent = itr->second; - for (int i = 0; i < parent->childCount(); ++i) { //checking if the contact is already added to that group - Item* item = parent->child(i); - if (item->type == Item::contact) { - Contact* ca = static_cast(item); - if (ca->getJid() == jid) { - qDebug() << "An attempt to add a contact" << jid << "to the group" << group << "for the second time, skipping"; - return; - } - } + if (parent->getContact(jid) != -1) { + qDebug() << "An attempt to add a contact" << jid << "to the group" << group << "for the second time, skipping"; + return; } - for (int i = 0; i < acc->childCount(); ++i) { //checking if that contact is among ugrouped - Item* item = acc->child(i); - if (item->type == Item::contact) { - Contact* ca = static_cast(item); - if (ca->getJid() == jid) { - qDebug() << "An attempt to add a already existing contact " << jid - << " to the group " << group - << ", contact will be moved from ungrouped contacts of " << account; - - parent->appendChild(ca); - return; - } - } + int refIndex = acc->getContact(jid); + if (refIndex != -1) { //checking if that contact is among ugrouped + qDebug() << "An attempt to add a already existing contact " << jid + << " to the group " << group + << ", contact will be moved from ungrouped contacts of " << account; + ref = static_cast(acc->child(refIndex)); + acc->removeChild(refIndex); } } - Contact* contact; - if (sample == 0) { - contact = new Contact(jid, data); - } else { - contact = sample->copy(); + + if (ref == 0) { + ref = new Reference(contact); } - contacts.insert(std::make_pair(id, contact)); - parent->appendChild(contact); + parent->appendChild(ref); } void Models::Roster::removeGroup(const QString& account, const QString& name) @@ -515,33 +509,24 @@ void Models::Roster::removeGroup(const QString& account, const QString& name) parent->removeChild(row); - std::deque toInsert; + std::deque toInsert; for (int i = 0; item->childCount() > 0; ++i) { - Contact* cont = static_cast(item->child(0)); + Reference* ref = static_cast(item->child(0)); item->removeChild(0); - std::multimap::iterator cBeg = contacts.lower_bound({account, cont->getJid()}); - std::multimap::iterator cEnd = contacts.upper_bound({account, cont->getJid()}); - - int count = std::distance(cBeg, cEnd); - if (count > 1) { - for (; cBeg != cEnd; ++count, ++cBeg) { - if (cBeg->second == cont) { - delete cont; - contacts.erase(cBeg); - break; - } - } + Contact* cont = static_cast(ref->dereference()); + if (cont->referencesCount() == 1) { + toInsert.push_back(ref); } else { - toInsert.push_back(cont); + cont->removeReference(ref); + delete ref; } } if (toInsert.size() > 0) { Account* acc = accounts.find("account")->second; for (std::deque::size_type i = 0; i < toInsert.size(); ++i) { - Contact* cont = toInsert[i]; - acc->appendChild(cont); //TODO optimisation + acc->appendChild(toInsert[i]); //TODO optimisation } } @@ -552,19 +537,18 @@ void Models::Roster::removeGroup(const QString& account, const QString& name) void Models::Roster::changeContact(const QString& account, const QString& jid, const QMap& data) { ElId id(account, jid); - std::multimap::iterator cBeg = contacts.lower_bound(id); - std::multimap::iterator cEnd = contacts.upper_bound(id); + std::map::iterator cItr = contacts.find(id); - for (; cBeg != cEnd; ++cBeg) { + if (cItr != contacts.end()) { for (QMap::const_iterator itr = data.begin(), end = data.end(); itr != end; ++itr) { - cBeg->second->update(itr.key(), itr.value()); + cItr->second->update(itr.key(), itr.value()); } - } - - std::map::iterator rItr = rooms.find(id); - if (rItr != rooms.end()) { - for (QMap::const_iterator itr = data.begin(), end = data.end(); itr != end; ++itr) { - rItr->second->update(itr.key(), itr.value()); + } else { + std::map::iterator rItr = rooms.find(id); + if (rItr != rooms.end()) { + for (QMap::const_iterator itr = data.begin(), end = data.end(); itr != end; ++itr) { + rItr->second->update(itr.key(), itr.value()); + } } } } @@ -572,18 +556,13 @@ void Models::Roster::changeContact(const QString& account, const QString& jid, c void Models::Roster::changeMessage(const QString& account, const QString& jid, const QString& id, const QMap& data) { ElId elid(account, jid); - std::multimap::iterator cBeg = contacts.lower_bound(elid); - std::multimap::iterator cEnd = contacts.upper_bound(elid); + std::map::iterator cItr = contacts.find(elid); - for (; cBeg != cEnd; ++cBeg) { - for (QMap::const_iterator itr = data.begin(), end = data.end(); itr != end; ++itr) { - cBeg->second->changeMessage(id, data); - } - } - - std::map::iterator rItr = rooms.find(elid); - if (rItr != rooms.end()) { - for (QMap::const_iterator itr = data.begin(), end = data.end(); itr != end; ++itr) { + if (cItr != contacts.end()) { + cItr->second->changeMessage(id, data); + } else { + std::map::iterator rItr = rooms.find(elid); + if (rItr != rooms.end()) { rItr->second->changeMessage(id, data); } } @@ -592,25 +571,26 @@ void Models::Roster::changeMessage(const QString& account, const QString& jid, c 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); - std::multimap::iterator cpBeg = cBeg; + std::map::iterator itr = contacts.find(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()); + if (itr != contacts.end()) { + Contact* contact = itr->second; + + contacts.erase(itr); + delete contact; + + std::set toRemove; + for (std::pair pair : groups) { + if (pair.second->childCount() == 0) { + toRemove.insert(pair.first); + } } - parent->removeChild(contact->row()); - contact->deleteLater(); - } - contacts.erase(cpBeg, cEnd); - - for (QSet::const_iterator itr = toRemove.begin(), end = toRemove.end(); itr != end; ++itr) { - removeGroup(account, *itr); + for (const ElId& elId : toRemove) { + removeGroup(elId.account, elId.name); + } + } else { + qDebug() << "An attempt to remove contact " << jid << " from account " << account <<" which doesn't exist there, skipping"; } } @@ -619,6 +599,12 @@ void Models::Roster::removeContact(const QString& account, const QString& jid, c ElId contactId(account, jid); ElId groupId(account, group); + std::map::iterator cItr = contacts.find(contactId); + if (cItr == contacts.end()) { + qDebug() << "An attempt to remove non existing contact " << jid << " from group " << group << " of account " << account <<", skipping"; + return; + } + 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"; @@ -626,57 +612,26 @@ void Models::Roster::removeContact(const QString& account, const QString& jid, c } Account* acc = accounts.find(account)->second; //I assume the account is found, otherwise there will be no groups with that ElId; Group* gr = gItr->second; - Contact* cont = 0; + Contact* cont = cItr->second; - unsigned int entries(0); - unsigned int ungroupped(0); - for (std::multimap::iterator cBeg = contacts.lower_bound(contactId), cEnd = contacts.upper_bound(contactId); cBeg != cEnd; ++cBeg) { - ++entries; - Contact* elem = cBeg->second; - if (elem->parentItem() == acc) { - ++ungroupped; - } + int contRow = gr->getContact(jid); + if (contRow == -1) { + qDebug() << "An attempt to remove contact " << jid << " of account " << account << " from group " << group <<", but there is no such contact in that group, skipping"; + return; + } + Reference* ref = static_cast(gr->child(contRow)); + gr->removeChild(contRow); + + if (cont->referencesCount() == 1) { + qDebug() << "An attempt to remove last instance of contact" << jid << "from the group" << group << ", contact will be moved to ungrouped contacts of" << account; + acc->appendChild(ref); + } else { + cont->removeReference(ref); + delete ref; } - if (ungroupped == 0 && entries == 1) { - for (std::multimap::iterator cBeg = contacts.lower_bound(contactId), cEnd = contacts.upper_bound(contactId); 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; - } - - qDebug() << "An attempt to remove last instance of contact" << jid << "from the group" << group << ", contact will be moved to ungrouped contacts of" << account; - acc->appendChild(cont); - - if (gr->childCount() == 0) { - removeGroup(account, group); - } - } else { - for (std::multimap::iterator cBeg = contacts.lower_bound(contactId), cEnd = contacts.upper_bound(contactId); cBeg != cEnd; ++cBeg) { - if (cBeg->second->parentItem() == gr) { - cont = cBeg->second; - contacts.erase(cBeg); - 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; - } - - gr->removeChild(cont->row()); - cont->deleteLater(); - - if (gr->childCount() == 0) { - removeGroup(account, group); - } + if (gr->childCount() == 0) { + removeGroup(account, group); } } @@ -738,50 +693,46 @@ void Models::Roster::onChildRemoved() void Models::Roster::addPresence(const QString& account, const QString& jid, const QString& name, const QMap& data) { ElId contactId(account, jid); - std::multimap::iterator cBeg = contacts.lower_bound(contactId); - std::multimap::iterator cEnd = contacts.upper_bound(contactId); - for (;cBeg != cEnd; ++cBeg) { - cBeg->second->addPresence(name, data); + std::map::iterator itr = contacts.find(contactId); + if (itr != contacts.end()) { + itr->second->addPresence(name, data); } } void Models::Roster::removePresence(const QString& account, const QString& jid, const QString& name) { ElId contactId(account, jid); - std::multimap::iterator cBeg = contacts.lower_bound(contactId); - std::multimap::iterator cEnd = contacts.upper_bound(contactId); - for (;cBeg != cEnd; ++cBeg) { - cBeg->second->removePresence(name); + std::map::iterator itr = contacts.find(contactId); + if (itr != contacts.end()) { + itr->second->removePresence(name); } } void Models::Roster::addMessage(const QString& account, const Shared::Message& data) { ElId id(account, data.getPenPalJid()); - - std::multimap::iterator cBeg = contacts.lower_bound(id); - std::multimap::iterator cEnd = contacts.upper_bound(id); - - for (;cBeg != cEnd; ++cBeg) { - cBeg->second->addMessage(data); - } - - std::map::const_iterator rItr = rooms.find(id); - if (rItr != rooms.end()) { - rItr->second->addMessage(data); + std::map::iterator itr = contacts.find(id); + if (itr != contacts.end()) { + itr->second->addMessage(data); + } else { + std::map::const_iterator rItr = rooms.find(id); + if (rItr != rooms.end()) { + rItr->second->addMessage(data); + } } } void Models::Roster::dropMessages(const QString& account, const QString& jid) { ElId id(account, jid); - for (std::multimap::iterator cBeg = contacts.lower_bound(id), cEnd = contacts.upper_bound(id) ;cBeg != cEnd; ++cBeg) { - cBeg->second->dropMessages(); - } - - std::map::const_iterator rItr = rooms.find(id); - if (rItr != rooms.end()) { - rItr->second->dropMessages(); + std::map::iterator itr = contacts.find(id); + if (itr != contacts.end()) { + itr->second->dropMessages(); + } else { + std::map::const_iterator rItr = rooms.find(id); + if (rItr != rooms.end()) { + rItr->second->dropMessages(); + } } } @@ -799,10 +750,10 @@ void Models::Roster::removeAccount(const QString& account) accountsModel->removeAccount(index); accounts.erase(itr); - std::multimap::const_iterator cItr = contacts.begin(); + std::map::const_iterator cItr = contacts.begin(); while (cItr != contacts.end()) { if (cItr->first.account == account) { - std::multimap::const_iterator lItr = cItr; + std::map::const_iterator lItr = cItr; ++cItr; contacts.erase(lItr); } else { @@ -838,7 +789,7 @@ void Models::Roster::removeAccount(const QString& account) QString Models::Roster::getContactName(const QString& account, const QString& jid) { ElId id(account, jid); - std::multimap::const_iterator cItr = contacts.find(id); + std::map::const_iterator cItr = contacts.find(id); QString name = ""; if (cItr == contacts.end()) { std::map::const_iterator rItr = rooms.find(id); @@ -971,15 +922,14 @@ bool Models::Roster::groupHasContact(const QString& account, const QString& grou if (gItr == groups.end()) { return false; } else { - const Group* gr = gItr->second; - return gr->hasContact(contact); + return gItr->second->getContact(contact) != -1; } } QString Models::Roster::getContactIconPath(const QString& account, const QString& jid, const QString& resource) { ElId id(account, jid); - std::multimap::const_iterator cItr = contacts.find(id); + std::map::const_iterator cItr = contacts.find(id); QString path = ""; if (cItr == contacts.end()) { std::map::const_iterator rItr = rooms.find(id); diff --git a/ui/models/roster.h b/ui/models/roster.h index 34c343c..d866b6d 100644 --- a/ui/models/roster.h +++ b/ui/models/roster.h @@ -32,6 +32,7 @@ #include "contact.h" #include "group.h" #include "room.h" +#include "reference.h" namespace Models { @@ -87,7 +88,7 @@ private: Item* root; std::map accounts; std::map groups; - std::multimap contacts; + std::map contacts; std::map rooms; private slots: diff --git a/ui/squawk.cpp b/ui/squawk.cpp index 26d69e0..41634ad 100644 --- a/ui/squawk.cpp +++ b/ui/squawk.cpp @@ -305,6 +305,9 @@ void Squawk::onRosterItemDoubleClicked(const QModelIndex& item) { if (item.isValid()) { Models::Item* node = static_cast(item.internalPointer()); + if (node->type == Models::Item::reference) { + node = static_cast(node)->dereference(); + } Models::Contact* contact = 0; Models::Room* room = 0; QString res; @@ -681,7 +684,9 @@ void Squawk::onRosterContextMenu(const QPoint& point) QModelIndex index = m_ui->roster->indexAt(point); if (index.isValid()) { Models::Item* item = static_cast(index.internalPointer()); - + if (item->type == Models::Item::reference) { + item = static_cast(item)->dereference(); + } contextMenu->clear(); bool hasMenu = false; bool active = item->getAccountConnectionState() == Shared::ConnectionState::connected; @@ -1105,6 +1110,9 @@ void Squawk::onRosterSelectionChanged(const QModelIndex& current, const QModelIn if (current.isValid()) { Models::Item* node = static_cast(current.internalPointer()); + if (node->type == Models::Item::reference) { + node = static_cast(node)->dereference(); + } Models::Contact* contact = 0; Models::Room* room = 0; QString res;