diff options
author | Kevin Smith <git@kismith.co.uk> | 2010-05-06 08:00:44 (GMT) |
---|---|---|
committer | Kevin Smith <git@kismith.co.uk> | 2010-05-06 10:49:49 (GMT) |
commit | 081fc03556708447610e9697a57235fa191a4f0d (patch) | |
tree | 505c8cc9129d2b44968d183a180f0ccddaa08810 /Swiften | |
parent | 8c53236875d2ca77f1b463449918458f6b424ab1 (diff) | |
download | swift-contrib-081fc03556708447610e9697a57235fa191a4f0d.zip swift-contrib-081fc03556708447610e9697a57235fa191a4f0d.tar.bz2 |
Rewrite of large amounts of roster code.
Now keeps widgets out of Swiften, keeps sorting inside Swiften,
and keeps track of presences to show the correct presence per
roster item.
Resolves: #316
Resolves: #81
Resolves: #239
Diffstat (limited to 'Swiften')
23 files changed, 398 insertions, 507 deletions
diff --git a/Swiften/Roster/AppearOffline.h b/Swiften/Roster/AppearOffline.h index 792cec1..8e14190 100644 --- a/Swiften/Roster/AppearOffline.h +++ b/Swiften/Roster/AppearOffline.h @@ -21,7 +21,7 @@ class AppearOffline : public RosterItemOperation { virtual void operator() (RosterItem* item) const { ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item); if (contact) { - contact->setStatusShow(StatusShow::None); + contact->clearPresence(); } } diff --git a/Swiften/Roster/ContactRosterItem.cpp b/Swiften/Roster/ContactRosterItem.cpp index 39e96bd..2d5082c 100644 --- a/Swiften/Roster/ContactRosterItem.cpp +++ b/Swiften/Roster/ContactRosterItem.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -10,49 +10,77 @@ namespace Swift { -ContactRosterItem::ContactRosterItem(const JID& jid, const String& name, GroupRosterItem* parent, TreeWidgetFactory* factory) : jid_(jid), name_(name) { - parent->addChild(this); - widget_ = factory->createTreeWidgetItem(parent->getWidget()); - widget_->setText(name.isEmpty() ? jid.toString() : name); - widget_->onUserAction.connect(boost::bind(&ContactRosterItem::handleUserAction, this, _1)); - setStatusShow(StatusShow::None); +ContactRosterItem::ContactRosterItem(const JID& jid, const String& name, GroupRosterItem* parent) : RosterItem(name, parent), jid_(jid) { } ContactRosterItem::~ContactRosterItem() { - delete widget_; } -void ContactRosterItem::setName(const String& name) { - widget_->setText(name); +StatusShow::Type ContactRosterItem::getStatusShow() const { + return shownPresence_ ? shownPresence_->getShow() : StatusShow::None; } -StatusShow::Type ContactRosterItem::getStatusShow() { - return statusShow_; +StatusShow::Type ContactRosterItem::getSimplifiedStatusShow() const { + switch (shownPresence_ ? shownPresence_->getShow() : StatusShow::None) { + case StatusShow::Online: return StatusShow::Online; break; + case StatusShow::Away: return StatusShow::Away; break; + case StatusShow::XA: return StatusShow::Away; break; + case StatusShow::FFC: return StatusShow::Online; break; + case StatusShow::DND: return StatusShow::DND; break; + case StatusShow::None: return StatusShow::None; break; + } + assert(false); } -void ContactRosterItem::setStatusShow(StatusShow::Type show) { - statusShow_ = show; - widget_->setStatusShow(show); -} - -void ContactRosterItem::setStatusText(const String& status) { - widget_->setStatusText(status); +String ContactRosterItem::getStatusText() const { + return shownPresence_ ? shownPresence_->getStatus() : ""; } void ContactRosterItem::setAvatarPath(const String& path) { - widget_->setAvatarPath(path); + avatarPath_ = path; + onDataChanged(); +} +const String& ContactRosterItem::getAvatarPath() const { + return avatarPath_; } const JID& ContactRosterItem::getJID() const { return jid_; } -void ContactRosterItem::show() { - widget_->show(); +typedef std::pair<String, boost::shared_ptr<Presence> > StringPresencePair; + +void ContactRosterItem::calculateShownPresence() { + shownPresence_ = offlinePresence_; + foreach (StringPresencePair presencePair, presences_) { + boost::shared_ptr<Presence> presence = presencePair.second; + if (!shownPresence_ || presence->getPriority() > shownPresence_->getPriority() || presence->getShow() < shownPresence_->getShow()) { + shownPresence_ = presence; + } + } +} + +void ContactRosterItem::clearPresence() { + presences_.clear(); + calculateShownPresence(); } -void ContactRosterItem::hide() { - widget_->hide(); +void ContactRosterItem::applyPresence(const String& resource, boost::shared_ptr<Presence> presence) { + if (offlinePresence_) { + offlinePresence_ = boost::shared_ptr<Presence>(); + } + if (presence->getType() == Presence::Unavailable) { + if (presences_.find(resource) != presences_.end()) { + presences_.erase(resource); + } + if (presences_.size() > 0) { + offlinePresence_ = presence; + } + } else { + presences_[resource] = presence; + } + calculateShownPresence(); + onDataChanged(); } } diff --git a/Swiften/Roster/ContactRosterItem.h b/Swiften/Roster/ContactRosterItem.h index 92b3056..bd49e05 100644 --- a/Swiften/Roster/ContactRosterItem.h +++ b/Swiften/Roster/ContactRosterItem.h @@ -1,48 +1,47 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_ContactRosterItem_H -#define SWIFTEN_ContactRosterItem_H +#pragma once #include "Swiften/Base/String.h" #include "Swiften/JID/JID.h" -#include "Swiften/Roster/TreeWidgetFactory.h" #include "Swiften/Roster/RosterItem.h" -#include "Swiften/Roster/UserRosterAction.h" #include "Swiften/Elements/StatusShow.h" +#include "Swiften/Elements/Presence.h" +#include <map> #include <boost/bind.hpp> #include <boost/signal.hpp> #include <boost/shared_ptr.hpp> namespace Swift { -class TreeWidgetItem; class GroupRosterItem; class ContactRosterItem : public RosterItem { public: - ContactRosterItem(const JID& jid, const String& name, GroupRosterItem* parent, TreeWidgetFactory* factory); - ~ContactRosterItem(); + ContactRosterItem(const JID& jid, const String& name, GroupRosterItem* parent); + virtual ~ContactRosterItem(); - StatusShow::Type getStatusShow(); - void setStatusShow(StatusShow::Type show); - void setStatusText(const String& status); + StatusShow::Type getStatusShow() const; + StatusShow::Type getSimplifiedStatusShow() const; + String getStatusText() const; void setAvatarPath(const String& path); + const String& getAvatarPath() const; const JID& getJID() const; - void setName(const String& name); - void show(); - void hide(); - + void applyPresence(const String& resource, boost::shared_ptr<Presence> presence); + void clearPresence(); + void calculateShownPresence(); private: JID jid_; - String name_; - TreeWidgetItem *widget_; - StatusShow::Type statusShow_; + String avatarPath_; + bool hidden_; + std::map<String, boost::shared_ptr<Presence> > presences_; + boost::shared_ptr<Presence> offlinePresence_; + boost::shared_ptr<Presence> shownPresence_; }; } -#endif diff --git a/Swiften/Roster/GroupRosterItem.cpp b/Swiften/Roster/GroupRosterItem.cpp new file mode 100644 index 0000000..05530ec --- /dev/null +++ b/Swiften/Roster/GroupRosterItem.cpp @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2010 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include "Swiften/Roster/GroupRosterItem.h" + +#include <boost/bind.hpp> +#include <iostream> + +namespace Swift { + +GroupRosterItem::GroupRosterItem(const String& name, GroupRosterItem* parent) : RosterItem(name, parent) { + +} + +GroupRosterItem::~GroupRosterItem() { + +} + +const std::vector<RosterItem*>& GroupRosterItem::getChildren() const { + return children_; +} + +const std::vector<RosterItem*>& GroupRosterItem::getDisplayedChildren() const { +// std::cout << "Fetching displayed children for " << getDisplayName() << " and found " << displayedChildren_.size() << std::endl; + return displayedChildren_; +} + +void GroupRosterItem::addChild(RosterItem* item) { + children_.push_back(item); + GroupRosterItem* group = dynamic_cast<GroupRosterItem*>(item); + if (group) { + group->onChildrenChanged.connect(boost::bind(&GroupRosterItem::handleChildrenChanged, this, group)); + } + onChildrenChanged(); + onDataChanged(); +} + +/** + * Returns the removed item - but only if it's the only one, otherwise + * the return result is undefined. + */ +ContactRosterItem* GroupRosterItem::removeChild(const JID& jid) { + std::vector<RosterItem*>::iterator it = children_.begin(); + ContactRosterItem* removed = NULL; + while (it != children_.end()) { + ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(*it); + if (contact && contact->getJID() == jid) { + displayedChildren_.erase(std::remove(displayedChildren_.begin(), displayedChildren_.end(), contact), displayedChildren_.end()); + removed = contact; + delete contact; + it = children_.erase(it); + continue; + } + GroupRosterItem* group = dynamic_cast<GroupRosterItem*>(*it); + if (group) { + ContactRosterItem* groupRemoved = group->removeChild(jid); + if (groupRemoved) { + removed = groupRemoved; + } + } + it++; + } + onChildrenChanged(); + onDataChanged(); + return removed; +} + +void GroupRosterItem::sortDisplayed() { + std::stable_sort(displayedChildren_.begin(), displayedChildren_.end(), itemLessThan); +} + +bool GroupRosterItem::itemLessThan(const RosterItem* left, const RosterItem* right) { + const ContactRosterItem* leftContact = dynamic_cast<const ContactRosterItem*>(left); + const ContactRosterItem* rightContact = dynamic_cast<const ContactRosterItem*>(right); + if (leftContact) { + if (rightContact) { + return false; + } + StatusShow::Type leftType = leftContact->getSimplifiedStatusShow(); + StatusShow::Type rightType = rightContact->getSimplifiedStatusShow(); + if (leftType == rightType) { + return left->getSortableDisplayName() < right->getSortableDisplayName(); + } else { + return leftType < rightType; + } + } else { + if (rightContact) { + return true; + } + return left->getSortableDisplayName() < right->getSortableDisplayName(); + } +} + +void GroupRosterItem::setDisplayed(RosterItem* item, bool displayed) { + bool found = false; + for (size_t i = 0; i < displayedChildren_.size(); i++) { + if (displayedChildren_[i] == item) { + found = true; + } + } + if (found == displayed) { + return; + } + if (displayed) { + displayedChildren_.push_back(item); + sortDisplayed(); + } else { + displayedChildren_.erase(std::remove(displayedChildren_.begin(), displayedChildren_.end(), item), displayedChildren_.end()); + } + onDataChanged(); + onChildrenChanged(); +} + +void GroupRosterItem::handleChildrenChanged(GroupRosterItem* group) { + size_t oldSize = getDisplayedChildren().size(); + if (group->getDisplayedChildren().size() > 0) { + bool found = false; + for (size_t i = 0; i < displayedChildren_.size(); i++) { + if (displayedChildren_[i] == group) { + found = true; + } + } + if (!found) { + displayedChildren_.push_back(group); + sortDisplayed(); + } + } else { + displayedChildren_.erase(std::remove(displayedChildren_.begin(), displayedChildren_.end(), group), displayedChildren_.end()); + } + if (oldSize != getDisplayedChildren().size()) { + onDataChanged(); + onChildrenChanged(); + } +} + + +} diff --git a/Swiften/Roster/GroupRosterItem.h b/Swiften/Roster/GroupRosterItem.h index 83128a5..5e16b2b 100644 --- a/Swiften/Roster/GroupRosterItem.h +++ b/Swiften/Roster/GroupRosterItem.h @@ -1,74 +1,37 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_GroupRosterItem_H -#define SWIFTEN_GroupRosterItem_H +#pragma once #include "Swiften/Roster/RosterItem.h" #include "Swiften/Base/String.h" -#include "Swiften/Roster/TreeWidget.h" -#include "Swiften/Roster/TreeWidgetFactory.h" -#include "Swiften/Roster/TreeWidgetItem.h" #include "Swiften/Roster/ContactRosterItem.h" -#include <list> +#include <vector> namespace Swift { class GroupRosterItem : public RosterItem { public: - GroupRosterItem(const String& name, TreeWidget* tree, TreeWidgetFactory* factory) : name_(name) { - widget_ = factory->createTreeWidgetItem(tree); - widget_->setExpanded(true); - widget_->setText(name); - } - - ~GroupRosterItem() { - delete widget_; - } - - const String& getName() const { - return name_; - } - - TreeWidgetItem* getWidget() const { - return widget_; - } - - const std::list<RosterItem*>& getChildren() const { - return children_; - } - - void addChild(RosterItem* item) { - children_.push_back(item); - } - - void removeChild(const JID& jid) { - std::list<RosterItem*>::iterator it = children_.begin(); - while (it != children_.end()) { - ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(*it); - if (contact && contact->getJID() == jid) { - delete contact; - it = children_.erase(it); - continue; - } - GroupRosterItem* group = dynamic_cast<GroupRosterItem*>(*it); - if (group) { - group->removeChild(jid); - } - it++; - } - } - + GroupRosterItem(const String& name, GroupRosterItem* parent); + virtual ~GroupRosterItem(); + const std::vector<RosterItem*>& getChildren() const; + const std::vector<RosterItem*>& getDisplayedChildren() const; + void addChild(RosterItem* item); + ContactRosterItem* removeChild(const JID& jid); + void setDisplayed(RosterItem* item, bool displayed); + boost::signal<void ()> onChildrenChanged; + static bool itemLessThan(const RosterItem* left, const RosterItem* right); private: + void handleChildrenChanged(GroupRosterItem* group); + void sortDisplayed(); String name_; - TreeWidgetItem* widget_; - std::list<RosterItem*> children_; + std::vector<RosterItem*> children_; + std::vector<RosterItem*> displayedChildren_; }; } -#endif diff --git a/Swiften/Roster/OpenChatRosterAction.h b/Swiften/Roster/OpenChatRosterAction.h deleted file mode 100644 index b0784f5..0000000 --- a/Swiften/Roster/OpenChatRosterAction.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#ifndef SWIFTEN_OpenChatRosterAction_H -#define SWIFTEN_OpenChatRosterAction_H - -#include "Swiften/Roster/UserRosterAction.h" - -namespace Swift { -class RosterItem; -class TreeWidgetItem; - -class OpenChatRosterAction : public UserRosterAction { - public: - virtual ~OpenChatRosterAction() {}; - -}; - -} -#endif - - - diff --git a/Swiften/Roster/Roster.cpp b/Swiften/Roster/Roster.cpp index 8c2aa0e..c25fd41 100644 --- a/Swiften/Roster/Roster.cpp +++ b/Swiften/Roster/Roster.cpp @@ -13,79 +13,93 @@ #include "Swiften/Roster/RosterItem.h" #include "Swiften/Roster/GroupRosterItem.h" #include "Swiften/Roster/RosterItemOperation.h" -#include "Swiften/Roster/TreeWidget.h" -#include "Swiften/Roster/TreeWidgetFactory.h" #include <boost/bind.hpp> +#include <iostream> #include <deque> namespace Swift { -Roster::Roster(TreeWidget *treeWidget, TreeWidgetFactory *widgetFactory) : treeWidget_(treeWidget), widgetFactory_(widgetFactory) { +Roster::Roster() { + root_ = new GroupRosterItem("Dummy-Root", NULL); } Roster::~Roster() { - foreach (RosterItem* item, items_) { + std::deque<RosterItem*> queue; + queue.push_back(root_); + while (!queue.empty()) { + RosterItem* item = *queue.begin(); + queue.pop_front(); + GroupRosterItem* group = dynamic_cast<GroupRosterItem*>(item); + if (group) { + queue.insert(queue.begin(), group->getChildren().begin(), group->getChildren().end()); + } delete item; } - delete treeWidget_; } -TreeWidget* Roster::getWidget() { - return treeWidget_; +GroupRosterItem* Roster::getRoot() { + return root_; } GroupRosterItem* Roster::getGroup(const String& groupName) { - foreach (RosterItem *item, children_) { + foreach (RosterItem *item, root_->getChildren()) { GroupRosterItem *group = dynamic_cast<GroupRosterItem*>(item); - if (group && group->getName() == groupName) { + if (group && group->getDisplayName() == groupName) { return group; } } - GroupRosterItem* group = new GroupRosterItem(groupName, treeWidget_, widgetFactory_); - children_.push_back(group); - items_.push_back(group); + GroupRosterItem* group = new GroupRosterItem(groupName, root_); + root_->addChild(group); +// std::cout << "Added " << groupName << " to root" << std::endl; + group->onChildrenChanged.connect(boost::bind(&Roster::handleChildrenChanged, this, group)); + group->onDataChanged.connect(boost::bind(&Roster::handleDataChanged, this, group)); return group; } -void Roster::handleUserAction(boost::shared_ptr<UserRosterAction> action) { - onUserAction(action); +void Roster::handleDataChanged(RosterItem* item) { + onDataChanged(item); } -void Roster::addContact(const JID& jid, const String& name, const String& group) { - ContactRosterItem *item = new ContactRosterItem(jid, name, getGroup(group), widgetFactory_); - items_.push_back(item); - itemMap_[jid.toBare()].push_back(item); - item->onUserAction.connect(boost::bind(&Roster::handleUserAction, this, _1)); - filterItem(item); +void Roster::handleChildrenChanged(GroupRosterItem* item) { + onChildrenChanged(item); +} +void Roster::addContact(const JID& jid, const String& name, const String& groupName) { + GroupRosterItem* group(getGroup(groupName)); + ContactRosterItem *item = new ContactRosterItem(jid, name, group); + group->addChild(item); + itemMap_[jid.toBare()].push_back(item); + item->onDataChanged.connect(boost::bind(&Roster::handleDataChanged, this, item)); + filterContact(item, group); } + void Roster::removeContact(const JID& jid) { - itemMap_.erase(jid.toBare()); - std::vector<RosterItem*>::iterator it = children_.begin(); - while (it != children_.end()) { - ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(*it); - if (contact && contact->getJID() == jid) { - delete contact; - it = children_.erase(it); - continue; - } - GroupRosterItem* group = dynamic_cast<GroupRosterItem*>(*it); - if (group) { - group->removeChild(jid); + std::vector<ContactRosterItem*> items = itemMap_[jid.toBare()]; + std::vector<ContactRosterItem*>::iterator it = items.begin(); + while (it != items.end()) { + if (jid == (*it)->getJID()) { + it = items.erase(it); } - it++; } + if (items.size() == 0) { + itemMap_.erase(jid.toBare()); + } + //Causes the delete + root_->removeChild(jid); } void Roster::removeContactFromGroup(const JID& jid, const String& groupName) { - std::vector<RosterItem*>::iterator it = children_.begin(); - while (it != children_.end()) { + std::vector<RosterItem*> children = root_->getChildren(); + std::vector<RosterItem*>::iterator it = children.begin(); + while (it != children.end()) { GroupRosterItem* group = dynamic_cast<GroupRosterItem*>(*it); - if (group && group->getName() == groupName) { - group->removeChild(jid); + if (group && group->getDisplayName() == groupName) { + ContactRosterItem* deleted = group->removeChild(jid); + std::vector<ContactRosterItem*> items = itemMap_[jid.toBare()]; + items.erase(std::remove(items.begin(), items.end(), deleted), items.end()); } it++; } @@ -101,14 +115,15 @@ void Roster::applyOnItems(const RosterItemOperation& operation) { } void Roster::applyOnItem(const RosterItemOperation& operation, const JID& jid) { - foreach (RosterItem* item, itemMap_[jid]) { + foreach (ContactRosterItem* item, itemMap_[jid.toBare()]) { operation(item); - filterItem(item); + filterContact(item, item->getParent()); } } void Roster::applyOnAllItems(const RosterItemOperation& operation) { - std::deque<RosterItem*> queue(children_.begin(), children_.end()); + std::deque<RosterItem*> queue; + queue.push_back(root_); while (!queue.empty()) { RosterItem* item = *queue.begin(); queue.pop_front(); @@ -131,29 +146,40 @@ void Roster::removeFilter(RosterFilter *filter) { filterAll(); } - -void Roster::filterItem(RosterItem* rosterItem) { - ContactRosterItem *item = dynamic_cast<ContactRosterItem*>(rosterItem); - if (!item) { - return; - } +void Roster::filterContact(ContactRosterItem* contact, GroupRosterItem* group) { + int oldDisplayedSize = group->getDisplayedChildren().size(); bool hide = true; foreach (RosterFilter *filter, filters_) { - hide &= (*filter)(item); + hide &= (*filter)(contact); + } + group->setDisplayed(contact, filters_.size() == 0 || !hide); + int newDisplayedSize = group->getDisplayedChildren().size(); +// std::cout << ", new size = " << newDisplayedSize << std::endl; + if (oldDisplayedSize == 0 && newDisplayedSize > 0) { +// std::cout << "Newly created" << std::endl; + onGroupAdded(group); + } +} + +void Roster::filterGroup(GroupRosterItem* group) { + foreach (RosterItem* child, group->getChildren()) { + ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(child); + if (contact) { + filterContact(contact, group); + } } - filters_.size() > 0 && hide ? item->hide() : item->show(); } void Roster::filterAll() { - std::deque<RosterItem*> queue(children_.begin(), children_.end()); + std::deque<RosterItem*> queue; + queue.push_back(root_); while (!queue.empty()) { RosterItem *item = *queue.begin(); queue.pop_front(); GroupRosterItem* group = dynamic_cast<GroupRosterItem*>(item); if (group) { queue.insert(queue.begin(), group->getChildren().begin(), group->getChildren().end()); - } else { - filterItem(item); + filterGroup(group); } } } diff --git a/Swiften/Roster/Roster.h b/Swiften/Roster/Roster.h index 5fc3cfb..3af89d7 100644 --- a/Swiften/Roster/Roster.h +++ b/Swiften/Roster/Roster.h @@ -10,7 +10,6 @@ #include "Swiften/Base/String.h" #include "Swiften/JID/JID.h" #include "Swiften/Roster/RosterItemOperation.h" -#include "Swiften/Roster/UserRosterAction.h" #include "Swiften/Roster/RosterFilter.h" #include <vector> @@ -20,39 +19,38 @@ namespace Swift { -class TreeWidgetFactory; -class TreeWidget; class RosterItem; class GroupRosterItem; +class ContactRosterItem; class Roster { public: - Roster(TreeWidget *treeWidget, TreeWidgetFactory *widgetFactory); + Roster(); ~Roster(); - TreeWidget* getWidget(); - GroupRosterItem* getGroup(const String& groupName); void addContact(const JID& jid, const String& name, const String& group); void removeContact(const JID& jid); void removeContactFromGroup(const JID& jid, const String& group); void applyOnItems(const RosterItemOperation& operation); void applyOnAllItems(const RosterItemOperation& operation); void applyOnItem(const RosterItemOperation& operation, const JID& jid); - boost::signal<void (boost::shared_ptr<UserRosterAction>)> onUserAction; - void addFilter(RosterFilter *filter) {filters_.push_back(filter);filterAll();} + void addFilter(RosterFilter *filter) {filters_.push_back(filter);filterAll();}; void removeFilter(RosterFilter *filter); - std::vector<RosterFilter*> getFilters() {return filters_;} - + GroupRosterItem* getRoot(); + std::vector<RosterFilter*> getFilters() {return filters_;}; + boost::signal<void (GroupRosterItem*)> onChildrenChanged; + boost::signal<void (GroupRosterItem*)> onGroupAdded; + boost::signal<void (RosterItem*)> onDataChanged; private: - void filterItem(RosterItem* item); + GroupRosterItem* getGroup(const String& groupName); + void handleDataChanged(RosterItem* item); + void handleChildrenChanged(GroupRosterItem* item); + void filterGroup(GroupRosterItem* item); + void filterContact(ContactRosterItem* contact, GroupRosterItem* group); void filterAll(); - void handleUserAction(boost::shared_ptr<UserRosterAction> action); - TreeWidget *treeWidget_; - TreeWidgetFactory *widgetFactory_; - std::vector<RosterItem*> children_; - std::vector<RosterItem*> items_; + GroupRosterItem* root_; std::vector<RosterFilter*> filters_; - std::map<JID, std::vector<RosterItem*> > itemMap_; + std::map<JID, std::vector<ContactRosterItem*> > itemMap_; }; } diff --git a/Swiften/Roster/RosterItem.cpp b/Swiften/Roster/RosterItem.cpp new file mode 100644 index 0000000..7229199 --- /dev/null +++ b/Swiften/Roster/RosterItem.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2010 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include "Swiften/Roster/RosterItem.h" + +#include "Swiften/Roster/GroupRosterItem.h" + +namespace Swift { + +RosterItem::RosterItem(const String& name, GroupRosterItem* parent) : name_(name), parent_(parent) { + /* The following would be good, but because of C++'s inheritance not working in constructors, it's not going to work. */ + //if (parent) { + // parent_->addChild(this); + //} +} + +RosterItem::~RosterItem() { + +} + +GroupRosterItem* RosterItem::getParent() const { + return parent_; +} + +void RosterItem::setDisplayName(const String& name) { + name_ = name; + sortableDisplayName_ = name_.getLowerCase(); + onDataChanged(); +} + +String RosterItem::getDisplayName() const { + return name_; +} + +String RosterItem::getSortableDisplayName() const { + return sortableDisplayName_; +} + + +} + diff --git a/Swiften/Roster/RosterItem.h b/Swiften/Roster/RosterItem.h index 2c2a7e4..3a1a1b1 100644 --- a/Swiften/Roster/RosterItem.h +++ b/Swiften/Roster/RosterItem.h @@ -1,30 +1,32 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_RosterItem_H -#define SWIFTEN_RosterItem_H - -#include "Swiften/Roster/UserRosterAction.h" +#pragma once #include <boost/signal.hpp> #include <boost/shared_ptr.hpp> -namespace Swift { +#include "Swiften/Base/String.h" +namespace Swift { +class GroupRosterItem; class RosterItem { public: - virtual ~RosterItem() {}; - boost::signal<void (boost::shared_ptr<UserRosterAction>)> onUserAction; - protected: - void handleUserAction(boost::shared_ptr<UserRosterAction> action) { - action->setRosterItem(this); - onUserAction(action); - } + RosterItem(const String& name, GroupRosterItem* parent); + virtual ~RosterItem(); + boost::signal<void ()> onDataChanged; + GroupRosterItem* getParent() const; + void setDisplayName(const String& name); + String getDisplayName() const; + String getSortableDisplayName() const; + private: + String name_; + String sortableDisplayName_; + GroupRosterItem* parent_; }; } -#endif diff --git a/Swiften/Roster/RosterItemOperation.h b/Swiften/Roster/RosterItemOperation.h index a901fb4..e27e68b 100644 --- a/Swiften/Roster/RosterItemOperation.h +++ b/Swiften/Roster/RosterItemOperation.h @@ -17,6 +17,11 @@ class RosterItemOperation { virtual ~RosterItemOperation() {}; bool requiresLookup() const {return requiresLookup_;}; const JID& lookupJID() const {return lookupJID_;}; + /** + * This is called when iterating over possible subjects, so must check it's + * applying to the right items - even if requiresLookup() is true an item + * with the same bare JID but different full JID may be passed. + */ virtual void operator() (RosterItem*) const = 0; private: bool requiresLookup_; diff --git a/Swiften/Roster/SetName.h b/Swiften/Roster/SetName.h index 33dd521..d3f7749 100644 --- a/Swiften/Roster/SetName.h +++ b/Swiften/Roster/SetName.h @@ -22,7 +22,7 @@ class SetName : public RosterItemOperation { virtual void operator() (RosterItem* item) const { ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item); if (contact && contact->getJID().equals(jid_, compareType_)) { - contact->setName(name_); + contact->setDisplayName(name_); } } diff --git a/Swiften/Roster/SetPresence.h b/Swiften/Roster/SetPresence.h index 9cc3ba9..134a63d 100644 --- a/Swiften/Roster/SetPresence.h +++ b/Swiften/Roster/SetPresence.h @@ -4,8 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_SetPresence_H -#define SWIFTEN_SetPresence_H +#pragma once #include "Swiften/Elements/Presence.h" #include "Swiften/JID/JID.h" @@ -24,13 +23,7 @@ class SetPresence : public RosterItemOperation { virtual void operator() (RosterItem* item) const { ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item); if (contact && contact->getJID().equals(presence_->getFrom(), compareType_)) { - if (presence_->getType() != Presence::Available) { - contact->setStatusShow(StatusShow::None); - contact->setStatusText(presence_->getStatus()); - } else { - contact->setStatusShow(presence_->getShow()); - contact->setStatusText(presence_->getStatus()); - } + contact->applyPresence(presence_->getFrom().getResource(), presence_); } } @@ -40,5 +33,4 @@ class SetPresence : public RosterItemOperation { }; } -#endif diff --git a/Swiften/Roster/TreeWidget.h b/Swiften/Roster/TreeWidget.h deleted file mode 100644 index 78b67b7..0000000 --- a/Swiften/Roster/TreeWidget.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#ifndef SWIFTEN_TreeWidget_H -#define SWIFTEN_TreeWidget_H - -namespace Swift { - -class TreeWidget { - public: - virtual ~TreeWidget() {} -}; - -} -#endif - diff --git a/Swiften/Roster/TreeWidgetFactory.h b/Swiften/Roster/TreeWidgetFactory.h deleted file mode 100644 index fbc4417..0000000 --- a/Swiften/Roster/TreeWidgetFactory.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#ifndef SWIFTEN_TreeWidgetFactory_H -#define SWIFTEN_TreeWidgetFactory_H - -namespace Swift { - -class TreeWidgetItem; -class TreeWidget; - -class TreeWidgetFactory { - public: - virtual ~TreeWidgetFactory() {} - virtual TreeWidget* createTreeWidget() = 0; - virtual TreeWidgetItem* createTreeWidgetItem(TreeWidgetItem* item) = 0; - virtual TreeWidgetItem* createTreeWidgetItem(TreeWidget* item) = 0; -}; - -} - -#endif - diff --git a/Swiften/Roster/TreeWidgetItem.h b/Swiften/Roster/TreeWidgetItem.h deleted file mode 100644 index 1718776..0000000 --- a/Swiften/Roster/TreeWidgetItem.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#ifndef SWIFTEN_TreeWidgetItem_H -#define SWIFTEN_TreeWidgetItem_H - -#include "Swiften/Base/String.h" -#include "Swiften/Roster/UserRosterAction.h" -#include "Swiften/Elements/StatusShow.h" - -#include <boost/signal.hpp> -#include <boost/shared_ptr.hpp> - -namespace Swift { - -class TreeWidgetItem { - public: - virtual ~TreeWidgetItem() {} - virtual void setText(const String& text) = 0; - virtual void setStatusText(const String& text) = 0; - virtual void setAvatarPath(const String& path) = 0; - virtual void setExpanded(bool b) = 0; - //virtual void setTextColor(unsigned long color) = 0; - virtual void setStatusShow(StatusShow::Type show) = 0; - //virtual void setBackgroundColor(unsigned long color) = 0; - boost::signal<void (boost::shared_ptr<UserRosterAction>)> onUserAction; - virtual void show() = 0; - virtual void hide() = 0; - void performUserAction(boost::shared_ptr<UserRosterAction> action) { - action->setTreeWidgetItem(this); - onUserAction(action); - } -}; - -} -#endif - diff --git a/Swiften/Roster/UnitTest/MockTreeWidget.h b/Swiften/Roster/UnitTest/MockTreeWidget.h deleted file mode 100644 index 97dd796..0000000 --- a/Swiften/Roster/UnitTest/MockTreeWidget.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2010 Kevin Smith - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#ifndef SWIFTEN_MockTreeWidget_H -#define SWIFTEN_MockTreeWidget_H - -#include "Swiften/Roster/TreeWidget.h" - -namespace Swift { - -class MockTreeWidget : public TreeWidget { - public: - virtual ~MockTreeWidget() {} -}; - -} -#endif diff --git a/Swiften/Roster/UnitTest/MockTreeWidgetFactory.h b/Swiften/Roster/UnitTest/MockTreeWidgetFactory.h deleted file mode 100644 index d94c859..0000000 --- a/Swiften/Roster/UnitTest/MockTreeWidgetFactory.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2010 Kevin Smith - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#ifndef SWIFTEN_MockTreeWidgetFactory_H -#define SWIFTEN_MockTreeWidgetFactory_H - -#include "Swiften/Roster/TreeWidgetFactory.h" - -#include <vector> -#include "Swiften/Base/foreach.h" -#include "Swiften/Roster/UnitTest/MockTreeWidget.h" -#include "Swiften/Roster/UnitTest/MockTreeWidgetItem.h" - -namespace Swift { - -class MockTreeWidgetItem; -class MockTreeWidget; - -class MockTreeWidgetFactory : public TreeWidgetFactory { - public: - virtual ~MockTreeWidgetFactory() {} - virtual TreeWidget* createTreeWidget() { - root_ = new MockTreeWidget(); - return root_; - }; - virtual TreeWidgetItem* createTreeWidgetItem(TreeWidgetItem* group) { - MockTreeWidgetItem* entry = new MockTreeWidgetItem(this); - groupMembers_[group].push_back(entry); - return entry; - }; - virtual TreeWidgetItem* createTreeWidgetItem(TreeWidget*) { - MockTreeWidgetItem* group = new MockTreeWidgetItem(this); - groups_.push_back(group); - return group; - }; - virtual std::vector<String> getGroups() { - std::vector<String> groupNames; - foreach (MockTreeWidgetItem* group, groups_) { - groupNames.push_back(group->getText()); - } - return groupNames; - }; - - typedef std::map<TreeWidgetItem*, std::vector<MockTreeWidgetItem*> > itemMap; - - virtual std::vector<MockTreeWidgetItem*> getGroupMembers(const String& group) { - for (itemMap::iterator it = groupMembers_.begin(); it != groupMembers_.end(); it++) { - if (((MockTreeWidgetItem*)(it->first))->getText() == group) { - return it->second; - } - } - return std::vector<MockTreeWidgetItem*>(); - }; - - virtual void removeItem(MockTreeWidgetItem* item) { - foreach (TreeWidgetItem* groupItem, groups_) { - std::vector<MockTreeWidgetItem*>& members = groupMembers_[groupItem]; - members.erase(std::remove(members.begin(), members.end(), item), members.end()); - } - }; - private: - std::vector<MockTreeWidgetItem*> groups_; - std::map<TreeWidgetItem*, std::vector<MockTreeWidgetItem*> > groupMembers_; - MockTreeWidget* root_; -}; - -} - -#endif - - diff --git a/Swiften/Roster/UnitTest/MockTreeWidgetItem.cpp b/Swiften/Roster/UnitTest/MockTreeWidgetItem.cpp deleted file mode 100644 index 4238ead..0000000 --- a/Swiften/Roster/UnitTest/MockTreeWidgetItem.cpp +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2010 Kevin Smith - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ -#include "Swiften/Roster/UnitTest/MockTreeWidgetItem.h" - -#include "Swiften/Roster/UnitTest/MockTreeWidgetFactory.h" - -namespace Swift { - -MockTreeWidgetItem::~MockTreeWidgetItem() { - factory_->removeItem(this); -} - -} - - - diff --git a/Swiften/Roster/UnitTest/MockTreeWidgetItem.h b/Swiften/Roster/UnitTest/MockTreeWidgetItem.h deleted file mode 100644 index 08b9f1a..0000000 --- a/Swiften/Roster/UnitTest/MockTreeWidgetItem.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2010 Kevin Smith - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#ifndef SWIFTEN_MockTreeWidgetItem_H -#define SWIFTEN_MockTreeWidgetItem_H - -#include "Swiften/Base/String.h" -#include "Swiften/Roster/TreeWidgetItem.h" - -#include <boost/signal.hpp> -#include <boost/shared_ptr.hpp> - -namespace Swift { - class MockTreeWidgetFactory; -class MockTreeWidgetItem : public TreeWidgetItem { - public: - MockTreeWidgetItem(MockTreeWidgetFactory* factory) {factory_ = factory;}; - virtual ~MockTreeWidgetItem(); - virtual void setText(const String& text) {text_ = text;}; - String getText() {return text_;}; - virtual void setStatusText(const String&) {}; - virtual void setAvatarPath(const String&) {}; - virtual void setExpanded(bool) {}; - virtual void setStatusShow(StatusShow::Type /*show*/) {}; - virtual void show() {}; - virtual void hide() {}; - private: - String text_; - MockTreeWidgetFactory* factory_; -}; - -} -#endif - - diff --git a/Swiften/Roster/UnitTest/RosterTest.cpp b/Swiften/Roster/UnitTest/RosterTest.cpp index 5a2a3e3..f9dff33 100644 --- a/Swiften/Roster/UnitTest/RosterTest.cpp +++ b/Swiften/Roster/UnitTest/RosterTest.cpp @@ -9,9 +9,7 @@ #include <boost/shared_ptr.hpp> #include "Swiften/Roster/Roster.h" -#include "Swiften/Roster/UnitTest/MockTreeWidget.h" -#include "Swiften/Roster/UnitTest/MockTreeWidgetFactory.h" -#include "Swiften/Roster/UnitTest/MockTreeWidgetItem.h" +#include "Swiften/Roster/GroupRosterItem.h" using namespace Swift; @@ -23,8 +21,6 @@ class RosterTest : public CppUnit::TestFixture private: Roster *roster_; - TreeWidget *widget_; - TreeWidgetFactory *factory_; JID jid1_; JID jid2_; JID jid3_; @@ -34,15 +30,11 @@ class RosterTest : public CppUnit::TestFixture RosterTest() : jid1_(JID("a@b.c")), jid2_(JID("b@c.d")), jid3_(JID("c@d.e")) {} void setUp() { - factory_ = new MockTreeWidgetFactory(); - widget_ = factory_->createTreeWidget(); - roster_ = new Roster(widget_, factory_); + roster_ = new Roster(); } void tearDown() { delete roster_; - //delete widget_; - delete factory_; } void testGetGroup() { @@ -50,12 +42,13 @@ class RosterTest : public CppUnit::TestFixture roster_->addContact(jid2_, "Ernie", "group2"); roster_->addContact(jid3_, "Cookie", "group1"); - CPPUNIT_ASSERT_EQUAL(roster_->getGroup("group1"), roster_->getGroup("group1")); - CPPUNIT_ASSERT_EQUAL(roster_->getGroup("group2"), roster_->getGroup("group2")); - CPPUNIT_ASSERT_EQUAL(roster_->getGroup("group3"), roster_->getGroup("group3")); - CPPUNIT_ASSERT(roster_->getGroup("group1") != roster_->getGroup("group2")); - CPPUNIT_ASSERT(roster_->getGroup("group2") != roster_->getGroup("group3")); - CPPUNIT_ASSERT(roster_->getGroup("group3") != roster_->getGroup("group1")); + CPPUNIT_ASSERT_EQUAL(2, (int)roster_->getRoot()->getChildren().size()); + CPPUNIT_ASSERT_EQUAL(String("group1"), roster_->getRoot()->getChildren()[0]->getDisplayName()); + CPPUNIT_ASSERT_EQUAL(String("group2"), roster_->getRoot()->getChildren()[1]->getDisplayName()); + CPPUNIT_ASSERT_EQUAL(String("Bert"), ((GroupRosterItem*)roster_->getRoot()->getChildren()[0])->getChildren()[0]->getDisplayName()); + CPPUNIT_ASSERT_EQUAL(String("Cookie"), ((GroupRosterItem*)roster_->getRoot()->getChildren()[0])->getChildren()[1]->getDisplayName()); + CPPUNIT_ASSERT_EQUAL(String("Ernie"), ((GroupRosterItem*)roster_->getRoot()->getChildren()[1])->getChildren()[0]->getDisplayName()); + } }; diff --git a/Swiften/Roster/UserRosterAction.h b/Swiften/Roster/UserRosterAction.h deleted file mode 100644 index b869530..0000000 --- a/Swiften/Roster/UserRosterAction.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#ifndef SWIFTEN_UserRosterAction_H -#define SWIFTEN_UserRosterAction_H - -namespace Swift { -class RosterItem; -class TreeWidgetItem; - -class UserRosterAction { - public: - virtual ~UserRosterAction() {}; - void setRosterItem(RosterItem *item) { - rosterItem_ = item; - }; - void setTreeWidgetItem(TreeWidgetItem *item) { - treeWidgetItem_ = item; - } - RosterItem* getRosterItem() { - return rosterItem_; - } - TreeWidgetItem* getTreeWidgetItem() { - return treeWidgetItem_; - } - - private: - RosterItem *rosterItem_; - TreeWidgetItem *treeWidgetItem_; -}; - -} -#endif - - diff --git a/Swiften/SConscript b/Swiften/SConscript index dfda3ba..a95635a 100644 --- a/Swiften/SConscript +++ b/Swiften/SConscript @@ -54,6 +54,8 @@ if env["SCONS_STAGE"] == "build" : "Queries/Responders/DiscoInfoResponder.cpp", "Queries/Responders/SoftwareVersionResponder.cpp", "Roster/ContactRosterItem.cpp", + "Roster/GroupRosterItem.cpp", + "Roster/RosterItem.cpp", "Roster/Roster.cpp", "Roster/XMPPRoster.cpp", "Serializer/AuthRequestSerializer.cpp", @@ -191,7 +193,6 @@ if env["SCONS_STAGE"] == "build" : File("Roster/UnitTest/OfflineRosterFilterTest.cpp"), File("Roster/UnitTest/RosterTest.cpp"), File("Roster/UnitTest/XMPPRosterTest.cpp"), - File("Roster/UnitTest/MockTreeWidgetItem.cpp"), File("SASL/UnitTest/PLAINMessageTest.cpp"), File("SASL/UnitTest/PLAINClientAuthenticatorTest.cpp"), File("SASL/UnitTest/SCRAMSHA1ClientAuthenticatorTest.cpp"), |