From e66d257f786f034a7372780c7933312fe8b66dff Mon Sep 17 00:00:00 2001
From: Kevin Smith <git@kismith.co.uk>
Date: Fri, 22 Apr 2011 19:37:42 +0100
Subject: Merge unread tab titles legibly.

Release-Notes: Chat tabs with unread messages from several chats will now be a little more descriptive.

Resolves: #485

diff --git a/.gitignore b/.gitignore
index 7c78bc1..b5a8577 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,6 +21,7 @@
 *.ilk
 *.res
 *.moc
+*.patch
 *~
 _CL_*
 *.manifest
diff --git a/SwifTools/UnitTest/SConscript b/SwifTools/UnitTest/SConscript
index e41da64..e469deb 100644
--- a/SwifTools/UnitTest/SConscript
+++ b/SwifTools/UnitTest/SConscript
@@ -3,5 +3,5 @@ Import("env")
 env.Append(UNITTEST_SOURCES = [
 		File("LinkifyTest.cpp"),
 		File("TabCompleteTest.cpp"),
-		File("LastLineTrackerTest.cpp")
+		File("LastLineTrackerTest.cpp"),
 	])
diff --git a/Swift/Controllers/ChatMessageSummarizer.cpp b/Swift/Controllers/ChatMessageSummarizer.cpp
new file mode 100644
index 0000000..682d88b
--- /dev/null
+++ b/Swift/Controllers/ChatMessageSummarizer.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2011 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swift/Controllers/ChatMessageSummarizer.h>
+
+#include <Swiften/Base/format.h>
+#include <Swift/Controllers/Intl.h>
+#include <Swiften/Base/foreach.h>
+
+using namespace Swift;
+using namespace std;
+
+string ChatMessageSummarizer::getSummary(const string& current, const vector<UnreadPair>& unreads) {
+	vector<UnreadPair> others;
+	int currentUnread = 0;
+	int otherCount = 0;
+	foreach (UnreadPair unread, unreads) {
+		if (unread.first == current) {
+			currentUnread += unread.second;
+		} else {
+			if (unread.second > 0) {
+				otherCount += unread.second;
+				others.push_back(unread);
+			}
+		}
+	}
+	string myString(current);
+
+	if (currentUnread > 0) {
+		string result(QT_TRANSLATE_NOOP("", "%1% (%2%)"));
+		myString = str(format(result) % current % currentUnread);
+	}
+
+	if (others.size() > 1) {
+		string result(QT_TRANSLATE_NOOP("", "%1% and %2% others (%3%)"));
+		myString = str(format(result) % myString % others.size() % otherCount);
+	} else if (others.size() > 0) {
+		string result(QT_TRANSLATE_NOOP("", "%1%, %2% (%3%)"));
+		myString = str(format(result) % myString % others[0].first % otherCount);
+	}
+	return myString;
+}
diff --git a/Swift/Controllers/ChatMessageSummarizer.h b/Swift/Controllers/ChatMessageSummarizer.h
new file mode 100644
index 0000000..d4ff188
--- /dev/null
+++ b/Swift/Controllers/ChatMessageSummarizer.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2011 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <vector>
+#include <utility>
+#include <string>
+
+namespace Swift {
+typedef std::pair<std::string, int> UnreadPair;
+
+	class ChatMessageSummarizer {
+		public:
+			std::string getSummary(const std::string& current, const std::vector<UnreadPair>& unreads);
+	};
+}
diff --git a/Swift/Controllers/SConscript b/Swift/Controllers/SConscript
index c523419..eb5d21f 100644
--- a/Swift/Controllers/SConscript
+++ b/Swift/Controllers/SConscript
@@ -54,7 +54,8 @@ if env["SCONS_STAGE"] == "build" :
 			"CertificateFileStorage.cpp",
 			"StatusUtil.cpp",
 			"Translator.cpp",
