From 7d323757a6bbd93148fc25b94778e92c4ab3d665 Mon Sep 17 00:00:00 2001
From: Kevin Smith <git@kismith.co.uk>
Date: Fri, 11 Feb 2011 21:49:56 +0000
Subject: Allow group changes at the same time as nick changes.

Resolves: #696
Also hopefully
Resolves: #764

diff --git a/Swift/Controllers/Roster/GroupRosterItem.cpp b/Swift/Controllers/Roster/GroupRosterItem.cpp
index c473ae7..7d0cf85 100644
--- a/Swift/Controllers/Roster/GroupRosterItem.cpp
+++ b/Swift/Controllers/Roster/GroupRosterItem.cpp
@@ -110,6 +110,25 @@ ContactRosterItem* GroupRosterItem::removeChild(const JID& jid) {
 	return removed;
 }
 
+GroupRosterItem* GroupRosterItem::removeGroupChild(const String& groupName) {
+	std::vector<RosterItem*>::iterator it = children_.begin();
+	GroupRosterItem* removed = NULL;
+	while (it != children_.end()) {
+		GroupRosterItem* group = dynamic_cast<GroupRosterItem*>(*it);
+		if (group && group->getDisplayName() == groupName) {
+			displayedChildren_.erase(std::remove(displayedChildren_.begin(), displayedChildren_.end(), group), displayedChildren_.end());
+			removed = group;
+			delete group;
+			it = children_.erase(it);
+			continue;
+		}
+		it++;
+	}
+	onChildrenChanged();
+	onDataChanged();
+	return removed;
+}
+
 /**
  * Returns false if the list didn't need a resort
  */
