From 558e5eb1b4b7d7de5ef291c173ed6ac012f23854 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Remko=20Tron=C3=A7on?= <git@el-tramo.be>
Date: Mon, 4 Jul 2011 13:04:13 +0200
Subject: Fixed TableRoster bugs.


diff --git a/BuildTools/SCons/SConstruct b/BuildTools/SCons/SConstruct
index a7496f2..42947eb 100644
--- a/BuildTools/SCons/SConstruct
+++ b/BuildTools/SCons/SConstruct
@@ -244,6 +244,8 @@ if target in ["iphone-device", "iphone-simulator", "xcode"] :
 		env["XCODE_PLATFORM_DEVELOPER_BIN_DIR"] = os.environ["PLATFORM_DEVELOPER_BIN_DIR"]
 		env["XCODE_SDKROOT"] = os.environ["SDKROOT"]
 		env["XCODE_ARCH_FLAGS"] = sum([["-arch", arch] for arch in os.environ["ARCHS"].split(" ")], [])
+		# Usae absolute path sources so Xcode can highlight compilation errors in swiften
+		env['CXXCOM'] = '$CXX -o $TARGET -c $CXXFLAGS $CCFLAGS $_CCCOMCOM ${SOURCES.abspath}'
 	else :
 		# Hard code values
 		env["XCODE_PLATFORM_DEVELOPER_BIN_DIR"] = "/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin"
@@ -515,7 +517,8 @@ if env["PLATFORM"] == "win32" :
 
 # LibXML
 conf = Configure(conf_env, custom_tests = {"CheckVersion": CheckVersion})
-if conf.CheckCHeader("libxml/parser.h") and conf.CheckLib("xml2") and conf.CheckVersion("LibXML", "2.6.23", "LIBXML_VERSION", "libxml/xmlversion.h", 20623) :
+if conf.CheckCHeader("libxml/parser.h") and conf.CheckLib("xml2") :
+#and conf.CheckVersion("LibXML", "2.6.23", "LIBXML_VERSION", "libxml/xmlversion.h", 20623) :
 	env["HAVE_LIBXML"] = 1
 	env["LIBXML_FLAGS"] = { "LIBS": ["xml2"] }
 conf.Finish()
@@ -524,7 +527,8 @@ if not env.get("HAVE_LIBXML", 0) :
 	libxml_env = conf_env.Clone()
 	libxml_env.Append(CPPPATH = ["/usr/include/libxml2"])
 	conf = Configure(libxml_env, custom_tests = {"CheckVersion": CheckVersion})
-	if conf.CheckCHeader("libxml/parser.h") and conf.CheckLib("xml2") and conf.CheckVersion("LibXML", "2.6.23", "LIBXML_VERSION", "libxml/xmlversion.h", 20623):
+	if conf.CheckCHeader("libxml/parser.h") and conf.CheckLib("xml2") :
+#	and conf.CheckVersion("LibXML", "2.6.23", "LIBXML_VERSION", "libxml/xmlversion.h", 20623):
 		env["HAVE_LIBXML"] = 1
 		env["LIBXML_FLAGS"] = { "CPPPATH": ["/usr/include/libxml2"], "LIBS": ["xml2"] }
 	conf.Finish()
