From 72819f0c95ad3fe264806d3a072fcbfab3131fcf Mon Sep 17 00:00:00 2001
From: Catalin Badea <catalin.badea392@gmail.com>
Date: Wed, 27 Jun 2012 20:53:07 +0300
Subject: Display conversations by using roster selection


diff --git a/Swift/Controllers/Chat/ChatControllerBase.cpp b/Swift/Controllers/Chat/ChatControllerBase.cpp
index 302f793..97b574b 100644
--- a/Swift/Controllers/Chat/ChatControllerBase.cpp
+++ b/Swift/Controllers/Chat/ChatControllerBase.cpp
@@ -145,7 +145,9 @@ void ChatControllerBase::handleSendMessageRequest(const std::string &body, bool
 	onActivity(message->getBody());
 
 	// log message
-	historyController_->addMessage(getBaseJID(), selfJID_, std::string("me"), body, now);
+	if (historyController_) {
+		historyController_->addMessage(getBaseJID(), selfJID_, std::string("me"), body, now);
+	}
 }
 
 void ChatControllerBase::handleSecurityLabelsCatalogResponse(boost::shared_ptr<SecurityLabelsCatalog> catalog, ErrorPayload::ref error) {
@@ -252,7 +254,9 @@ void ChatControllerBase::handleIncomingMessage(boost::shared_ptr<MessageEvent> m
 		}
 		else {
 			lastMessagesUIID_[from] = addMessage(body, senderDisplayNameFromMessage(from), isIncomingMessageFromMe(message), label, std::string(avatarManager_->getAvatarPath(from).string()), timeStamp);
-			historyController_->addMessage(getBaseJID(), from, senderDisplayNameFromMessage(from), body, timeStamp);
+			if (historyController_) {
+				historyController_->addMessage(getBaseJID(), from, senderDisplayNameFromMessage(from), body, timeStamp);
+			}
 		}
 	}
 	chatWindow_->show();
diff --git a/Swift/Controllers/HistoryController.cpp b/Swift/Controllers/HistoryController.cpp
index c82892a..63d4690 100644
--- a/Swift/Controllers/HistoryController.cpp
+++ b/Swift/Controllers/HistoryController.cpp
@@ -24,8 +24,12 @@ void HistoryController::addMessage(const JID& baseJID, const JID& fromJID, const
 	localHistory_->addMessage(message);
 }
 
-std::vector<HistoryMessage> HistoryController::getMessages() const {
-	return localHistory_->getMessages();
+std::vector<HistoryMessage> HistoryController::getMessages(const JID& baseJID) const {
+	return localHistory_->getMessages(baseJID);
+}
+
+std::vector<JID> HistoryController::getAllContacts() const {
+	return localHistory_->getAllContacts();
 }
 
 }
