From 32672b49d8ec454a3ffc94031bb973c6cfa7f862 Mon Sep 17 00:00:00 2001
From: Catalin Badea <catalin.badea392@gmail.com>
Date: Thu, 19 Jul 2012 12:04:58 +0300
Subject: Retrieve messages from last matching day


diff --git a/Swift/Controllers/HistoryController.cpp b/Swift/Controllers/HistoryController.cpp
index d52e2b2..51891f6 100644
--- a/Swift/Controllers/HistoryController.cpp
+++ b/Swift/Controllers/HistoryController.cpp
@@ -25,11 +25,11 @@ void HistoryController::addMessage(const std::string& message, const JID& fromJI
 	onNewMessage(historyMessage);
 }
 
-std::vector<HistoryMessage> HistoryController::getMessages(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type) const {
-	return localHistory_->getMessages(selfJID, contactJID, type);
+std::vector<HistoryMessage> HistoryController::getMessages(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date) const {
+	return localHistory_->getMessages(selfJID, contactJID, type, date);
 }
 
-std::set<JID> HistoryController::getContacts(const JID& selfJID, HistoryMessage::Type type, const std::string& keyword) const {
+ContactsMap HistoryController::getContacts(const JID& selfJID, HistoryMessage::Type type, const std::string& keyword) const {
 	return localHistory_->getContacts(selfJID, type, keyword);
 }
 
diff --git a/Swift/Controllers/HistoryController.h b/Swift/Controllers/HistoryController.h
index ef832c9..53260a1 100644
--- a/Swift/Controllers/HistoryController.h
+++ b/Swift/Controllers/HistoryController.h
@@ -12,9 +12,9 @@
 #include <set>
 #include <Swiften/Base/boost_bsignals.h>
 #include <Swiften/History/HistoryMessage.h>
+#include <Swiften/History/HistoryManager.h>
 
 namespace Swift {
-	class HistoryManager;
 	class JID;
 
 	class HistoryController {
@@ -23,8 +23,8 @@ namespace Swift {
 			~HistoryController();
 
 			void addMessage(const std::string& message, const JID& fromJID, const JID& toJID, HistoryMessage::Type type, const boost::posix_time::ptime& timeStamp);
-			std::vector<HistoryMessage> getMessages(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type) const;
-			std::set<JID> getContacts(const JID& selfJID, HistoryMessage::Type type, const std::string& keyword = std::string()) const;
+			std::vector<HistoryMessage> getMessages(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date) const;
+			ContactsMap getContacts(const JID& selfJID, HistoryMessage::Type type, const std::string& keyword = std::string()) const;
 
 			boost::signal<void (const HistoryMessage&)> onNewMessage;
 
diff --git a/Swift/Controllers/HistoryViewController.cpp b/Swift/Controllers/HistoryViewController.cpp
index 18e27bd..b7b71cd 100644
--- a/Swift/Controllers/HistoryViewController.cpp
+++ b/Swift/Controllers/HistoryViewController.cpp
@@ -30,7 +30,8 @@ HistoryViewController::HistoryViewController(
 			avatarManager_(avatarManager),
 			historyWindowFactory_(historyWindowFactory),
 			historyWindow_(NULL),
-			selectedItem_(NULL) {
+			selectedItem_(NULL),
+			currentDate_(boost::gregorian::not_a_date_time) {
 	uiEventStream_->onUIEvent.connect(boost::bind(&HistoryViewController::handleUIEvent, this, _1));
 	historyController_->onNewMessage.connect(boost::bind(&HistoryViewController::handleNewMessage, this, _1));
 
@@ -42,6 +43,7 @@ HistoryViewController::~HistoryViewController() {
 	historyController_->onNewMessage.disconnect(boost::bind(&HistoryViewController::handleNewMessage, this, _1));
 	if (historyWindow_) {
 		historyWindow_->onSelectedContactChanged.disconnect(boost::bind(&HistoryViewController::handleSelectedContactChanged, this, _1));
+		historyWindow_->onReturnPressed.disconnect(boost::bind(&HistoryViewController::handleReturnPressed, this, _1));
 		delete historyWindow_;
 	}
 	delete roster_;
@@ -54,37 +56,14 @@ void HistoryViewController::handleUIEvent(boost::shared_ptr<UIEvent> rawEvent) {
 		if (historyWindow_ == NULL) {
 			historyWindow_ = historyWindowFactory_->createHistoryWindow(uiEventStream_);
 			historyWindow_->onSelectedContactChanged.connect(boost::bind(&HistoryViewController::handleSelectedContactChanged, this, _1));
+			historyWindow_->onReturnPressed.connect(boost::bind(&HistoryViewController::handleReturnPressed, this, _1));
 
 			historyWindow_->setRosterModel(roster_);
-
-			// MUCs
-			std::set<JID> rooms = historyController_->getContacts(selfJID_, HistoryMessage::Groupchat);
-			foreach (const JID& room, rooms) {
-				if ( !rooms_.count(room)) {
-					roster_->addContact(room, room, nickResolver_->jidToNick(room), "MUC", avatarManager_->getAvatarPath(room).string());
-					rooms_.insert(room);
-				}
-			}
-
-			// Contacts
-			std::set<JID> contacts = historyController_->getContacts(selfJID_, HistoryMessage::Chat);
-			foreach (const JID& contact, contacts) {
-				if (!contacts_.count(contact)) {
-					roster_->addContact(contact, contact, nickResolver_->jidToNick(contact), "Contacts", avatarManager_->getAvatarPath(contact).string());
-					contacts_.insert(contact);
-				}
-			}
-
-			// MUC contacts
-			std::set<JID> roomPrivateContacts = historyController_->getContacts(selfJID_, HistoryMessage::PrivateMessage);
-			foreach (const JID& contact, roomPrivateContacts) {
-				if ( !roomPrivateContacts_.count(contact)) {
-					roster_->addContact(contact, contact, nickResolver_->jidToNick(contact), "Contacts", avatarManager_->getAvatarPath(contact).string());
-					roomPrivateContacts_.insert(contact);
-				}
-			}
 		}
 
+		// populate roster by doing an empty search
+		handleReturnPressed(std::string());
+
 		historyWindow_->activate();
 	}
 }
@@ -105,13 +84,16 @@ void HistoryViewController::handleSelectedContactChanged(RosterItem* newContact)
 
 	std::vector<HistoryMessage> messages;
 	if (roomPrivateContacts_.count(contactJID)) {
-		messages = historyController_->getMessages(selfJID_, contactJID, HistoryMessage::PrivateMessage);
+		currentDate_ = *roomPrivateContacts_[contactJID].rbegin();
+		messages = historyController_->getMessages(selfJID_, contactJID, HistoryMessage::PrivateMessage, currentDate_);
 	}
 	else if (contacts_.count(contactJID)) {
-		messages = historyController_->getMessages(selfJID_, contactJID, HistoryMessage::Chat);
+		currentDate_ = *contacts_[contactJID].rbegin();
+		messages = historyController_->getMessages(selfJID_, contactJID, HistoryMessage::Chat, currentDate_);
 	}
 	else {
-		messages = historyController_->getMessages(selfJID_, contactJID, HistoryMessage::Groupchat);
+		currentDate_ = *rooms_[contactJID].rbegin();
+		messages = historyController_->getMessages(selfJID_, contactJID, HistoryMessage::Groupchat, currentDate_);
 	}
 
 	foreach (const HistoryMessage& message, messages) {
@@ -137,15 +119,17 @@ void HistoryViewController::handleNewMessage(const HistoryMessage& message) {
 	// add new contact
 	else if (message.getType() == HistoryMessage::Groupchat && !rooms_.count(displayJID)) {
 		roster_->addContact(displayJID, displayJID, nickResolver_->jidToNick(displayJID), "MUC", avatarManager_->getAvatarPath(displayJID).string());
-		rooms_.insert(displayJID);
+		//
+		// TODO add message date here
+		rooms_[displayJID] = std::set<boost::gregorian::date>();
 	}
 	else if (message.getType() == HistoryMessage::Chat && !contacts_.count(displayJID)) {
 		roster_->addContact(displayJID, displayJID, nickResolver_->jidToNick(displayJID), "Contacts", avatarManager_->getAvatarPath(displayJID).string());
-		contacts_.insert(displayJID);
+		contacts_[displayJID] = std::set<boost::gregorian::date>();
 	}
 	else if (message.getType() == HistoryMessage::PrivateMessage && !roomPrivateContacts_.count(displayJID)) {
 		roster_->addContact(displayJID, displayJID, nickResolver_->jidToNick(displayJID), "Contacts", avatarManager_->getAvatarPath(displayJID).string());
-		roomPrivateContacts_.insert(displayJID);
+		roomPrivateContacts_[displayJID] = std::set<boost::gregorian::date>();
 	}
 }
 
@@ -155,4 +139,35 @@ void HistoryViewController::addNewMessage(const HistoryMessage& message) {
 	historyWindow_->addMessage(message.getMessage(), nickResolver_->jidToNick(message.getFromJID()), senderIsSelf, avatarPath, message.getTime());
 }
 
+void HistoryViewController::handleReturnPressed(const std::string& keyword) {
+	roster_->removeAll();
+	rooms_.clear();
+	contacts_.clear();
+	roomPrivateContacts_.clear();
+	selectedItem_ = NULL;
+	historyWindow_->resetConversationView();
+	// TODO set date
+
+	// MUCs
+	rooms_ = historyController_->getContacts(selfJID_, HistoryMessage::Groupchat, keyword);
+	for (ContactsMap::const_iterator room = rooms_.begin(); room != rooms_.end(); room++) {
+		const JID& jid = room->first;
+		roster_->addContact(jid, jid, nickResolver_->jidToNick(jid), "MUC", avatarManager_->getAvatarPath(jid).string());
+	}
+
+	// Contacts
+	contacts_ = historyController_->getContacts(selfJID_, HistoryMessage::Chat, keyword);
+	for (ContactsMap::const_iterator contact = contacts_.begin(); contact != contacts_.end(); contact++) {
+		const JID& jid = contact->first;
+		roster_->addContact(jid, jid, nickResolver_->jidToNick(jid), "Contacts", avatarManager_->getAvatarPath(jid).string());
+	}
+
+	// MUC contacts
+	roomPrivateContacts_ = historyController_->getContacts(selfJID_, HistoryMessage::PrivateMessage, keyword);
+	for (ContactsMap::const_iterator contact = roomPrivateContacts_.begin(); contact != roomPrivateContacts_.end(); contact++) {
+		const JID& jid = contact->first;
+		roster_->addContact(jid, jid, nickResolver_->jidToNick(jid), "Contacts", avatarManager_->getAvatarPath(jid).string());
+	}
+}
+
 }
diff --git a/Swift/Controllers/HistoryViewController.h b/Swift/Controllers/HistoryViewController.h
index 4957e37..cddcfb8 100644
--- a/Swift/Controllers/HistoryViewController.h
+++ b/Swift/Controllers/HistoryViewController.h
@@ -11,6 +11,7 @@
 #include <boost/shared_ptr.hpp>
 
 #include <Swift/Controllers/UIEvents/UIEventStream.h>
+#include <Swiften/History/HistoryManager.h>
 #include <Swiften/JID/JID.h>
 #include <set>
 
@@ -35,6 +36,7 @@ namespace Swift {
 			void handleSelectedContactChanged(RosterItem* item);
 			void handleNewMessage(const HistoryMessage& message);
 			void addNewMessage(const HistoryMessage& message);
+			void handleReturnPressed(const std::string& keyword);
 
 		private:
 			JID selfJID_;
@@ -46,9 +48,10 @@ namespace Swift {
 			HistoryWindow* historyWindow_;
 			Roster* roster_;
 
-			std::set<JID> contacts_;
-			std::set<JID> rooms_;
-			std::set<JID> roomPrivateContacts_;
+			ContactsMap contacts_;
+			ContactsMap rooms_;
+			ContactsMap roomPrivateContacts_;
 			ContactRosterItem* selectedItem_;
+			boost::gregorian::date currentDate_;
 	};
 }
diff --git a/Swift/Controllers/UIInterfaces/HistoryWindow.h b/Swift/Controllers/UIInterfaces/HistoryWindow.h
index cd232f1..d38d6df 100644
--- a/Swift/Controllers/UIInterfaces/HistoryWindow.h
+++ b/Swift/Controllers/UIInterfaces/HistoryWindow.h
@@ -19,5 +19,6 @@ namespace Swift {
 			virtual void resetConversationView() = 0;
 
 			boost::signal<void (RosterItem*)> onSelectedContactChanged;
+			boost::signal<void (const std::string&)> onReturnPressed;
 	};
 }
diff --git a/Swift/QtUI/QtHistoryWindow.cpp b/Swift/QtUI/QtHistoryWindow.cpp
index 51dd1d5..ed91551 100644
--- a/Swift/QtUI/QtHistoryWindow.cpp
+++ b/Swift/QtUI/QtHistoryWindow.cpp
@@ -148,6 +148,7 @@ void QtHistoryWindow::handleScrollReachedBottom() {
 }
 
 void QtHistoryWindow::handleReturnPressed() {
+	onReturnPressed(ui_.searchBox_->lineEdit()->text().toStdString());
 }
 
 void QtHistoryWindow::handleCalendarClicked(const QDate& date) {
diff --git a/Swiften/History/HistoryManager.h b/Swiften/History/HistoryManager.h
index 51039e4..908d35c 100644
--- a/Swiften/History/HistoryManager.h
+++ b/Swiften/History/HistoryManager.h
@@ -7,18 +7,22 @@
 #pragma once
 
 #include <set>
+#include <map>
 #include <vector>
 #include <Swiften/JID/JID.h>
 #include <Swiften/History/HistoryMessage.h>
+#include <boost/date_time/gregorian/gregorian_types.hpp>
 
 namespace Swift {
+	typedef std::map<JID, std::set<boost::gregorian::date> > ContactsMap;
+
 	class HistoryManager {
 		public:
 			virtual ~HistoryManager();
 
 			virtual void addMessage(const HistoryMessage& message) = 0;
 
-			virtual std::vector<HistoryMessage> getMessages(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type) const = 0;
-			virtual std::set<JID> getContacts(const JID& selfJID, HistoryMessage::Type type, const std::string& keyword) const = 0;
+			virtual std::vector<HistoryMessage> getMessages(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date) const = 0;
+			virtual ContactsMap getContacts(const JID& selfJID, HistoryMessage::Type type, const std::string& keyword) const = 0;
 	};
 }
diff --git a/Swiften/History/SQLiteHistoryManager.cpp b/Swiften/History/SQLiteHistoryManager.cpp
index 0a14b99..7cddf43 100644
--- a/Swiften/History/SQLiteHistoryManager.cpp
+++ b/Swiften/History/SQLiteHistoryManager.cpp
@@ -9,6 +9,7 @@
 
 #include <sqlite3.h>
 #include <Swiften/History/SQLiteHistoryManager.h>
+#include <boost/date_time/gregorian/gregorian_types.hpp>
 
 inline std::string getEscapedString(const std::string& s) {
 	std::string result(s);
@@ -66,7 +67,7 @@ void SQLiteHistoryManager::addMessage(const HistoryMessage& message) {
 	}
 }
 
-std::vector<HistoryMessage> SQLiteHistoryManager::getMessages(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type) const {
+std::vector<HistoryMessage> SQLiteHistoryManager::getMessages(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date) const {
 	sqlite3_stmt* selectStatement;
 
 	boost::optional<int> selfID = getIDFromJID(selfJID.toBare());
@@ -77,12 +78,12 @@ std::vector<HistoryMessage> SQLiteHistoryManager::getMessages(const JID& selfJID
 		return std::vector<HistoryMessage>();
 	}
 
-	std::string selectQuery = "SELECT * FROM messages WHERE type=" + boost::lexical_cast<std::string>(type);
+	std::string selectQuery = "SELECT * FROM messages WHERE (type=" + boost::lexical_cast<std::string>(type);
 	if (contactJID.isBare()) {
 		// match only bare jid
 		selectQuery += " AND ((fromBare=" + boost::lexical_cast<std::string>(*selfID) + " AND toBare=" +
 				boost::lexical_cast<std::string>(*contactID) + ") OR (fromBare=" +
-				boost::lexical_cast<std::string>(*contactID) + " AND toBare=" + boost::lexical_cast<std::string>(*selfID) + "))";
+				boost::lexical_cast<std::string>(*contactID) + " AND toBare=" + boost::lexical_cast<std::string>(*selfID) + ")))";
 	}
 	else {
 		// match resource too
@@ -91,7 +92,15 @@ std::vector<HistoryMessage> SQLiteHistoryManager::getMessages(const JID& selfJID
 				getEscapedString(contactJID.getResource()) + "')) OR ((fromBare=" +
 				boost::lexical_cast<std::string>(*contactID) + " AND fromResource='" +
 				getEscapedString(contactJID.getResource()) + "') AND toBare=" +
-				boost::lexical_cast<std::string>(*selfID) + "))";
+				boost::lexical_cast<std::string>(*selfID) + ")))";
+	}
+
+	if (!date.is_not_a_date()) {
+		int lowerBound = (boost::posix_time::ptime(date) - boost::posix_time::ptime(boost::gregorian::date(1970, 1, 1))).total_seconds();
+		int upperBound = lowerBound + 86400;
+
+		selectQuery += " AND (time>=" + boost::lexical_cast<std::string>(lowerBound) +
+				" AND time<" + boost::lexical_cast<std::string>(upperBound) + ")";
 	}
 
 	int r = sqlite3_prepare(db_, selectQuery.c_str(), selectQuery.size(), &selectStatement, NULL);
@@ -190,8 +199,8 @@ boost::optional<int> SQLiteHistoryManager::getIDFromJID(const JID& jid) const {
 	return result;
 }
 
-std::set<JID> SQLiteHistoryManager::getContacts(const JID& selfJID, HistoryMessage::Type type, const std::string& keyword) const {
-	std::set<JID> result;
+ContactsMap SQLiteHistoryManager::getContacts(const JID& selfJID, HistoryMessage::Type type, const std::string& keyword) const {
+	ContactsMap result;
 	sqlite3_stmt* selectStatement;
 
 	// get id
@@ -201,9 +210,15 @@ std::set<JID> SQLiteHistoryManager::getContacts(const JID& selfJID, HistoryMessa
 	}
 
 	// get contacts
-	std::string query = "SELECT DISTINCT messages.'fromBare', messages.'fromResource', messages.'toBare', messages.'toResource' FROM messages WHERE type="
+	std::string query = "SELECT DISTINCT messages.'fromBare', messages.'fromResource', messages.'toBare', messages.'toResource', messages.'time' "
+		"FROM messages WHERE (type="
 		+ boost::lexical_cast<std::string>(type) + " AND (toBare="
-		+ boost::lexical_cast<std::string>(*id) + " OR fromBare=" + boost::lexical_cast<std::string>(*id) + ")";
+		+ boost::lexical_cast<std::string>(*id) + " OR fromBare=" + boost::lexical_cast<std::string>(*id) + "))";
+
+	// match keyword
+	if (getEscapedString(keyword).length()) {
+		query += " AND message LIKE '%" + getEscapedString(keyword) + "%'";
+	}
 
 	int r = sqlite3_prepare(db_, query.c_str(), query.size(), &selectStatement, NULL);
 	if (r != SQLITE_OK) {
@@ -218,6 +233,9 @@ std::set<JID> SQLiteHistoryManager::getContacts(const JID& selfJID, HistoryMessa
 		std::string toResource(reinterpret_cast<const char*>(sqlite3_column_text(selectStatement, 3)));
 		std::string resource;
 
+		int secondsSinceEpoch(sqlite3_column_int(selectStatement, 4));
+		boost::posix_time::ptime time(boost::gregorian::date(1970, 1, 1), boost::posix_time::seconds(secondsSinceEpoch));
+
 		boost::optional<JID> contactJID;
 
 		if (fromBareID == *id) {
@@ -235,7 +253,7 @@ std::set<JID> SQLiteHistoryManager::getContacts(const JID& selfJID, HistoryMessa
 		}
 
 		if (contactJID) {
-			result.insert(*contactJID);
+			result[*contactJID].insert(time.date());
 		}
 
 		r = sqlite3_step(selectStatement);
diff --git a/Swiften/History/SQLiteHistoryManager.h b/Swiften/History/SQLiteHistoryManager.h
index a02ecc3..638d73f 100644
--- a/Swiften/History/SQLiteHistoryManager.h
+++ b/Swiften/History/SQLiteHistoryManager.h
@@ -19,8 +19,8 @@ namespace Swift {
 			~SQLiteHistoryManager();
 
 			void addMessage(const HistoryMessage& message);
-			std::vector<HistoryMessage> getMessages(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type) const;
-			std::set<JID> getContacts(const JID& selfJID, HistoryMessage::Type type, const std::string& keyword) const;
+			ContactsMap getContacts(const JID& selfJID, HistoryMessage::Type type, const std::string& keyword) const;
+			std::vector<HistoryMessage> getMessages(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date) const;
 
 		private:
 			int getIDForJID(const JID&);
-- 
cgit v0.10.2-6-g49f6