diff --git a/Swift/Controllers/Roster/TableRoster.cpp b/Swift/Controllers/Roster/TableRoster.cpp
index 66e3a85..54f2484 100644
--- a/Swift/Controllers/Roster/TableRoster.cpp
+++ b/Swift/Controllers/Roster/TableRoster.cpp
@@ -40,7 +40,7 @@ namespace Swift {
 
 	struct ItemNeedsUpdate {
 			bool operator()(const TableRoster::Item& i1, const TableRoster::Item& i2) const {
-				return i1.description != i2.description || i1.name != i2.name;
+				return i1.status != i2.status || i1.description != i2.description || i1.name != i2.name;
 			}
 	};
 
@@ -58,18 +58,24 @@ namespace Swift {
 
 using namespace Swift;
 
-TableRoster::TableRoster(Roster* model, TimerFactory* timerFactory, int updateDelay) : model(model) {
+TableRoster::TableRoster(Roster* model, TimerFactory* timerFactory, int updateDelay) : model(model), updatePending(false) {
 	updateTimer = timerFactory->createTimer(updateDelay);
-	model->onChildrenChanged.connect(boost::bind(&TableRoster::scheduleUpdate, this));
-	model->onGroupAdded.connect(boost::bind(&TableRoster::scheduleUpdate, this));
-	model->onDataChanged.connect(boost::bind(&TableRoster::scheduleUpdate, this));
+	updateTimer->onTick.connect(boost::bind(&TableRoster::handleUpdateTimerTick, this));
+	if (model) {
+		model->onChildrenChanged.connect(boost::bind(&TableRoster::scheduleUpdate, this));
+		model->onGroupAdded.connect(boost::bind(&TableRoster::scheduleUpdate, this));
+		model->onDataChanged.connect(boost::bind(&TableRoster::scheduleUpdate, this));
+	}
 }
 
 TableRoster::~TableRoster() {
-	model->onDataChanged.disconnect(boost::bind(&TableRoster::scheduleUpdate, this));
-	model->onGroupAdded.disconnect(boost::bind(&TableRoster::scheduleUpdate, this));
-	model->onChildrenChanged.disconnect(boost::bind(&TableRoster::scheduleUpdate, this));
 	updateTimer->stop();
+	updateTimer->onTick.disconnect(boost::bind(&TableRoster::handleUpdateTimerTick, this));
+	if (model) {
+		model->onDataChanged.disconnect(boost::bind(&TableRoster::scheduleUpdate, this));
+		model->onGroupAdded.disconnect(boost::bind(&TableRoster::scheduleUpdate, this));
+		model->onChildrenChanged.disconnect(boost::bind(&TableRoster::scheduleUpdate, this));
+	}
 }
 			
 size_t TableRoster::getNumberOfSections() const {
@@ -94,15 +100,19 @@ void TableRoster::handleUpdateTimerTick() {
 
 	// Get a model for the new roster
 	std::vector<Section> newSections;
-	foreach(RosterItem* item, model->getRoot()->getDisplayedChildren()) {
-		if (GroupRosterItem* groupItem = boost::polymorphic_downcast<GroupRosterItem*>(item)) {
-			Section section(groupItem->getDisplayName());
-			foreach(RosterItem* groupChildItem, groupItem->getDisplayedChildren()) {
-				if (ContactRosterItem* contact = boost::polymorphic_downcast<ContactRosterItem*>(groupChildItem)) {
-					section.items.push_back(Item(contact->getDisplayName(), contact->getStatusText(), contact->getDisplayJID()));
+	if (model) {
+		foreach(RosterItem* item, model->getRoot()->getDisplayedChildren()) {
+			if (GroupRosterItem* groupItem = boost::polymorphic_downcast<GroupRosterItem*>(item)) {
+				//std::cerr << "* " << groupItem->getDisplayName() << std::endl;
+				Section section(groupItem->getDisplayName());
+				foreach(RosterItem* groupChildItem, groupItem->getDisplayedChildren()) {
+					if (ContactRosterItem* contact = boost::polymorphic_downcast<ContactRosterItem*>(groupChildItem)) {
+						//std::cerr << "  - " << contact->getDisplayJID() << std::endl;
+						section.items.push_back(Item(contact->getDisplayName(), contact->getStatusText(), contact->getDisplayJID(), contact->getStatusShow()));
+					}
 				}
+				newSections.push_back(section);
 			}
-			newSections.push_back(section);
 		}
 	}
 
@@ -120,17 +130,48 @@ void TableRoster::handleUpdateTimerTick() {
 		std::vector<size_t> itemRemoves;
 		std::vector<size_t> itemInserts;
 		computeIndexDiff<Item, ItemEquals, ItemNeedsUpdate >(sections[sectionUpdates[i]].items, newSections[sectionPostUpdates[i]].items, itemUpdates, itemPostUpdates, itemRemoves, itemInserts);
-		update.insertedRows.resize(itemInserts.size());
-		std::transform(itemInserts.begin(), itemInserts.end(), update.insertedRows.begin(), CreateIndexForSection(sectionPostUpdates[i]));
-		update.deletedRows.resize(itemRemoves.size());
-		std::transform(itemRemoves.begin(), itemRemoves.end(), update.deletedRows.begin(), CreateIndexForSection(sectionPostUpdates[i]));
-		update.updatedRows.resize(itemUpdates.size());
-		std::transform(itemUpdates.begin(), itemUpdates.end(), update.updatedRows.begin(), CreateIndexForSection(sectionPostUpdates[i]));
+		size_t end = update.insertedRows.size();
+		update.insertedRows.resize(update.insertedRows.size() + itemInserts.size());
+		std::transform(itemInserts.begin(), itemInserts.end(), update.insertedRows.begin() + end, CreateIndexForSection(sectionPostUpdates[i]));
+		end = update.deletedRows.size();
+		update.deletedRows.resize(update.deletedRows.size() + itemRemoves.size());
+		std::transform(itemRemoves.begin(), itemRemoves.end(), update.deletedRows.begin() + end, CreateIndexForSection(sectionUpdates[i]));
+		end = update.updatedRows.size();
+		update.updatedRows.resize(update.updatedRows.size() + itemUpdates.size());
+		std::transform(itemUpdates.begin(), itemUpdates.end(), update.updatedRows.begin() + end, CreateIndexForSection(sectionPostUpdates[i]));
 	}
 	
 	// Switch the old model with the new
 	sections.swap(newSections);
 
+	/*
+	std::cerr << "-S: ";
+	for (size_t i = 0; i < update.deletedSections.size(); ++i) {
+		std::cerr << update.deletedSections[i] << " ";
+	}
+	std::cerr << std::endl;
+	std::cerr << "+S: ";
+	for (size_t i = 0; i < update.insertedSections.size(); ++i) {
+		std::cerr << update.insertedSections[i] << " ";
+	}
+	std::cerr << std::endl;
+	std::cerr << "-R: ";
+	for (size_t i = 0; i < update.deletedRows.size(); ++i) {
+		std::cerr << update.deletedRows[i].section << "," << update.deletedRows[i].row << " ";
+	}
+	std::cerr << std::endl;
+	std::cerr << "*R: ";
+	for (size_t i = 0; i < update.updatedRows.size(); ++i) {
+		std::cerr << update.updatedRows[i].section << "," << update.updatedRows[i].row << " ";
+	}
+	std::cerr << std::endl;
+	std::cerr << "+R: ";
+	for (size_t i = 0; i < update.insertedRows.size(); ++i) {
+		std::cerr << update.insertedRows[i].section << "," << update.insertedRows[i].row << " ";
+	}
+	std::cerr << std::endl;
+	*/
+
 	// Emit the update
 	onUpdate(update);
 }
diff --git a/Swift/Controllers/Roster/TableRoster.h b/Swift/Controllers/Roster/TableRoster.h
index 7360d20..a19d592 100644
--- a/Swift/Controllers/Roster/TableRoster.h
+++ b/Swift/Controllers/Roster/TableRoster.h
@@ -11,6 +11,7 @@
 #include <Swiften/Base/boost_bsignals.h>
 
 #include <Swiften/JID/JID.h>
+#include <Swiften/Elements/StatusShow.h>
 
 namespace Swift {
 	class Roster;
@@ -20,11 +21,12 @@ namespace Swift {
 	class TableRoster {
 		public:
 			struct Item {
-				Item(const std::string& name, const std::string& description, const JID& jid) : name(name), description(description), jid(jid) {
+				Item(const std::string& name, const std::string& description, const JID& jid, StatusShow::Type status) : name(name), description(description), jid(jid), status(status) {
 				}
 				std::string name;
 				std::string description;
 				JID jid;
+				StatusShow::Type status;
 			};
 
 			struct Index {
diff --git a/Swift/Controllers/Roster/UnitTest/LeastCommonSubsequenceTest.cpp b/Swift/Controllers/Roster/UnitTest/LeastCommonSubsequenceTest.cpp
index 97b5406..3acab12 100644
--- a/Swift/Controllers/Roster/UnitTest/LeastCommonSubsequenceTest.cpp
+++ b/Swift/Controllers/Roster/UnitTest/LeastCommonSubsequenceTest.cpp
@@ -45,6 +45,7 @@ class LeastCommonSubsequenceTest : public CppUnit::TestFixture {
 		CPPUNIT_TEST(testComputeLeastCommonSubsequenceMatrix_NoCommonSequence);
 		CPPUNIT_TEST(testComputeLeastCommonSubsequenceMatrix_SameSequences);
 		CPPUNIT_TEST(testComputeIndexDiff_1);
+		CPPUNIT_TEST(testComputeIndexDiff_2);
 		CPPUNIT_TEST(testComputeIndexDiff_Sequence1Empty);
 		CPPUNIT_TEST(testComputeIndexDiff_Sequence2Empty);
 		CPPUNIT_TEST(testComputeIndexDiff_BothSequencesEmpty);
@@ -181,6 +182,23 @@ class LeastCommonSubsequenceTest : public CppUnit::TestFixture {
 			CPPUNIT_ASSERT_EQUAL(expectedInserts, inserts);
 		}
 
+		void testComputeIndexDiff_2() {
+			std::vector<char> x = boost::assign::list_of('x')('y');
+			std::vector<char> y = boost::assign::list_of('x');
+
+			std::vector<size_t> updates;
+			std::vector<size_t> postUpdates;
+			std::vector<size_t> removes;
+			std::vector<size_t> inserts;
+			computeIndexDiff<char, std::equal_to<char>, IsBOrC >(x, y, updates, postUpdates, removes, inserts);
+			
+			std::vector<size_t> expectedRemoves = boost::assign::list_of(1);
+			CPPUNIT_ASSERT(updates.empty());
+			CPPUNIT_ASSERT(postUpdates.empty());
+			CPPUNIT_ASSERT(inserts.empty());
+			CPPUNIT_ASSERT_EQUAL(expectedRemoves, removes);
+		}
+
 		void testComputeIndexDiff_Sequence1Empty() {
 			std::vector<char> x;
 			std::vector<char> y = boost::assign::list_of('a')('b')('c');
-- 
cgit v0.10.2-6-g49f6