diff options
Diffstat (limited to 'Swiften/Roster')
25 files changed, 1051 insertions, 0 deletions
diff --git a/Swiften/Roster/AppearOffline.h b/Swiften/Roster/AppearOffline.h new file mode 100644 index 0000000..673e018 --- /dev/null +++ b/Swiften/Roster/AppearOffline.h @@ -0,0 +1,26 @@ +#pragma once + +#include "Swiften/Roster/RosterItemOperation.h" +#include "Swiften/Roster/ContactRosterItem.h" + +namespace Swift { + +class RosterItem; + +class AppearOffline : public RosterItemOperation { + public: + AppearOffline() { + } + + virtual void operator() (RosterItem* item) const { + ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item); + if (contact) { + contact->setStatusShow(StatusShow::None); + } + } + +}; + +} + + diff --git a/Swiften/Roster/ContactRosterItem.cpp b/Swiften/Roster/ContactRosterItem.cpp new file mode 100644 index 0000000..968f7f1 --- /dev/null +++ b/Swiften/Roster/ContactRosterItem.cpp @@ -0,0 +1,50 @@ +#include "Swiften/Roster/ContactRosterItem.h" +#include "Swiften/Roster/GroupRosterItem.h" + +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() { + delete widget_; +} + +StatusShow::Type ContactRosterItem::getStatusShow() { + return statusShow_; +} + +void ContactRosterItem::setStatusShow(StatusShow::Type show) { + statusShow_ = show; + widget_->setStatusShow(show); +} + +void ContactRosterItem::setStatusText(const String& status) { + widget_->setStatusText(status); +} + +void ContactRosterItem::setAvatarPath(const String& path) { + widget_->setAvatarPath(path); +} + +const JID& ContactRosterItem::getJID() const { + return jid_; +} + +void ContactRosterItem::show() { + widget_->show(); +} + +void ContactRosterItem::hide() { + widget_->hide(); +} + +} + + diff --git a/Swiften/Roster/ContactRosterItem.h b/Swiften/Roster/ContactRosterItem.h new file mode 100644 index 0000000..f1810aa --- /dev/null +++ b/Swiften/Roster/ContactRosterItem.h @@ -0,0 +1,41 @@ +#ifndef SWIFTEN_ContactRosterItem_H +#define SWIFTEN_ContactRosterItem_H + +#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 <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(); + + StatusShow::Type getStatusShow(); + void setStatusShow(StatusShow::Type show); + void setStatusText(const String& status); + void setAvatarPath(const String& path); + const JID& getJID() const; + void show(); + void hide(); + + private: + JID jid_; + String name_; + TreeWidgetItem *widget_; + StatusShow::Type statusShow_; +}; + +} +#endif + diff --git a/Swiften/Roster/GroupRosterItem.h b/Swiften/Roster/GroupRosterItem.h new file mode 100644 index 0000000..2ab59ea --- /dev/null +++ b/Swiften/Roster/GroupRosterItem.h @@ -0,0 +1,68 @@ +#ifndef SWIFTEN_GroupRosterItem_H +#define SWIFTEN_GroupRosterItem_H + +#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> + +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++; + } + } + + private: + String name_; + TreeWidgetItem* widget_; + std::list<RosterItem*> children_; +}; + +} +#endif + diff --git a/Swiften/Roster/OfflineRosterFilter.h b/Swiften/Roster/OfflineRosterFilter.h new file mode 100644 index 0000000..512d074 --- /dev/null +++ b/Swiften/Roster/OfflineRosterFilter.h @@ -0,0 +1,24 @@ +#ifndef SWIFTEN_OfflineRosterFilter_H +#define SWIFTEN_OfflineRosterFilter_H + +#include "Swiften/Roster/ContactRosterItem.h" +#include "Swiften/Roster/RosterItem.h" +#include "Swiften/Roster/RosterFilter.h" +#include "Swiften/Elements/StatusShow.h" + +namespace Swift { + +class OfflineRosterFilter : public RosterFilter { + public: + virtual ~OfflineRosterFilter() {} + virtual bool operator() (RosterItem *item) const { + ContactRosterItem *contactItem = dynamic_cast<ContactRosterItem*>(item); + return contactItem && contactItem->getStatusShow() == StatusShow::None; + } +}; + +} +#endif + + + diff --git a/Swiften/Roster/OpenChatRosterAction.h b/Swiften/Roster/OpenChatRosterAction.h new file mode 100644 index 0000000..03715a5 --- /dev/null +++ b/Swiften/Roster/OpenChatRosterAction.h @@ -0,0 +1,20 @@ +#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 new file mode 100644 index 0000000..28245af --- /dev/null +++ b/Swiften/Roster/Roster.cpp @@ -0,0 +1,139 @@ +#include "Swiften/Roster/Roster.h" + +#include "Swiften/Base/foreach.h" +#include "Swiften/Base/String.h" +#include "Swiften/JID/JID.h" +#include "Swiften/Roster/ContactRosterItem.h" +#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 <deque> + +namespace Swift { + +Roster::Roster(TreeWidget *treeWidget, TreeWidgetFactory *widgetFactory) : treeWidget_(treeWidget), widgetFactory_(widgetFactory) { +} + +Roster::~Roster() { + foreach (RosterItem* item, items_) { + delete item; + } + delete treeWidget_; +} + +TreeWidget* Roster::getWidget() { + return treeWidget_; +} + +GroupRosterItem* Roster::getGroup(const String& groupName) { + foreach (RosterItem *item, children_) { + GroupRosterItem *group = dynamic_cast<GroupRosterItem*>(item); + if (group && group->getName() == groupName) { + return group; + } + } + GroupRosterItem* group = new GroupRosterItem(groupName, treeWidget_, widgetFactory_); + children_.push_back(group); + items_.push_back(group); + return group; +} + +void Roster::handleUserAction(boost::shared_ptr<UserRosterAction> action) { + onUserAction(action); +} + +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); + item->onUserAction.connect(boost::bind(&Roster::handleUserAction, this, _1)); + filterItem(item); + +} + +void Roster::removeContact(const JID& jid) { + 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); + } + it++; + } +} + +void Roster::removeContactFromGroup(const JID& jid, const String& groupName) { + 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); + } + it++; + } +} + + +void Roster::applyOnItems(const RosterItemOperation& operation) { + std::deque<RosterItem*> queue(children_.begin(), children_.end()); + while (!queue.empty()) { + RosterItem* item = *queue.begin(); + queue.pop_front(); + operation(item); + GroupRosterItem* group = dynamic_cast<GroupRosterItem*>(item); + if (group) { + queue.insert(queue.begin(), group->getChildren().begin(), group->getChildren().end()); + } + } + filterAll(); +} + +void Roster::removeFilter(RosterFilter *filter) { + for (unsigned int i = 0; i < filters_.size(); i++) { + if (filters_[i] == filter) { + filters_.erase(filters_.begin() + i); + break; + } + } + filterAll(); +} + + +void Roster::filterItem(RosterItem* rosterItem) { + ContactRosterItem *item = dynamic_cast<ContactRosterItem*>(rosterItem); + if (!item) { + return; + } + bool hide = true; + foreach (RosterFilter *filter, filters_) { + hide &= (*filter)(item); + } + filters_.size() > 0 && hide ? item->hide() : item->show(); +} + +void Roster::filterAll() { + std::deque<RosterItem*> queue(children_.begin(), children_.end()); + 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); + } + } +} + +} + diff --git a/Swiften/Roster/Roster.h b/Swiften/Roster/Roster.h new file mode 100644 index 0000000..6010832 --- /dev/null +++ b/Swiften/Roster/Roster.h @@ -0,0 +1,49 @@ +#ifndef SWIFTEN_Roster_H +#define SWIFTEN_Roster_H + +#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> +#include <boost/signal.hpp> +#include <boost/shared_ptr.hpp> + +namespace Swift { + +class TreeWidgetFactory; +class TreeWidget; +class RosterItem; +class GroupRosterItem; + +class Roster { + public: + Roster(TreeWidget *treeWidget, TreeWidgetFactory *widgetFactory); + ~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); + boost::signal<void (boost::shared_ptr<UserRosterAction>)> onUserAction; + void addFilter(RosterFilter *filter) {filters_.push_back(filter);filterAll();} + void removeFilter(RosterFilter *filter); + std::vector<RosterFilter*> getFilters() {return filters_;} + + private: + void filterItem(RosterItem* item); + void filterAll(); + void handleUserAction(boost::shared_ptr<UserRosterAction> action); + TreeWidget *treeWidget_; + TreeWidgetFactory *widgetFactory_; + std::vector<RosterItem*> children_; + std::vector<RosterItem*> items_; + std::vector<RosterFilter*> filters_; +}; +} + +#endif diff --git a/Swiften/Roster/RosterFilter.h b/Swiften/Roster/RosterFilter.h new file mode 100644 index 0000000..a824304 --- /dev/null +++ b/Swiften/Roster/RosterFilter.h @@ -0,0 +1,17 @@ +#ifndef SWIFTEN_RosterFilter_H +#define SWIFTEN_RosterFilter_H + +#include "Swiften/Roster/RosterItem.h" + +namespace Swift { + +class RosterFilter { + public: + virtual ~RosterFilter() {} + virtual bool operator() (RosterItem* item) const = 0; +}; + +} +#endif + + diff --git a/Swiften/Roster/RosterItem.h b/Swiften/Roster/RosterItem.h new file mode 100644 index 0000000..2707920 --- /dev/null +++ b/Swiften/Roster/RosterItem.h @@ -0,0 +1,24 @@ +#ifndef SWIFTEN_RosterItem_H +#define SWIFTEN_RosterItem_H + +#include "Swiften/Roster/UserRosterAction.h" + +#include <boost/signal.hpp> +#include <boost/shared_ptr.hpp> + +namespace Swift { + +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); + } +}; + +} +#endif + diff --git a/Swiften/Roster/RosterItemOperation.h b/Swiften/Roster/RosterItemOperation.h new file mode 100644 index 0000000..ea8e723 --- /dev/null +++ b/Swiften/Roster/RosterItemOperation.h @@ -0,0 +1,16 @@ +#ifndef SWIFTEN_RosterItemOperation_H +#define SWIFTEN_RosterItemOperation_H + +#include "Swiften/Roster/RosterItem.h" + +namespace Swift { + +class RosterItemOperation { + public: + virtual ~RosterItemOperation() {} + virtual void operator() (RosterItem*) const = 0; +}; + +} +#endif + diff --git a/Swiften/Roster/SetAvatar.h b/Swiften/Roster/SetAvatar.h new file mode 100644 index 0000000..7bc9c37 --- /dev/null +++ b/Swiften/Roster/SetAvatar.h @@ -0,0 +1,33 @@ +#ifndef SWIFTEN_SetAvatar_H +#define SWIFTEN_SetAvatar_H + +#include "Swiften/Elements/Presence.h" +#include "Swiften/JID/JID.h" +#include "Swiften/Roster/RosterItemOperation.h" +#include "Swiften/Roster/ContactRosterItem.h" + +namespace Swift { + +class RosterItem; + +class SetAvatar : public RosterItemOperation { + public: + SetAvatar(const JID& jid, const String& path, JID::CompareType compareType = JID::WithoutResource) : jid_(jid), path_(path), compareType_(compareType) { + } + + virtual void operator() (RosterItem* item) const { + ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item); + if (contact && contact->getJID().equals(jid_, compareType_)) { + contact->setAvatarPath(path_); + } + } + + private: + JID jid_; + String path_; + JID::CompareType compareType_; +}; + +} +#endif + diff --git a/Swiften/Roster/SetPresence.h b/Swiften/Roster/SetPresence.h new file mode 100644 index 0000000..a18ae6d --- /dev/null +++ b/Swiften/Roster/SetPresence.h @@ -0,0 +1,38 @@ +#ifndef SWIFTEN_SetPresence_H +#define SWIFTEN_SetPresence_H + +#include "Swiften/Elements/Presence.h" +#include "Swiften/JID/JID.h" +#include "Swiften/Roster/RosterItemOperation.h" +#include "Swiften/Roster/ContactRosterItem.h" + +namespace Swift { + +class RosterItem; + +class SetPresence : public RosterItemOperation { + public: + SetPresence(boost::shared_ptr<Presence> presence, JID::CompareType compareType = JID::WithoutResource) : presence_(presence), compareType_(compareType) { + } + + 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()); + } + } + } + + private: + boost::shared_ptr<Presence> presence_; + JID::CompareType compareType_; +}; + +} +#endif + diff --git a/Swiften/Roster/TreeWidget.h b/Swiften/Roster/TreeWidget.h new file mode 100644 index 0000000..a26003e --- /dev/null +++ b/Swiften/Roster/TreeWidget.h @@ -0,0 +1,13 @@ +#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 new file mode 100644 index 0000000..f4ba68d --- /dev/null +++ b/Swiften/Roster/TreeWidgetFactory.h @@ -0,0 +1,20 @@ +#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 new file mode 100644 index 0000000..4124546 --- /dev/null +++ b/Swiften/Roster/TreeWidgetItem.h @@ -0,0 +1,34 @@ +#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 new file mode 100644 index 0000000..e6f6def --- /dev/null +++ b/Swiften/Roster/UnitTest/MockTreeWidget.h @@ -0,0 +1,14 @@ +#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 new file mode 100644 index 0000000..b2b4f10 --- /dev/null +++ b/Swiften/Roster/UnitTest/MockTreeWidgetFactory.h @@ -0,0 +1,50 @@ +#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(); + groupMembers_[group].push_back(entry); + return entry; + }; + virtual TreeWidgetItem* createTreeWidgetItem(TreeWidget*) { + MockTreeWidgetItem* group = new MockTreeWidgetItem(); + 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; + }; + private: + std::vector<MockTreeWidgetItem*> groups_; + std::map<TreeWidgetItem*, std::vector<MockTreeWidgetItem*> > groupMembers_; + MockTreeWidget* root_; +}; + +} + +#endif + + diff --git a/Swiften/Roster/UnitTest/MockTreeWidgetItem.h b/Swiften/Roster/UnitTest/MockTreeWidgetItem.h new file mode 100644 index 0000000..a40aca7 --- /dev/null +++ b/Swiften/Roster/UnitTest/MockTreeWidgetItem.h @@ -0,0 +1,30 @@ +#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 MockTreeWidgetItem : public TreeWidgetItem { + public: + 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_; +}; + +} +#endif + + diff --git a/Swiften/Roster/UnitTest/OfflineRosterFilterTest.cpp b/Swiften/Roster/UnitTest/OfflineRosterFilterTest.cpp new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/Swiften/Roster/UnitTest/OfflineRosterFilterTest.cpp diff --git a/Swiften/Roster/UnitTest/RosterTest.cpp b/Swiften/Roster/UnitTest/RosterTest.cpp new file mode 100644 index 0000000..b43a41c --- /dev/null +++ b/Swiften/Roster/UnitTest/RosterTest.cpp @@ -0,0 +1,57 @@ +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> +#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" + +using namespace Swift; + +class RosterTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(RosterTest); + CPPUNIT_TEST(testGetGroup); + CPPUNIT_TEST_SUITE_END(); + + private: + Roster *roster_; + TreeWidget *widget_; + TreeWidgetFactory *factory_; + JID jid1_; + JID jid2_; + JID jid3_; + + public: + + 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_); + } + + void tearDown() { + delete roster_; + //delete widget_; + delete factory_; + } + + void testGetGroup() { + roster_->addContact(jid1_, "Bert", "group1"); + 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_TEST_SUITE_REGISTRATION(RosterTest); + diff --git a/Swiften/Roster/UnitTest/XMPPRosterTest.cpp b/Swiften/Roster/UnitTest/XMPPRosterTest.cpp new file mode 100644 index 0000000..d03953e --- /dev/null +++ b/Swiften/Roster/UnitTest/XMPPRosterTest.cpp @@ -0,0 +1,164 @@ +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> +#include <boost/shared_ptr.hpp> +#include <boost/bind.hpp> + +#include <vector> + +#include "Swiften/Roster/XMPPRoster.h" + + +using namespace Swift; + +enum XMPPRosterEvents {None, Add, Remove, Update}; + +class XMPPRosterSignalHandler { +public: + XMPPRosterSignalHandler(XMPPRoster* roster) { + lastEvent_ = None; + roster->onJIDAdded.connect(boost::bind(&XMPPRosterSignalHandler::handleJIDAdded, this, _1)); + roster->onJIDRemoved.connect(boost::bind(&XMPPRosterSignalHandler::handleJIDRemoved, this, _1)); + roster->onJIDUpdated.connect(boost::bind(&XMPPRosterSignalHandler::handleJIDUpdated, this, _1, _2, _3)); + } + + XMPPRosterEvents getLastEvent() { + return lastEvent_; + } + + JID getLastJID() { + return lastJID_; + } + + String getLastOldName() { + return lastOldName_; + } + + std::vector<String> getLastOldGroups() { + return lastOldGroups_; + } + + void reset() { + lastEvent_ = None; + } + +private: + void handleJIDAdded(const JID& jid) { + lastJID_ = jid; + lastEvent_ = Add; + } + + void handleJIDRemoved(const JID& jid) { + lastJID_ = jid; + lastEvent_ = Remove; + } + + void handleJIDUpdated(const JID& jid, const String& oldName, const std::vector<String>& oldGroups) { + CPPUNIT_ASSERT_EQUAL(None, lastEvent_); + lastJID_ = jid; + lastOldName_ = oldName; + lastOldGroups_ = oldGroups; + lastEvent_ = Update; + } + + XMPPRosterEvents lastEvent_; + JID lastJID_; + String lastOldName_; + std::vector<String> lastOldGroups_; + +}; + +class XMPPRosterTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(XMPPRosterTest); + CPPUNIT_TEST(testJIDAdded); + CPPUNIT_TEST(testJIDRemoved); + CPPUNIT_TEST(testJIDUpdated); + CPPUNIT_TEST_SUITE_END(); + + private: + XMPPRoster* roster_; + XMPPRosterSignalHandler* handler_; + JID jid1_; + JID jid2_; + JID jid3_; + std::vector<String> groups1_; + std::vector<String> groups2_; + + + public: + + XMPPRosterTest() : jid1_(JID("a@b.c")), jid2_(JID("b@c.d")), jid3_(JID("c@d.e")) {} + + void setUp() { + roster_ = new XMPPRoster(); + handler_ = new XMPPRosterSignalHandler(roster_); + groups1_.push_back("bobs"); + groups1_.push_back("berts"); + groups2_.push_back("ernies"); + } + + void tearDown() { + delete roster_; + } + + void testJIDAdded() { + roster_->addContact(jid1_, "NewName", groups1_, RosterItemPayload::Both); + CPPUNIT_ASSERT_EQUAL(Add, handler_->getLastEvent()); + CPPUNIT_ASSERT_EQUAL(jid1_, handler_->getLastJID()); + CPPUNIT_ASSERT_EQUAL(String("NewName"), roster_->getNameForJID(jid1_)); + CPPUNIT_ASSERT(groups1_ == roster_->getGroupsForJID(jid1_)); + handler_->reset(); + roster_->addContact(jid2_, "NameTwo", groups1_, RosterItemPayload::Both); + CPPUNIT_ASSERT_EQUAL(Add, handler_->getLastEvent()); + CPPUNIT_ASSERT_EQUAL(jid2_, handler_->getLastJID()); + CPPUNIT_ASSERT_EQUAL(String("NameTwo"), roster_->getNameForJID(jid2_)); + CPPUNIT_ASSERT_EQUAL(String("NewName"), roster_->getNameForJID(jid1_)); + CPPUNIT_ASSERT(groups1_ == roster_->getGroupsForJID(jid2_)); + CPPUNIT_ASSERT(groups1_ == roster_->getGroupsForJID(jid1_)); + handler_->reset(); + roster_->addContact(jid3_, "NewName", groups2_, RosterItemPayload::Both); + CPPUNIT_ASSERT_EQUAL(Add, handler_->getLastEvent()); + CPPUNIT_ASSERT_EQUAL(jid3_, handler_->getLastJID()); + CPPUNIT_ASSERT_EQUAL(String("NewName"), roster_->getNameForJID(jid3_)); + CPPUNIT_ASSERT(groups2_ == roster_->getGroupsForJID(jid3_)); + } + + void testJIDRemoved() { + roster_->addContact(jid1_, "NewName", groups1_, RosterItemPayload::Both); + handler_->reset(); + roster_->removeContact(jid1_); + CPPUNIT_ASSERT_EQUAL(Remove, handler_->getLastEvent()); + CPPUNIT_ASSERT_EQUAL(jid1_, handler_->getLastJID()); + handler_->reset(); + roster_->addContact(jid1_, "NewName2", groups1_, RosterItemPayload::Both); + CPPUNIT_ASSERT_EQUAL(Add, handler_->getLastEvent()); + CPPUNIT_ASSERT_EQUAL(jid1_, handler_->getLastJID()); + CPPUNIT_ASSERT_EQUAL(String("NewName2"), roster_->getNameForJID(jid1_)); + roster_->addContact(jid2_, "NewName3", groups1_, RosterItemPayload::Both); + handler_->reset(); + roster_->removeContact(jid2_); + CPPUNIT_ASSERT_EQUAL(Remove, handler_->getLastEvent()); + CPPUNIT_ASSERT_EQUAL(jid2_, handler_->getLastJID()); + handler_->reset(); + roster_->removeContact(jid1_); + CPPUNIT_ASSERT_EQUAL(Remove, handler_->getLastEvent()); + CPPUNIT_ASSERT_EQUAL(jid1_, handler_->getLastJID()); + } + + void testJIDUpdated() { + roster_->addContact(jid1_, "NewName", groups1_, RosterItemPayload::Both); + CPPUNIT_ASSERT_EQUAL(Add, handler_->getLastEvent()); + CPPUNIT_ASSERT_EQUAL(jid1_, handler_->getLastJID()); + CPPUNIT_ASSERT_EQUAL(String("NewName"), roster_->getNameForJID(jid1_)); + CPPUNIT_ASSERT(groups1_ == roster_->getGroupsForJID(jid1_)); + handler_->reset(); + roster_->addContact(jid1_, "NameTwo", groups2_, RosterItemPayload::Both); + CPPUNIT_ASSERT_EQUAL(Update, handler_->getLastEvent()); + CPPUNIT_ASSERT_EQUAL(jid1_, handler_->getLastJID()); + CPPUNIT_ASSERT_EQUAL(String("NameTwo"), roster_->getNameForJID(jid1_)); + CPPUNIT_ASSERT(groups2_ == roster_->getGroupsForJID(jid1_)); + } + +}; +CPPUNIT_TEST_SUITE_REGISTRATION(XMPPRosterTest); + diff --git a/Swiften/Roster/UserRosterAction.h b/Swiften/Roster/UserRosterAction.h new file mode 100644 index 0000000..80ace68 --- /dev/null +++ b/Swiften/Roster/UserRosterAction.h @@ -0,0 +1,32 @@ +#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/Roster/XMPPRoster.cpp b/Swiften/Roster/XMPPRoster.cpp new file mode 100644 index 0000000..62edc45 --- /dev/null +++ b/Swiften/Roster/XMPPRoster.cpp @@ -0,0 +1,48 @@ +#include "Swiften/Roster/XMPPRoster.h" + +namespace Swift { + +void XMPPRoster::addContact(const JID& jid, const String& name, const std::vector<String>& groups, RosterItemPayload::Subscription subscription) { + JID bareJID(jid.toBare()); + bool exists = containsJID(bareJID); + String oldName = getNameForJID(bareJID); + std::vector<String> oldGroups = entries_[bareJID].groups; + if (exists) { + entries_.erase(bareJID); + } + XMPPRosterItem item; + item.groups = groups; + item.name = name; + item.jid = jid; + item.subscription = subscription; + entries_[bareJID] = item; + if (exists) { + onJIDUpdated(bareJID, oldName, oldGroups); + } else { + onJIDAdded(bareJID); + } +} + +void XMPPRoster::removeContact(const JID& jid) { + entries_.erase(JID(jid.toBare())); + onJIDRemoved(jid); +} + +bool XMPPRoster::containsJID(const JID& jid) { + return entries_.find(JID(jid.toBare())) != entries_.end(); +} + +const String& XMPPRoster::getNameForJID(const JID& jid) { + return entries_[JID(jid.toBare())].name; +} + +const std::vector<String>& XMPPRoster::getGroupsForJID(const JID& jid) { + return entries_[JID(jid.toBare())].groups; +} + +RosterItemPayload::Subscription XMPPRoster::getSubscriptionStateForJID(const JID& jid) { + return entries_[JID(jid.toBare())].subscription; +} + +} + diff --git a/Swiften/Roster/XMPPRoster.h b/Swiften/Roster/XMPPRoster.h new file mode 100644 index 0000000..47326c3 --- /dev/null +++ b/Swiften/Roster/XMPPRoster.h @@ -0,0 +1,44 @@ +#ifndef SWIFTEN_XMPPRoster_H +#define SWIFTEN_XMPPRoster_H + +#include "Swiften/Base/String.h" +#include "Swiften/JID/JID.h" +#include "Swiften/Elements/RosterItemPayload.h" + +#include <map> +#include <vector> +#include <boost/signal.hpp> + +namespace Swift { + +struct XMPPRosterItem { + JID jid; + String name; + std::vector<String> groups; + RosterItemPayload::Subscription subscription; +}; + +class XMPPRoster { + public: + XMPPRoster() {}; + ~XMPPRoster() {}; + + void addContact(const JID& jid, const String& name, const std::vector<String>& groups, const RosterItemPayload::Subscription subscription); + bool containsJID(const JID& jid); + void removeContact(const JID& jid); + RosterItemPayload::Subscription getSubscriptionStateForJID(const JID& jid); + const String& getNameForJID(const JID& jid); + const std::vector<String>& getGroupsForJID(const JID& jid); + + boost::signal<void (const JID&)> onJIDAdded; + boost::signal<void (const JID&)> onJIDRemoved; + boost::signal<void (const JID&, const String&, const std::vector<String>&)> onJIDUpdated; + + private: + //std::map<JID, std::pair<String, std::vector<String> > > entries_; + std::map<JID, XMPPRosterItem> entries_; +}; +} + +#endif + |