diff --git a/Swift/Controllers/HistoryController.h b/Swift/Controllers/HistoryController.h
index 6ead3f1..0d337f6 100644
--- a/Swift/Controllers/HistoryController.h
+++ b/Swift/Controllers/HistoryController.h
@@ -21,7 +21,8 @@ namespace Swift {
 			~HistoryController();
 
 			void addMessage(const JID& baseJID, const JID& fromJID, const std::string& displayNick, const std::string& messageBody, boost::posix_time::ptime timeStamp);
-			std::vector<HistoryMessage> getMessages() const;
+			std::vector<HistoryMessage> getMessages(const JID& baseJID) const;
+			std::vector<JID> getAllContacts() const;
 
 		private:
 			HistoryManager* localHistory_;
diff --git a/Swift/Controllers/HistoryViewController.cpp b/Swift/Controllers/HistoryViewController.cpp
index 1061e78..5cc25e0 100644
--- a/Swift/Controllers/HistoryViewController.cpp
+++ b/Swift/Controllers/HistoryViewController.cpp
@@ -26,8 +26,11 @@ HistoryViewController::HistoryViewController(
 
 HistoryViewController::~HistoryViewController() {
 	uiEventStream_->onUIEvent.disconnect(boost::bind(&HistoryViewController::handleUIEvent, this, _1));
-	delete historyWindow_;
-	delete roster_;
+	if (historyWindow_) {
+		historyWindow_->onSelectedContactChanged.disconnect(boost::bind(&HistoryViewController::handleSelectedContactChanged, this, _1));
+		delete historyWindow_;
+		delete roster_;
+	}
 }
 
 void HistoryViewController::handleUIEvent(boost::shared_ptr<UIEvent> rawEvent) {
@@ -35,24 +38,34 @@ void HistoryViewController::handleUIEvent(boost::shared_ptr<UIEvent> rawEvent) {
 	if (event != NULL) {
 		if (historyWindow_ == NULL) {
 			historyWindow_ = historyWindowFactory_->createHistoryWindow(uiEventStream_);
+			historyWindow_->onSelectedContactChanged.connect(boost::bind(&HistoryViewController::handleSelectedContactChanged, this, _1));
+
 			roster_ = new Roster(false, true);
 			historyWindow_->setRosterModel(roster_);
 
-			JID putin("vputin@karla.com");
-			JID medvedev("dmedvedev@karla.com");
-			JID kev("kevin@doomsong.co.uk");
-			const std::set<ContactRosterItem::Feature> none;
-			roster_->addContact(putin, putin, "Vladimir Putin", "Recent", "");
-			roster_->addContact(medvedev, medvedev, "Dmitri Medvedev", "Recent", "");
-			roster_->addContact(kev, kev, "Kev", "Recent", "");
+			std::vector<JID> contacts = historyController_->getAllContacts();
+			for (std::vector<JID>::iterator it = contacts.begin(); it != contacts.end(); it++) {
+				roster_->addContact(*it, *it, *it, "Recent", "");
+			}
 		}
 
-		std::vector<HistoryMessage> messages = historyController_->getMessages();
-		for (std::vector<HistoryMessage>::iterator it = messages.begin(); it != messages.end(); it++) {
-			historyWindow_->addMessage(*it);
-		}
 		historyWindow_->activate();
 	}
 }
 
+void HistoryViewController::handleSelectedContactChanged(RosterItem* newContact) {
+	// TODO: check if actually changed
+	// FIXME: signal is triggerd twice.
+	if (newContact == NULL) {
+		return;
+	}
+
+	ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(newContact);
+
+	std::vector<HistoryMessage> messages = historyController_->getMessages(contact->getJID());
+	for (std::vector<HistoryMessage>::iterator it = messages.begin(); it != messages.end(); it++) {
+		historyWindow_->addMessage(*it);
+	}
+}
+
 }
diff --git a/Swift/Controllers/HistoryViewController.h b/Swift/Controllers/HistoryViewController.h
index f64dd35..94e5df3 100644
--- a/Swift/Controllers/HistoryViewController.h
+++ b/Swift/Controllers/HistoryViewController.h
@@ -16,6 +16,7 @@ namespace Swift {
 	class HistoryWindowFactory;
 	class HistoryWindow;
 	class Roster;
+	class RosterItem;
 	class HistoryController;
 
 	class HistoryViewController {
@@ -25,6 +26,7 @@ namespace Swift {
 
 		private:
 			void handleUIEvent(boost::shared_ptr<UIEvent> event);
+			void handleSelectedContactChanged(RosterItem* item);
 
 		private:
 			UIEventStream* uiEventStream_;
diff --git a/Swift/Controllers/UIInterfaces/HistoryWindow.h b/Swift/Controllers/UIInterfaces/HistoryWindow.h
index 9ec79e2..cc3f0b8 100644
--- a/Swift/Controllers/UIInterfaces/HistoryWindow.h
+++ b/Swift/Controllers/UIInterfaces/HistoryWindow.h
@@ -18,5 +18,7 @@ namespace Swift {
 			virtual void activate() = 0;
 			virtual void setRosterModel(Roster*) = 0;
 			virtual void addMessage(const HistoryMessage& message) = 0;
+
+			boost::signal<void (RosterItem*)> onSelectedContactChanged;
 	};
 }
diff --git a/Swift/QtUI/QtHistoryWindow.cpp b/Swift/QtUI/QtHistoryWindow.cpp
index d067190..b3df29f 100644
--- a/Swift/QtUI/QtHistoryWindow.cpp
+++ b/Swift/QtUI/QtHistoryWindow.cpp
@@ -42,6 +42,8 @@ QtHistoryWindow::QtHistoryWindow(SettingsProvider* settings, UIEventStream* even
 	ui_.bottomLeftLayout_->addWidget(conversationRoster_);
 
 	setWindowTitle(tr("History"));
+
+	conversationRoster_->onSomethingSelectedChanged.connect(boost::bind(&QtHistoryWindow::handleSomethingSelectedChanged, this, _1));
 }
 
 QtHistoryWindow::~QtHistoryWindow() {
@@ -72,4 +74,9 @@ void QtHistoryWindow::addMessage(const HistoryMessage& message) {
 	conversation_->addMessage(snippet);
 }
 
+void QtHistoryWindow::handleSomethingSelectedChanged(RosterItem* item) {
+	conversation_->resetView();
+	onSelectedContactChanged(item);
+}
+
 }
diff --git a/Swift/QtUI/QtHistoryWindow.h b/Swift/QtUI/QtHistoryWindow.h
index d522f53..1f0cdb7 100644
--- a/Swift/QtUI/QtHistoryWindow.h
+++ b/Swift/QtUI/QtHistoryWindow.h
@@ -31,6 +31,8 @@ namespace Swift {
 			virtual void closeEvent(QCloseEvent* event);
 			virtual void showEvent(QShowEvent* event);
 
+			void handleSomethingSelectedChanged(RosterItem* item);
+
 			Ui::QtHistoryWindow ui_;
 			QtChatTheme* theme_;
 			QtChatView* conversation_;
diff --git a/Swiften/History/HistoryManager.h b/Swiften/History/HistoryManager.h
index 7a4324b..151f8be 100644
--- a/Swiften/History/HistoryManager.h
+++ b/Swiften/History/HistoryManager.h
@@ -17,6 +17,7 @@ namespace Swift {
 
 			virtual void addMessage(const HistoryMessage& message) = 0;
 
-			virtual std::vector<HistoryMessage> getMessages() const = 0;
+			virtual std::vector<HistoryMessage> getMessages(const JID&) const = 0;
+			virtual std::vector<JID> getAllContacts() const = 0;
 	};
 }
diff --git a/Swiften/History/SQLiteHistoryManager.cpp b/Swiften/History/SQLiteHistoryManager.cpp
index e10de07..33d2c58 100644
--- a/Swiften/History/SQLiteHistoryManager.cpp
+++ b/Swiften/History/SQLiteHistoryManager.cpp
@@ -9,6 +9,7 @@
 
 #include <sqlite3.h>
 #include <Swiften/History/SQLiteHistoryManager.h>
+#include <sstream>
 
 inline std::string getEscapedString(const std::string& s) {
 	std::string result(s);
@@ -36,6 +37,12 @@ SQLiteHistoryManager::SQLiteHistoryManager(const std::string& file) : db_(0) {
 		std::cerr << "SQL Error: " << errorMessage << std::endl;
 		sqlite3_free(errorMessage);
 	}
+
+	result = sqlite3_exec(db_, "CREATE TABLE IF NOT EXISTS conversations('id' INTEGER UNIQUE NOT NULL, 'time' INTEGER)", 0, 0, &errorMessage);
+	if (result != SQLITE_OK) {
+		std::cerr << "SQL Error: " << errorMessage << std::endl;
+		sqlite3_free(errorMessage);
+	}
 }
 
 SQLiteHistoryManager::~SQLiteHistoryManager() {
@@ -43,6 +50,8 @@ SQLiteHistoryManager::~SQLiteHistoryManager() {
 }
 
 void SQLiteHistoryManager::addMessage(const HistoryMessage& message) {
+	updateConversation(message);
+
 	int secondsSinceEpoch = (message.getTime() - boost::posix_time::ptime(boost::gregorian::date(1970, 1, 1))).total_seconds();
 	std::string statement = std::string("INSERT INTO messages('baseID', 'from', 'nick', 'message', 'time') VALUES(") +
 					boost::lexical_cast<std::string>(getIDForJID(message.getBaseJID())) + ", " +
@@ -58,11 +67,18 @@ void SQLiteHistoryManager::addMessage(const HistoryMessage& message) {
 	}
 }
 
-std::vector<HistoryMessage> SQLiteHistoryManager::getMessages() const {
+std::vector<HistoryMessage> SQLiteHistoryManager::getMessages(const JID& baseJID) const {
 	std::vector<HistoryMessage> result;
 	sqlite3_stmt* selectStatement;
-	std::string selectQuery("SELECT messages.'baseID', messages.'from', messages.'nick', messages.'message', messages.'time' FROM messages");
-	int r = sqlite3_prepare(db_, selectQuery.c_str(), selectQuery.size(), &selectStatement, NULL);
+	boost::optional<int> baseID = getIDFromJID(baseJID);
+	if (!baseID) {
+		return std::vector<HistoryMessage>();
+	}
+
+	std::stringstream selectQuery;
+	selectQuery << "SELECT messages.'baseID', messages.'from', messages.'nick', messages.'message', messages.'time' FROM messages WHERE baseID=" << *baseID;
+
+	int r = sqlite3_prepare(db_, selectQuery.str().c_str(), selectQuery.str().size(), &selectStatement, NULL);
 	if (r != SQLITE_OK) {
 		std::cout << "Error: " << sqlite3_errmsg(db_) << std::endl;
 	}
@@ -138,4 +154,48 @@ boost::optional<int> SQLiteHistoryManager::getIDFromJID(const JID& jid) const {
 	return result;
 }
 
+void SQLiteHistoryManager::updateConversation(const HistoryMessage& message) {
+	int id = getIDForJID(message.getBaseJID());
+	int secondsSinceEpoch = (message.getTime() - boost::posix_time::ptime(boost::gregorian::date(1970, 1, 1))).total_seconds(); // this might fail in 2038
+
+	std::stringstream statement;
+	statement << "insert or replace into conversations('id', 'time') VALUES(" <<
+		id <<", " << secondsSinceEpoch << ")";
+
+	char* errorMessage;
+	int result = sqlite3_exec(db_, statement.str().c_str(), 0, 0, &errorMessage);
+
+	if (result != SQLITE_OK) {
+		std::cerr << "SQL Error: " << errorMessage << std::endl;
+		sqlite3_free(errorMessage);
+	}
+}
+
+std::vector<JID> SQLiteHistoryManager::getAllContacts() const {
+	std::string query("SELECT conversations.'id' FROM conversations");
+	sqlite3_stmt* selectStatement;
+
+	int r = sqlite3_prepare(db_, query.c_str(), query.size(), &selectStatement, NULL);
+	if (r != SQLITE_OK) {
+		std::cout << "Error: " << sqlite3_errmsg(db_) << std::endl;
+	}
+
+	r = sqlite3_step(selectStatement);
+	std::vector<JID> result;
+	while (r == SQLITE_ROW) {
+		boost::optional<JID> contactJID(getJIDFromID(sqlite3_column_int(selectStatement, 0)));
+		if (contactJID) {
+			result.push_back(*contactJID);
+		}
+
+		r = sqlite3_step(selectStatement);
+	}
+	if (r != SQLITE_DONE) {
+		std::cout << "Error: " << sqlite3_errmsg(db_) << std::endl;
+	}
+
+	sqlite3_finalize(selectStatement);
+	return result;
+}
+
 }
diff --git a/Swiften/History/SQLiteHistoryManager.h b/Swiften/History/SQLiteHistoryManager.h
index ffd9492..ff82f5e 100644
--- a/Swiften/History/SQLiteHistoryManager.h
+++ b/Swiften/History/SQLiteHistoryManager.h
@@ -18,16 +18,18 @@ namespace Swift {
 			SQLiteHistoryManager(const std::string& file);
 			~SQLiteHistoryManager();
 
-			virtual void addMessage(const HistoryMessage& message);
-			virtual std::vector<HistoryMessage> getMessages() const;
+			void addMessage(const HistoryMessage& message);
+			std::vector<HistoryMessage> getMessages(const JID&) const;
+			std::vector<JID> getAllContacts() const;
 
+		private:
 			int getIDForJID(const JID&);
 			int addJID(const JID&);
+			void updateConversation(const HistoryMessage& message);
 
 			boost::optional<JID> getJIDFromID(int id) const;
 			boost::optional<int> getIDFromJID(const JID& jid) const;
 
-		private:
 			sqlite3* db_;
 	};
 }
-- 
cgit v0.10.2-6-g49f6