From ecc4dc5633b6d3b46ff2ef24d7d976172b9c01ae Mon Sep 17 00:00:00 2001
From: Kevin Smith <git@kismith.co.uk>
Date: Fri, 24 Sep 2010 16:38:29 +0100
Subject: Add logic and tests for modifying roster items. No UI Yet.

(Partially)
Resolves: #575
(Partially)
Resolves: #272

diff --git a/Swift/Controllers/RosterController.cpp b/Swift/Controllers/RosterController.cpp
index c8f94f1..79cf3b8 100644
--- a/Swift/Controllers/RosterController.cpp
+++ b/Swift/Controllers/RosterController.cpp
@@ -29,7 +29,8 @@
 #include "Swiften/Roster/XMPPRoster.h"
 #include "Swift/Controllers/UIEvents/AddContactUIEvent.h"
 #include "Swift/Controllers/UIEvents/RemoveRosterItemUIEvent.h"
-
+#include "Swift/Controllers/UIEvents/RenameRosterItemUIEvent.h"
+#include "Swift/Controllers/UIEvents/RegroupRosterItemUIEvent.h"
 
 namespace Swift {
 	
@@ -172,7 +173,42 @@ void RosterController::handleUIEvent(boost::shared_ptr<UIEvent> event) {
 
 		return;
 	}
-
+	boost::shared_ptr<RenameRosterItemUIEvent> renameEvent = boost::dynamic_pointer_cast<RenameRosterItemUIEvent>(event);
+	if (renameEvent) {
+		JID contact(renameEvent->getJID());
+		RosterItemPayload item(contact, renameEvent->getNewName(), xmppRoster_->getSubscriptionStateForJID(contact));
+		item.setGroups(xmppRoster_->getGroupsForJID(contact));
+		boost::shared_ptr<RosterPayload> roster(new RosterPayload());
+		roster->addItem(item);
+		boost::shared_ptr<SetRosterRequest> request(new SetRosterRequest(roster, iqRouter_));
+		request->onResponse.connect(boost::bind(&RosterController::handleRosterSetError, this, _1, roster));
+		request->send();
+		return;
+	}
+	boost::shared_ptr<RegroupRosterItemUIEvent> regroupEvent = boost::dynamic_pointer_cast<RegroupRosterItemUIEvent>(event);
+	if (regroupEvent) {
+		JID contact(regroupEvent->getJID());
+		RosterItemPayload item(contact, xmppRoster_->getNameForJID(contact), xmppRoster_->getSubscriptionStateForJID(contact));
+		std::vector<String> newGroups;
+		const std::vector<String> addedGroups = regroupEvent->getAddedGroups();
+		const std::vector<String> removedGroups = regroupEvent->getRemovedGroups();
+		foreach (const String& oldGroup, xmppRoster_->getGroupsForJID(contact)) {
+			if (std::find(removedGroups.begin(), removedGroups.end(), oldGroup) == removedGroups.end()
+					&& std::find(addedGroups.begin(), addedGroups.end(), oldGroup) == addedGroups.end()) {
+					newGroups.push_back(oldGroup);
+			}
+		}
+		foreach (const String& newGroup, regroupEvent->getAddedGroups()) {
+			newGroups.push_back(newGroup);
+		}
+		item.setGroups(newGroups);
+		boost::shared_ptr<RosterPayload> roster(new RosterPayload());
+		roster->addItem(item);
+		boost::shared_ptr<SetRosterRequest> request(new SetRosterRequest(roster, iqRouter_));
+		request->onResponse.connect(boost::bind(&RosterController::handleRosterSetError, this, _1, roster));
+		request->send();
+		return;
+	}
 }
 
 void RosterController::handleRosterSetError(boost::optional<ErrorPayload> error, boost::shared_ptr<RosterPayload> rosterPayload) {
diff --git a/Swift/Controllers/UIEvents/RegroupRosterItemUIEvent.h b/Swift/Controllers/UIEvents/RegroupRosterItemUIEvent.h
new file mode 100644
index 0000000..b8552b3
--- /dev/null
+++ b/Swift/Controllers/UIEvents/RegroupRosterItemUIEvent.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2010 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+#include <vector>
+
+#include "Swift/Controllers/UIEvents/UIEvent.h"
+#include "Swiften/MUC/MUCBookmark.h"
+
+namespace Swift {
+	/**
+	 * An event for regrouping a roster item.
+	 * This doesn't need to cover all groups, so it's valid to have the
+	 * contact in several groups that are neither removedGroups or addedGroups.
+	 */
+	class RegroupRosterItemUIEvent : public UIEvent {
+		public:
+			RegroupRosterItemUIEvent(const JID& jid, const std::vector<String>& addedGroups, const std::vector<String>& removedGroups) : jid_(jid), addedGroups_(addedGroups), removedGroups_(removedGroups) {}
+
+			const JID& getJID() const {return jid_;}
+			const std::vector<String>& getAddedGroups() const {return addedGroups_;}
+			const std::vector<String>& getRemovedGroups() const {return removedGroups_;}
+
+		private:
+			JID jid_;
+			std::vector<String> addedGroups_;
+			std::vector<String> removedGroups_;
+	};
+}
diff --git a/Swift/Controllers/UIEvents/RenameRosterItemUIEvent.h b/Swift/Controllers/UIEvents/RenameRosterItemUIEvent.h
new file mode 100644
index 0000000..4b550e6
--- /dev/null
+++ b/Swift/Controllers/UIEvents/RenameRosterItemUIEvent.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2010 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include "Swift/Controllers/UIEvents/UIEvent.h"
+#include "Swiften/MUC/MUCBookmark.h"
+
+namespace Swift {
+	class RenameRosterItemUIEvent : public UIEvent {
+		public:
+			RenameRosterItemUIEvent(const JID& jid, const String& newName) : jid_(jid), newName_(newName) {}
+
+			const JID& getJID() const {return jid_;}
+			const String& getNewName() const {return newName_;}
+
+		private:
+			JID jid_;
+			String newName_;
+	};
+}
diff --git a/Swift/Controllers/UIInterfaces/MainWindow.h b/Swift/Controllers/UIInterfaces/MainWindow.h
index 4709499..5d0c14e 100644
--- a/Swift/Controllers/UIInterfaces/MainWindow.h
+++ b/Swift/Controllers/UIInterfaces/MainWindow.h
@@ -26,7 +26,6 @@ namespace Swift {
 			virtual void setMyStatusType(StatusShow::Type type) = 0;
 			virtual void setRosterModel(Roster* roster) = 0;
 			
-			boost::signal<void (const JID&)> onStartChatRequest;
 			boost::signal<void (StatusShow::Type, const String&)> onChangeStatusRequest;
 			boost::signal<void (bool)> onShowOfflineToggled;
 			boost::signal<void ()> onSignOutRequest;
diff --git a/Swift/Controllers/UnitTest/RosterControllerTest.cpp b/Swift/Controllers/UnitTest/RosterControllerTest.cpp
index de46588..4ecc4c8 100644
--- a/Swift/Controllers/UnitTest/RosterControllerTest.cpp
+++ b/Swift/Controllers/UnitTest/RosterControllerTest.cpp
@@ -26,6 +26,8 @@
 #include "Swiften/Presence/PresenceSender.h"
 #include "Swift/Controllers/NickResolver.h"
 #include "Swift/Controllers/UIEvents/UIEventStream.h"
+#include "Swift/Controllers/UIEvents/RenameRosterItemUIEvent.h"
+#include "Swift/Controllers/UIEvents/RegroupRosterItemUIEvent.h"
 #include "Swiften/MUC/MUCRegistry.h"
 
 using namespace Swift;
@@ -37,7 +39,9 @@ class RosterControllerTest : public CppUnit::TestFixture
 		CPPUNIT_TEST_SUITE(RosterControllerTest);
 		CPPUNIT_TEST(testAdd);
 		CPPUNIT_TEST(testAddSubscription);
-		CPPUNIT_TEST(testRename);
+		CPPUNIT_TEST(testReceiveRename);
+		CPPUNIT_TEST(testSendRename);
+		CPPUNIT_TEST(testSendRegroup);
 		CPPUNIT_TEST_SUITE_END();
 
 	public:
@@ -107,7 +111,7 @@ class RosterControllerTest : public CppUnit::TestFixture
 
 		};
 
-		void testRename() {
+		void testReceiveRename() {
 			std::vector<String> groups;
 			JID jid("test@testdomain.com");
 			xmppRoster_->addContact(jid, "name", groups, RosterItemPayload::Both);
@@ -121,6 +125,71 @@ class RosterControllerTest : public CppUnit::TestFixture
 			CPPUNIT_ASSERT_EQUAL(String("NewName"), groupChild(0)->getChildren()[0]->getDisplayName());
 		};
 
+		void testSendRename() {
+			JID jid("testling@wonderland.lit");
+			std::vector<String> groups;
+			groups.push_back("Friends");
+			groups.push_back("Enemies");
+			xmppRoster_->addContact(jid, "Bob", groups, RosterItemPayload::From);
+			CPPUNIT_ASSERT_EQUAL(groups.size(), xmppRoster_->getGroupsForJID(jid).size());
+			uiEventStream_->send(boost::shared_ptr<UIEvent>(new RenameRosterItemUIEvent(jid, "Robert")));
+			CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), channel_->iqs_.size());
+			CPPUNIT_ASSERT_EQUAL(IQ::Set, channel_->iqs_[0]->getType());
+			boost::shared_ptr<RosterPayload> payload = channel_->iqs_[0]->getPayload<RosterPayload>();
+			CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), payload->getItems().size());
+			RosterItemPayload item = payload->getItems()[0];
+			CPPUNIT_ASSERT_EQUAL(jid, item.getJID());
+			CPPUNIT_ASSERT_EQUAL(String("Robert"), item.getName());
+
+			CPPUNIT_ASSERT_EQUAL(groups.size(), item.getGroups().size());
+			assertVectorsEqual(groups, item.getGroups(), __LINE__);
+		}
+
+		void testSendRegroup() {
+			JID jid("testling@wonderland.lit");
+			String friends("Friends");
+			String enemies("Ememies");
+			String people("People");
+			String contacts("Contacts");
+			std::vector<String> oldGroups;
+			oldGroups.push_back(friends);
+			oldGroups.push_back(enemies);
+			std::vector<String> newGroups;
+			newGroups.push_back(friends);
+			newGroups.push_back(people);
+			newGroups.push_back(contacts);
+			std::vector<String> addedGroups;
+			addedGroups.push_back(people);
+			addedGroups.push_back(contacts);
+			std::vector<String> removedGroups;
+			removedGroups.push_back(enemies);
+
+
+			xmppRoster_->addContact(jid, "Bob", oldGroups, RosterItemPayload::From);
+			CPPUNIT_ASSERT_EQUAL(oldGroups.size(), xmppRoster_->getGroupsForJID(jid).size());
+			uiEventStream_->send(boost::shared_ptr<UIEvent>(new RegroupRosterItemUIEvent(jid, addedGroups, removedGroups)));
+			CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), channel_->iqs_.size());
+			CPPUNIT_ASSERT_EQUAL(IQ::Set, channel_->iqs_[0]->getType());
+			boost::shared_ptr<RosterPayload> payload = channel_->iqs_[0]->getPayload<RosterPayload>();
+			CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), payload->getItems().size());
+			RosterItemPayload item = payload->getItems()[0];
+			CPPUNIT_ASSERT_EQUAL(jid, item.getJID());
+			CPPUNIT_ASSERT_EQUAL(String("Bob"), item.getName());
+
+			CPPUNIT_ASSERT_EQUAL(newGroups.size(), item.getGroups().size());
+			assertVectorsEqual(newGroups, item.getGroups(), __LINE__);
+		}
+
+		void assertVectorsEqual(const std::vector<String>& v1, const std::vector<String>& v2, int line) {
+			foreach (const String& entry, v1) {
+				if (std::find(v2.begin(), v2.end(), entry) == v2.end()) {
+					std::stringstream stream;
+					stream <<	"Couldn't find " << entry.getUTF8String() << " in v2 (line " << line << ")";
+					CPPUNIT_FAIL(stream.str());
+				}
+			}
+		}
+
 	private:
 		JID jid_;
 		XMPPRoster* xmppRoster_;
-- 
cgit v0.10.2-6-g49f6