-			"XMPPURIController.cpp",	
+			"XMPPURIController.cpp",
+			"ChatMessageSummarizer.cpp",
 		])
 
 	env.Append(UNITTEST_SOURCES = [
@@ -65,4 +66,5 @@ if env["SCONS_STAGE"] == "build" :
 			File("Chat/UnitTest/ChatsManagerTest.cpp"),
 			File("Chat/UnitTest/MUCControllerTest.cpp"),
 			File("UnitTest/MockChatWindow.cpp"),
+			File("UnitTest/ChatMessageSummarizerTest.cpp"),
 		])
diff --git a/Swift/Controllers/UnitTest/ChatMessageSummarizerTest.cpp b/Swift/Controllers/UnitTest/ChatMessageSummarizerTest.cpp
new file mode 100644
index 0000000..ee0ee9f
--- /dev/null
+++ b/Swift/Controllers/UnitTest/ChatMessageSummarizerTest.cpp
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2011 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+
+#include "Swift/Controllers/ChatMessageSummarizer.h"
+
+using namespace Swift;
+using namespace std;
+
+class ChatMessageSummarizerTest : public CppUnit::TestFixture {
+	CPPUNIT_TEST_SUITE(ChatMessageSummarizerTest);
+	CPPUNIT_TEST(testEmpty);
+	CPPUNIT_TEST(testCurrentNone);
+	CPPUNIT_TEST(testCurrentCount);
+	CPPUNIT_TEST(testCurrentCountOthersNone);
+	CPPUNIT_TEST(testCurrentCountOtherCount);
+	CPPUNIT_TEST(testCurrentNoneOtherCount);
+	CPPUNIT_TEST(testCurrentCountOthersCount);
+	CPPUNIT_TEST(testCurrentNoneOthersCount);
+	CPPUNIT_TEST(testCurrentCountSomeOthersCount);
+	CPPUNIT_TEST_SUITE_END();
+
+public:
+	ChatMessageSummarizerTest() {};
+
+	void setUp() {
+
+	}
+
+	void testEmpty() {
+		string current("");
+		vector<UnreadPair> unreads;
+		ChatMessageSummarizer summary;
+		CPPUNIT_ASSERT_EQUAL(current, summary.getSummary(current, unreads));
+	}
+
+	void testCurrentNone() {
+		string current("Bob");
+		vector<UnreadPair> unreads;
+		unreads.push_back(UnreadPair("Bob", 0));
+		ChatMessageSummarizer summary;
+		CPPUNIT_ASSERT_EQUAL(current, summary.getSummary(current, unreads));
+	}
+
+	void testCurrentCount() {
+		string current("Bob");
+		vector<UnreadPair> unreads;
+		unreads.push_back(UnreadPair("Bob", 3));
+		ChatMessageSummarizer summary;
+		CPPUNIT_ASSERT_EQUAL(string("Bob (3)"), summary.getSummary(current, unreads));
+	}
+
+	void testCurrentCountOthersNone() {
+		string current("Bob");
+		vector<UnreadPair> unreads;
+		unreads.push_back(UnreadPair("Bert", 0));
+		unreads.push_back(UnreadPair("Bob", 3));
+		unreads.push_back(UnreadPair("Betty", 0));
+		ChatMessageSummarizer summary;
+		CPPUNIT_ASSERT_EQUAL(string("Bob (3)"), summary.getSummary(current, unreads));
+	}
+
+	void testCurrentCountOtherCount() {
+		string current("Bob");
+		vector<UnreadPair> unreads;
+		unreads.push_back(UnreadPair("Bert", 0));
+		unreads.push_back(UnreadPair("Bob", 3));
+		unreads.push_back(UnreadPair("Betty", 7));
+		ChatMessageSummarizer summary;
+		CPPUNIT_ASSERT_EQUAL(string("Bob (3), Betty (7)"), summary.getSummary(current, unreads));
+	}
+
+	void testCurrentNoneOtherCount() {
+		string current("Bob");
+		vector<UnreadPair> unreads;
+		unreads.push_back(UnreadPair("Bert", 0));
+		unreads.push_back(UnreadPair("Bob", 0));
+		unreads.push_back(UnreadPair("Betty", 7));
+		ChatMessageSummarizer summary;
+		CPPUNIT_ASSERT_EQUAL(string("Bob, Betty (7)"), summary.getSummary(current, unreads));
+	}
+
+	void testCurrentNoneOthersCount() {
+		string current("Bob");
+		vector<UnreadPair> unreads;
+		unreads.push_back(UnreadPair("Bert", 2));
+		unreads.push_back(UnreadPair("Bob", 0));
+		unreads.push_back(UnreadPair("Betty", 7));
+		ChatMessageSummarizer summary;
+		CPPUNIT_ASSERT_EQUAL(string("Bob and 2 others (9)"), summary.getSummary(current, unreads));
+	}
+
+	void testCurrentCountOthersCount() {
+		string current("Bob");
+		vector<UnreadPair> unreads;
+		unreads.push_back(UnreadPair("Bert", 2));
+		unreads.push_back(UnreadPair("Bob", 11));
+		unreads.push_back(UnreadPair("Betty", 7));
+		ChatMessageSummarizer summary;
+		CPPUNIT_ASSERT_EQUAL(string("Bob (11) and 2 others (9)"), summary.getSummary(current, unreads));
+	}
+
+	void testCurrentCountSomeOthersCount() {
+		string current("Bob");
+		vector<UnreadPair> unreads;
+		unreads.push_back(UnreadPair("Bert", 2));
+		unreads.push_back(UnreadPair("Beverly", 0));
+		unreads.push_back(UnreadPair("Bob", 11));
+		unreads.push_back(UnreadPair("Beatrice", 0));
+		unreads.push_back(UnreadPair("Betty", 7));
+		ChatMessageSummarizer summary;
+		CPPUNIT_ASSERT_EQUAL(string("Bob (11) and 2 others (9)"), summary.getSummary(current, unreads));
+	}
+
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(ChatMessageSummarizerTest);
diff --git a/Swift/QtUI/QtChatTabs.cpp b/Swift/QtUI/QtChatTabs.cpp
index 25c7ca2..249080b 100644
--- a/Swift/QtUI/QtChatTabs.cpp
+++ b/Swift/QtUI/QtChatTabs.cpp
@@ -7,6 +7,10 @@
 #include "QtChatTabs.h"
 
 #include <algorithm>
+#include <vector>
+
+#include <Swift/Controllers/ChatMessageSummarizer.h>
+#include <Swift/QtUI/QtSwiftUtil.h>
 
 #include <QCloseEvent>
 #include <QDesktopWidget>
@@ -236,16 +240,18 @@ void QtChatTabs::handleTabTitleUpdated(QWidget* widget) {
 	default : tabTextColor = QColor();
 	}
 	tabs_->tabBar()->setTabTextColor(index, tabTextColor);
-	int unread = 0;
+
+	std::vector<std::pair<std::string, int> > unreads;
 	for (int i = 0; i < tabs_->count(); i++) {
 		QtTabbable* tab = qobject_cast<QtTabbable*>(tabs_->widget(i));
 		if (tab) {
-			unread += tab->getCount();
+			unreads.push_back(std::pair<std::string, int>(Q2PSTRING(tab->windowTitle()), tab->getCount()));
 		}
 	}
 
-	QtTabbable* current = qobject_cast<QtTabbable*>(tabs_->currentWidget());
-	setWindowTitle(unread > 0 ? QString("(%1) %2").arg(unread).arg(current->windowTitle()) : current->windowTitle());
+	std::string current(Q2PSTRING(qobject_cast<QtTabbable*>(tabs_->currentWidget())->windowTitle()));
+	ChatMessageSummarizer summary;
+	setWindowTitle(summary.getSummary(current, unreads).c_str());
 }
 
 void QtChatTabs::flash() {
-- 
cgit v0.10.2-6-g49f6