From 9ccedec3844df80241c65dc6fb24d97efc2f41fc Mon Sep 17 00:00:00 2001 From: Catalin Badea Date: Fri, 20 Jul 2012 15:22:40 +0300 Subject: continous scroll between dates. diff --git a/Swift/Controllers/HistoryController.cpp b/Swift/Controllers/HistoryController.cpp index 51891f6..deda25b 100644 --- a/Swift/Controllers/HistoryController.cpp +++ b/Swift/Controllers/HistoryController.cpp @@ -25,8 +25,16 @@ void HistoryController::addMessage(const std::string& message, const JID& fromJI onNewMessage(historyMessage); } -std::vector 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::vector HistoryController::getMessagesFromDate(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date) const { + return localHistory_->getMessagesFromDate(selfJID, contactJID, type, date); +} + +std::vector HistoryController::getMessagesFromPreviousDate(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date) const { + return localHistory_->getMessagesFromPreviousDate(selfJID, contactJID, type, date); +} + +std::vector HistoryController::getMessagesFromNextDate(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date) const { + return localHistory_->getMessagesFromNextDate(selfJID, contactJID, type, date); } ContactsMap HistoryController::getContacts(const JID& selfJID, HistoryMessage::Type type, const std::string& keyword) const { diff --git a/Swift/Controllers/HistoryController.h b/Swift/Controllers/HistoryController.h index 53260a1..00ad752 100644 --- a/Swift/Controllers/HistoryController.h +++ b/Swift/Controllers/HistoryController.h @@ -23,7 +23,9 @@ 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 getMessages(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date) const; + std::vector getMessagesFromDate(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date) const; + std::vector getMessagesFromPreviousDate(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date) const; + std::vector getMessagesFromNextDate(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 onNewMessage; diff --git a/Swift/Controllers/HistoryViewController.cpp b/Swift/Controllers/HistoryViewController.cpp index b7b71cd..8efdc99 100644 --- a/Swift/Controllers/HistoryViewController.cpp +++ b/Swift/Controllers/HistoryViewController.cpp @@ -31,7 +31,7 @@ HistoryViewController::HistoryViewController( historyWindowFactory_(historyWindowFactory), historyWindow_(NULL), selectedItem_(NULL), - currentDate_(boost::gregorian::not_a_date_time) { + currentResultDate_(boost::gregorian::not_a_date_time) { uiEventStream_->onUIEvent.connect(boost::bind(&HistoryViewController::handleUIEvent, this, _1)); historyController_->onNewMessage.connect(boost::bind(&HistoryViewController::handleNewMessage, this, _1)); @@ -44,6 +44,8 @@ HistoryViewController::~HistoryViewController() { if (historyWindow_) { historyWindow_->onSelectedContactChanged.disconnect(boost::bind(&HistoryViewController::handleSelectedContactChanged, this, _1)); historyWindow_->onReturnPressed.disconnect(boost::bind(&HistoryViewController::handleReturnPressed, this, _1)); + historyWindow_->onScrollReachedTop.disconnect(boost::bind(&HistoryViewController::handleScrollReachedTop, this, _1)); + historyWindow_->onScrollReachedBottom.disconnect(boost::bind(&HistoryViewController::handleScrollReachedBottom, this, _1)); delete historyWindow_; } delete roster_; @@ -57,6 +59,8 @@ void HistoryViewController::handleUIEvent(boost::shared_ptr rawEvent) { historyWindow_ = historyWindowFactory_->createHistoryWindow(uiEventStream_); historyWindow_->onSelectedContactChanged.connect(boost::bind(&HistoryViewController::handleSelectedContactChanged, this, _1)); historyWindow_->onReturnPressed.connect(boost::bind(&HistoryViewController::handleReturnPressed, this, _1)); + historyWindow_->onScrollReachedTop.connect(boost::bind(&HistoryViewController::handleScrollReachedTop, this, _1)); + historyWindow_->onScrollReachedBottom.connect(boost::bind(&HistoryViewController::handleScrollReachedBottom, this, _1)); historyWindow_->setRosterModel(roster_); } @@ -84,20 +88,23 @@ void HistoryViewController::handleSelectedContactChanged(RosterItem* newContact) std::vector messages; if (roomPrivateContacts_.count(contactJID)) { - currentDate_ = *roomPrivateContacts_[contactJID].rbegin(); - messages = historyController_->getMessages(selfJID_, contactJID, HistoryMessage::PrivateMessage, currentDate_); + currentResultDate_ = *roomPrivateContacts_[contactJID].rbegin(); + messages = historyController_->getMessagesFromDate(selfJID_, contactJID, HistoryMessage::PrivateMessage, currentResultDate_); + currentItemType_ = HistoryMessage::PrivateMessage; } else if (contacts_.count(contactJID)) { - currentDate_ = *contacts_[contactJID].rbegin(); - messages = historyController_->getMessages(selfJID_, contactJID, HistoryMessage::Chat, currentDate_); + currentResultDate_ = *contacts_[contactJID].rbegin(); + messages = historyController_->getMessagesFromDate(selfJID_, contactJID, HistoryMessage::Chat, currentResultDate_); + currentItemType_ = HistoryMessage::Chat; } else { - currentDate_ = *rooms_[contactJID].rbegin(); - messages = historyController_->getMessages(selfJID_, contactJID, HistoryMessage::Groupchat, currentDate_); + currentResultDate_ = *rooms_[contactJID].rbegin(); + messages = historyController_->getMessagesFromDate(selfJID_, contactJID, HistoryMessage::Groupchat, currentResultDate_); + currentItemType_ = HistoryMessage::Groupchat; } foreach (const HistoryMessage& message, messages) { - addNewMessage(message); + addNewMessage(message, false); } } @@ -114,7 +121,7 @@ void HistoryViewController::handleNewMessage(const HistoryMessage& message) { // check current conversation if (selectedItem_ && selectedItem_->getJID() == displayJID) { - addNewMessage(message); + addNewMessage(message, false); } // add new contact else if (message.getType() == HistoryMessage::Groupchat && !rooms_.count(displayJID)) { @@ -133,10 +140,10 @@ void HistoryViewController::handleNewMessage(const HistoryMessage& message) { } } -void HistoryViewController::addNewMessage(const HistoryMessage& message) { +void HistoryViewController::addNewMessage(const HistoryMessage& message, bool addAtTheTop) { bool senderIsSelf = message.getFromJID().toBare() == selfJID_; std::string avatarPath = avatarManager_->getAvatarPath(message.getFromJID()).string(); - historyWindow_->addMessage(message.getMessage(), nickResolver_->jidToNick(message.getFromJID()), senderIsSelf, avatarPath, message.getTime()); + historyWindow_->addMessage(message.getMessage(), nickResolver_->jidToNick(message.getFromJID()), senderIsSelf, avatarPath, message.getTime(), addAtTheTop); } void HistoryViewController::handleReturnPressed(const std::string& keyword) { @@ -146,7 +153,6 @@ void HistoryViewController::handleReturnPressed(const std::string& keyword) { roomPrivateContacts_.clear(); selectedItem_ = NULL; historyWindow_->resetConversationView(); - // TODO set date // MUCs rooms_ = historyController_->getContacts(selfJID_, HistoryMessage::Groupchat, keyword); @@ -170,4 +176,20 @@ void HistoryViewController::handleReturnPressed(const std::string& keyword) { } } +void HistoryViewController::handleScrollReachedTop(const boost::gregorian::date& date) { + std::vector messages = historyController_->getMessagesFromPreviousDate(selfJID_, selectedItem_->getJID(), currentItemType_, date); + + reverse_foreach (const HistoryMessage& message, messages) { + addNewMessage(message, true); + } +} + +void HistoryViewController::handleScrollReachedBottom(const boost::gregorian::date& date) { + std::vector messages = historyController_->getMessagesFromNextDate(selfJID_, selectedItem_->getJID(), currentItemType_, date); + + foreach (const HistoryMessage& message, messages) { + addNewMessage(message, true); + } +} + } diff --git a/Swift/Controllers/HistoryViewController.h b/Swift/Controllers/HistoryViewController.h index cddcfb8..5c4dc96 100644 --- a/Swift/Controllers/HistoryViewController.h +++ b/Swift/Controllers/HistoryViewController.h @@ -35,8 +35,10 @@ namespace Swift { void handleUIEvent(boost::shared_ptr event); void handleSelectedContactChanged(RosterItem* item); void handleNewMessage(const HistoryMessage& message); - void addNewMessage(const HistoryMessage& message); + void addNewMessage(const HistoryMessage& message, bool addAtTheTop); void handleReturnPressed(const std::string& keyword); + void handleScrollReachedTop(const boost::gregorian::date& date); + void handleScrollReachedBottom(const boost::gregorian::date& date); private: JID selfJID_; @@ -52,6 +54,7 @@ namespace Swift { ContactsMap rooms_; ContactsMap roomPrivateContacts_; ContactRosterItem* selectedItem_; - boost::gregorian::date currentDate_; + HistoryMessage::Type currentItemType_; + boost::gregorian::date currentResultDate_; }; } diff --git a/Swift/Controllers/UIInterfaces/HistoryWindow.h b/Swift/Controllers/UIInterfaces/HistoryWindow.h index d38d6df..effff27 100644 --- a/Swift/Controllers/UIInterfaces/HistoryWindow.h +++ b/Swift/Controllers/UIInterfaces/HistoryWindow.h @@ -15,10 +15,12 @@ namespace Swift { virtual void activate() = 0; virtual void setRosterModel(Roster*) = 0; - virtual void addMessage(const std::string &message, const std::string &senderName, bool senderIsSelf, const std::string& avatarPath, const boost::posix_time::ptime& time) = 0; + virtual void addMessage(const std::string &message, const std::string &senderName, bool senderIsSelf, const std::string& avatarPath, const boost::posix_time::ptime& time, bool addAtTheTop) = 0; virtual void resetConversationView() = 0; boost::signal onSelectedContactChanged; boost::signal onReturnPressed; + boost::signal onScrollReachedTop; + boost::signal onScrollReachedBottom; }; } diff --git a/Swift/QtUI/QtHistoryWindow.cpp b/Swift/QtUI/QtHistoryWindow.cpp index ed91551..feec059 100644 --- a/Swift/QtUI/QtHistoryWindow.cpp +++ b/Swift/QtUI/QtHistoryWindow.cpp @@ -23,6 +23,7 @@ #include #include +#include namespace Swift { @@ -92,7 +93,7 @@ void QtHistoryWindow::setRosterModel(Roster* model) { conversationRoster_->setRosterModel(model); } -void QtHistoryWindow::addMessage(const std::string &message, const std::string &senderName, bool senderIsSelf, const std::string& avatarPath, const boost::posix_time::ptime& time) { +void QtHistoryWindow::addMessage(const std::string &message, const std::string &senderName, bool senderIsSelf, const std::string& avatarPath, const boost::posix_time::ptime& time, bool addAtTheTop) { QString scaledAvatarPath = QtScaledAvatarCache(32).getScaledAvatarPath(avatarPath.c_str()); QString messageHTML(P2QSTRING(message)); @@ -104,7 +105,12 @@ void QtHistoryWindow::addMessage(const std::string &message, const std::string & QString qAvatarPath = scaledAvatarPath.isEmpty() ? "qrc:/icons/avatar.png" : QUrl::fromLocalFile(scaledAvatarPath).toEncoded(); - conversation_->addMessageBottom(boost::shared_ptr(new MessageSnippet(messageHTML, Qt::escape(P2QSTRING(senderName)), qTime, qAvatarPath, senderIsSelf, false, theme_, P2QSTRING(id)))); + if (addAtTheTop) { + conversation_->addMessageTop(boost::shared_ptr(new MessageSnippet(messageHTML, Qt::escape(P2QSTRING(senderName)), qTime, qAvatarPath, senderIsSelf, false, theme_, P2QSTRING(id)))); + } + else { + conversation_->addMessageBottom(boost::shared_ptr(new MessageSnippet(messageHTML, Qt::escape(P2QSTRING(senderName)), qTime, qAvatarPath, senderIsSelf, false, theme_, P2QSTRING(id)))); + } // keep track of the days viewable in the chatView if (!dates_.count(date)) { @@ -135,16 +141,21 @@ void QtHistoryWindow::handleScrollRequested(int pos) { } } - if (currentDate_ != currentDate) { - currentDate_ = currentDate; - ui_.calendarWidget_->setSelectedDate(currentDate_); + if (ui_.calendarWidget_->selectedDate() != currentDate) { + ui_.calendarWidget_->setSelectedDate(currentDate); } } void QtHistoryWindow::handleScrollReachedTop() { + int year, month, day; + ui_.calendarWidget_->selectedDate().getDate(&year, &month, &day); + onScrollReachedTop(boost::gregorian::date(year, month, day)); } void QtHistoryWindow::handleScrollReachedBottom() { + int year, month, day; + ui_.calendarWidget_->selectedDate().getDate(&year, &month, &day); + onScrollReachedBottom(boost::gregorian::date(year, month, day)); } void QtHistoryWindow::handleReturnPressed() { diff --git a/Swift/QtUI/QtHistoryWindow.h b/Swift/QtUI/QtHistoryWindow.h index 9a887bf..97b9866 100644 --- a/Swift/QtUI/QtHistoryWindow.h +++ b/Swift/QtUI/QtHistoryWindow.h @@ -23,7 +23,7 @@ namespace Swift { ~QtHistoryWindow(); void activate(); void setRosterModel(Roster*); - void addMessage(const std::string &message, const std::string &senderName, bool senderIsSelf, const std::string& avatarPath, const boost::posix_time::ptime& time); + void addMessage(const std::string &message, const std::string &senderName, bool senderIsSelf, const std::string& avatarPath, const boost::posix_time::ptime& time, bool addAtTheTop); void resetConversationView(); void closeEvent(QCloseEvent* event); @@ -44,7 +44,6 @@ namespace Swift { QtChatView* conversation_; QtTreeWidget* conversationRoster_; std::set dates_; - QDate currentDate_; int idCounter_; }; } diff --git a/Swiften/Base/foreach.h b/Swiften/Base/foreach.h index 87f6147..3ad506d 100644 --- a/Swiften/Base/foreach.h +++ b/Swiften/Base/foreach.h @@ -10,3 +10,4 @@ #undef foreach #define foreach BOOST_FOREACH +#define reverse_foreach BOOST_REVERSE_FOREACH diff --git a/Swiften/History/HistoryManager.h b/Swiften/History/HistoryManager.h index 908d35c..6b32206 100644 --- a/Swiften/History/HistoryManager.h +++ b/Swiften/History/HistoryManager.h @@ -22,7 +22,9 @@ namespace Swift { virtual void addMessage(const HistoryMessage& message) = 0; - virtual std::vector getMessages(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date) const = 0; + virtual std::vector getMessagesFromDate(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date) const = 0; + virtual std::vector getMessagesFromNextDate(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date) const = 0; + virtual std::vector getMessagesFromPreviousDate(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 7cddf43..57fce2f 100644 --- a/Swiften/History/SQLiteHistoryManager.cpp +++ b/Swiften/History/SQLiteHistoryManager.cpp @@ -9,7 +9,7 @@ #include #include -#include +#include inline std::string getEscapedString(const std::string& s) { std::string result(s); @@ -67,7 +67,7 @@ void SQLiteHistoryManager::addMessage(const HistoryMessage& message) { } } -std::vector SQLiteHistoryManager::getMessages(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date) const { +std::vector SQLiteHistoryManager::getMessagesFromDate(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date) const { sqlite3_stmt* selectStatement; boost::optional selfID = getIDFromJID(selfJID.toBare()); @@ -267,4 +267,72 @@ ContactsMap SQLiteHistoryManager::getContacts(const JID& selfJID, HistoryMessage return result; } +boost::gregorian::date SQLiteHistoryManager::getNextDateWithLogs(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date, bool reverseOrder) const { + sqlite3_stmt* selectStatement; + boost::optional selfID = getIDFromJID(selfJID.toBare()); + boost::optional contactID = getIDFromJID(contactJID.toBare()); + + if (!selfID || !contactID) { + // JIDs missing from the database + return boost::gregorian::date(boost::gregorian::not_a_date_time); + } + + std::string selectQuery = "SELECT time FROM messages WHERE (type=" + boost::lexical_cast(type); + if (contactJID.isBare()) { + // match only bare jid + selectQuery += " AND ((fromBare=" + boost::lexical_cast(*selfID) + " AND toBare=" + + boost::lexical_cast(*contactID) + ") OR (fromBare=" + + boost::lexical_cast(*contactID) + " AND toBare=" + boost::lexical_cast(*selfID) + ")))"; + } + else { + // match resource too + selectQuery += " AND ((fromBare=" + boost::lexical_cast(*selfID) + " AND (toBare=" + + boost::lexical_cast(*contactID) +" AND toResource='" + + getEscapedString(contactJID.getResource()) + "')) OR ((fromBare=" + + boost::lexical_cast(*contactID) + " AND fromResource='" + + getEscapedString(contactJID.getResource()) + "') AND toBare=" + + boost::lexical_cast(*selfID) + ")))"; + } + + int timeStamp = (boost::posix_time::ptime(date) - boost::posix_time::ptime(boost::gregorian::date(1970, 1, 1))).total_seconds() + (reverseOrder ? 0 : 86400); + + selectQuery += " AND time" + (reverseOrder ? std::string("<") : std::string(">")) + boost::lexical_cast(timeStamp); + selectQuery += " ORDER BY time " + (reverseOrder ? std::string("DESC") : std::string("ASC")) + " LIMIT 1"; + + int r = sqlite3_prepare(db_, selectQuery.c_str(), selectQuery.size(), &selectStatement, NULL); + if (r != SQLITE_OK) { + std::cout << "Error: " << sqlite3_errmsg(db_) << std::endl; + } + + r = sqlite3_step(selectStatement); + if (r == SQLITE_ROW) { + int secondsSinceEpoch(sqlite3_column_int(selectStatement, 0)); + boost::posix_time::ptime time(boost::gregorian::date(1970, 1, 1), boost::posix_time::seconds(secondsSinceEpoch)); + std::cout << "next day is: " << time.date() << "\n"; + return time.date(); + } + + return boost::gregorian::date(boost::gregorian::not_a_date_time); +} + +std::vector SQLiteHistoryManager::getMessagesFromNextDate(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date) const { + boost::gregorian::date nextDate = getNextDateWithLogs(selfJID, contactJID, type, date, false); + + if (nextDate.is_not_a_date()) { + return std::vector(); + } + + return getMessagesFromDate(selfJID, contactJID, type, nextDate); +} + +std::vector SQLiteHistoryManager::getMessagesFromPreviousDate(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date) const { + boost::gregorian::date previousDate = getNextDateWithLogs(selfJID, contactJID, type, date, true); + + if (previousDate.is_not_a_date()) { + return std::vector(); + } + + return getMessagesFromDate(selfJID, contactJID, type, previousDate); +} + } diff --git a/Swiften/History/SQLiteHistoryManager.h b/Swiften/History/SQLiteHistoryManager.h index 638d73f..8b08e6b 100644 --- a/Swiften/History/SQLiteHistoryManager.h +++ b/Swiften/History/SQLiteHistoryManager.h @@ -20,9 +20,12 @@ namespace Swift { void addMessage(const HistoryMessage& message); ContactsMap getContacts(const JID& selfJID, HistoryMessage::Type type, const std::string& keyword) const; - std::vector getMessages(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date) const; + std::vector getMessagesFromDate(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date) const; + std::vector getMessagesFromNextDate(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date) const; + std::vector getMessagesFromPreviousDate(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date) const; private: + boost::gregorian::date getNextDateWithLogs(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type, const boost::gregorian::date& date, bool reverseOrder) const; int getIDForJID(const JID&); int addJID(const JID&); -- cgit v0.10.2-6-g49f6