diff --git a/Swift/Controllers/Roster/GroupRosterItem.h b/Swift/Controllers/Roster/GroupRosterItem.h
index 85e8e46..ff5e798 100644
--- a/Swift/Controllers/Roster/GroupRosterItem.h
+++ b/Swift/Controllers/Roster/GroupRosterItem.h
@@ -22,6 +22,7 @@ class GroupRosterItem : public RosterItem {
 		const std::vector<RosterItem*>& getDisplayedChildren() const;
 		void addChild(RosterItem* item);
 		ContactRosterItem* removeChild(const JID& jid);
+		GroupRosterItem* removeGroupChild(const String& group);
 		void removeAll();
 		void setDisplayed(RosterItem* item, bool displayed);
 		boost::signal<void ()> onChildrenChanged;
diff --git a/Swift/Controllers/Roster/Roster.cpp b/Swift/Controllers/Roster/Roster.cpp
index 7967a38..9edcaaf 100644
--- a/Swift/Controllers/Roster/Roster.cpp
+++ b/Swift/Controllers/Roster/Roster.cpp
@@ -60,6 +60,10 @@ GroupRosterItem* Roster::getGroup(const String& groupName) {
 	return group;
 }
 
+void Roster::removeGroup(const String& group) {
+	root_->removeGroupChild(group);
+}
+
 void Roster::handleDataChanged(RosterItem* item) {
 	onDataChanged(item);
 }
diff --git a/Swift/Controllers/Roster/Roster.h b/Swift/Controllers/Roster/Roster.h
index 70ff0b5..5589f97 100644
--- a/Swift/Controllers/Roster/Roster.h
+++ b/Swift/Controllers/Roster/Roster.h
@@ -30,6 +30,7 @@ class Roster {
 		void addContact(const JID& jid, const JID& displayJID, const String& name, const String& group, const String& avatarPath);
 		void removeContact(const JID& jid);
 		void removeContactFromGroup(const JID& jid, const String& group);
+		void removeGroup(const String& group);
 		void removeAll();
 		void applyOnItems(const RosterItemOperation& operation);
 		void applyOnAllItems(const RosterItemOperation& operation);
@@ -41,8 +42,8 @@ class Roster {
 		boost::signal<void (GroupRosterItem*)> onChildrenChanged;
 		boost::signal<void (GroupRosterItem*)> onGroupAdded;
 		boost::signal<void (RosterItem*)> onDataChanged;
-	private:
 		GroupRosterItem* getGroup(const String& groupName);
+	private:
 		void handleDataChanged(RosterItem* item);
 		void handleChildrenChanged(GroupRosterItem* item);
 		void filterGroup(GroupRosterItem* item);
diff --git a/Swift/Controllers/Roster/RosterController.cpp b/Swift/Controllers/Roster/RosterController.cpp
index 2dddd7d..758d4f2 100644
--- a/Swift/Controllers/Roster/RosterController.cpp
+++ b/Swift/Controllers/Roster/RosterController.cpp
@@ -27,6 +27,7 @@
 #include "Swift/Controllers/Roster/SetAvatar.h"
 #include "Swift/Controllers/Roster/SetName.h"
 #include "Swift/Controllers/Roster/OfflineRosterFilter.h"
+#include "Swift/Controllers/Roster/GroupRosterItem.h"
 #include "Swiften/Roster/XMPPRoster.h"
 #include "Swiften/Roster/XMPPRosterItem.h"
 #include "Swift/Controllers/UIEvents/AddContactUIEvent.h"
@@ -141,7 +142,6 @@ void RosterController::handleOnJIDRemoved(const JID& jid) {
 void RosterController::handleOnJIDUpdated(const JID& jid, const String& oldName, const std::vector<String> passedOldGroups) {
 	if (oldName != xmppRoster_->getNameForJID(jid)) {
 		roster_->applyOnItems(SetName(nickResolver_->jidToNick(jid), jid));
-		return;
 	}
 	std::vector<String> groups = xmppRoster_->getGroupsForJID(jid);
 	std::vector<String> oldGroups = passedOldGroups;
@@ -161,6 +161,9 @@ void RosterController::handleOnJIDUpdated(const JID& jid, const String& oldName,
 	foreach(const String& group, oldGroups) {
 		if (std::find(groups.begin(), groups.end(), group) == groups.end()) {
 			roster_->removeContactFromGroup(jid, group);
+			if (roster_->getGroup(group)->getChildren().size() == 0) {
+				roster_->removeGroup(group);
+			}
 		}
 	}
 	applyAllPresenceTo(jid);
diff --git a/Swift/Controllers/Roster/UnitTest/RosterControllerTest.cpp b/Swift/Controllers/Roster/UnitTest/RosterControllerTest.cpp
index 604cda6..466a528 100644
--- a/Swift/Controllers/Roster/UnitTest/RosterControllerTest.cpp
+++ b/Swift/Controllers/Roster/UnitTest/RosterControllerTest.cpp
@@ -40,6 +40,7 @@ class RosterControllerTest : public CppUnit::TestFixture {
 		CPPUNIT_TEST(testAdd);
 		CPPUNIT_TEST(testAddSubscription);
 		CPPUNIT_TEST(testReceiveRename);
+		CPPUNIT_TEST(testReceiveRegroup);
 		CPPUNIT_TEST(testSendRename);
 		CPPUNIT_TEST(testPresence);
 		CPPUNIT_TEST(testHighestPresence);
@@ -237,6 +238,32 @@ class RosterControllerTest : public CppUnit::TestFixture {
 			CPPUNIT_ASSERT_EQUAL(String("NewName"), groupChild(0)->getChildren()[0]->getDisplayName());
 		};
 
+	void testReceiveRegroup() {
+		std::vector<String> oldGroups;
+		std::vector<String> newGroups;
+		newGroups.push_back("A Group");
+		std::vector<String> newestGroups;
+		newestGroups.push_back("Best Group");
+		JID jid("test@testdomain.com");
+		xmppRoster_->addContact(jid, "", oldGroups, RosterItemPayload::Both);
+
+		CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(CHILDREN.size()));
+		CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(groupChild(0)->getChildren().size()));
+		CPPUNIT_ASSERT_EQUAL(jid.toString(), groupChild(0)->getChildren()[0]->getDisplayName());
+
+		xmppRoster_->addContact(jid, "new name", newGroups, RosterItemPayload::Both);
+		CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(CHILDREN.size()));
+		CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(groupChild(0)->getChildren().size()));
+		CPPUNIT_ASSERT_EQUAL(String("new name"), groupChild(0)->getChildren()[0]->getDisplayName());
+		CPPUNIT_ASSERT_EQUAL(String("A Group"), groupChild(0)->getDisplayName());
+
+		xmppRoster_->addContact(jid, "new name", newestGroups, RosterItemPayload::Both);
+		CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(CHILDREN.size()));
+		CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(groupChild(0)->getChildren().size()));
+		CPPUNIT_ASSERT_EQUAL(String("new name"), groupChild(0)->getChildren()[0]->getDisplayName());
+		CPPUNIT_ASSERT_EQUAL(String("Best Group"), groupChild(0)->getDisplayName());
+	};
+
 		void testSendRename() {
 			JID jid("testling@wonderland.lit");
 			std::vector<String> groups;
-- 
cgit v0.10.2-6-g49f6