From 5e736fe9601d1af367d564b94666372661f70d2a Mon Sep 17 00:00:00 2001
From: Catalin Badea <catalin.badea392@gmail.com>
Date: Mon, 16 Jul 2012 12:42:35 +0300
Subject: Allow adding top messages in the chatview.


diff --git a/Swift/QtUI/QtChatView.cpp b/Swift/QtUI/QtChatView.cpp
index f1a33a1..d399c4f 100644
--- a/Swift/QtUI/QtChatView.cpp
+++ b/Swift/QtUI/QtChatView.cpp
@@ -86,13 +86,31 @@ void QtChatView::handleKeyPressEvent(QKeyEvent* event) {
 	webView_->keyPressEvent(event);
 }
 
-void QtChatView::addMessage(boost::shared_ptr<ChatSnippet> snippet) {
+void QtChatView::addMessageBottom(boost::shared_ptr<ChatSnippet> snippet) {
 	if (viewReady_) {
 		addToDOM(snippet);
 	} else {
 		/* If this asserts, the previous queuing code was necessary and should be reinstated */
 		assert(false);
 	}
+
+	if (firstElement_.isNull()) {
+		firstElement_ = lastElement_;
+	}
+}
+void QtChatView::addMessageTop(boost::shared_ptr<ChatSnippet> snippet) {
+	// save scrollbar maximum value
+	if (!topMessageAdded_) {
+		scrollBarMaximum_ = webPage_->mainFrame()->scrollBarMaximum(Qt::Vertical);
+	}
+	topMessageAdded_ = true;
+
+	QWebElement newElement = snippetToDOM(snippet);
+	firstElement_.prependOutside(newElement);
+	firstElement_ = newElement;
+	if (lastElement_.isNull()) {
+		lastElement_ = firstElement_;
+	}
 }
 
 QWebElement QtChatView::snippetToDOM(boost::shared_ptr<ChatSnippet> snippet) {
@@ -241,6 +259,13 @@ void QtChatView::scrollToBottom() {
 }
 
 void QtChatView::handleFrameSizeChanged() {
+	if (topMessageAdded_) {
+		// adjust new scrollbar position
+		int newMaximum = webPage_->mainFrame()->scrollBarMaximum(Qt::Vertical);
+		webPage_->mainFrame()->setScrollBarValue(Qt::Vertical, newMaximum - scrollBarMaximum_);
+		topMessageAdded_ = false;
+	}
+
 	if (isAtBottom_) {
 		scrollToBottom();
 	}
@@ -283,6 +308,9 @@ void QtChatView::resizeFont(int fontSizeSteps) {
 
 void QtChatView::resetView() {
 	lastElement_ = QWebElement();
+	firstElement_ = lastElement_;
+	topMessageAdded_ = false;
+	scrollBarMaximum_ = 0;
 	QString pageHTML = theme_->getTemplate();
 	pageHTML.replace("==bodyBackground==", "background-color:#e3e3e3");
 	pageHTML.replace(pageHTML.indexOf("%@"), 2, theme_->getBase());
@@ -386,8 +414,17 @@ void QtChatView::setMUCInvitationJoined(QString id) {
 }
 
 void QtChatView::handleScrollRequested(int, int dy, const QRect&) {
-	int pos = webPage_->mainFrame()->scrollBarValue(Qt::Vertical);
-	emit scrollRequested(pos - dy);
+	rememberScrolledToBottom();
+
+	int pos = webPage_->mainFrame()->scrollBarValue(Qt::Vertical) - dy;
+	emit scrollRequested(pos);
+
+	if (pos == 0) {
+		emit scrollReachedTop();
+	}
+	else if (pos == webPage_->mainFrame()->scrollBarMaximum(Qt::Vertical)) {
+		emit scrollReachedBottom();
+	}
 }
 
 int QtChatView::getSnippetPositionByDate(const QDate& date) {
diff --git a/Swift/QtUI/QtChatView.h b/Swift/QtUI/QtChatView.h
index 84771ee..d778f6f 100644
--- a/Swift/QtUI/QtChatView.h
+++ b/Swift/QtUI/QtChatView.h
@@ -29,7 +29,8 @@ namespace Swift {
 			Q_OBJECT
 		public:
 			QtChatView(QtChatTheme* theme, QWidget* parent);
-			void addMessage(boost::shared_ptr<ChatSnippet> snippet);
+			void addMessageTop(boost::shared_ptr<ChatSnippet> snippet);
+			void addMessageBottom(boost::shared_ptr<ChatSnippet> snippet);
 			void addLastSeenLine();
 			void replaceLastMessage(const QString& newMessage);
 			void replaceLastMessage(const QString& newMessage, const QString& note);
@@ -51,6 +52,8 @@ namespace Swift {
 			void fontResized(int);
 			void logCleared();
 			void scrollRequested(int pos);
+			void scrollReachedTop();
+			void scrollReachedBottom();
 
 		public slots:
 			void copySelectionToClipboard();
@@ -76,6 +79,8 @@ namespace Swift {
 
 			bool viewReady_;
 			bool isAtBottom_;
+			bool topMessageAdded_;
+			int scrollBarMaximum_;
 			QtWebView* webView_;
 			QWebPage* webPage_;
 			int fontSizeSteps_;
@@ -83,6 +88,7 @@ namespace Swift {
 			QWebElement newInsertPoint_;
 			QWebElement lineSeparator_;
 			QWebElement lastElement_;
+			QWebElement firstElement_;
 			QWebElement document_;
 	};
 }
diff --git a/Swift/QtUI/QtChatWindow.cpp b/Swift/QtUI/QtChatWindow.cpp
index f42469b..ddfe158 100644
--- a/Swift/QtUI/QtChatWindow.cpp
+++ b/Swift/QtUI/QtChatWindow.cpp
@@ -524,7 +524,7 @@ std::string QtChatWindow::addMessage(const QString &message, const std::string &
 	}
 	QString qAvatarPath =  scaledAvatarPath.isEmpty() ? "qrc:/icons/avatar.png" : QUrl::fromLocalFile(scaledAvatarPath).toEncoded();
 	std::string id = "id" + boost::lexical_cast<std::string>(idCounter_++);
-	messageLog_->addMessage(boost::shared_ptr<ChatSnippet>(new MessageSnippet(htmlString, Qt::escape(P2QSTRING(senderName)), B2QDATE(time), qAvatarPath, senderIsSelf, appendToPrevious, theme_, P2QSTRING(id))));
+	messageLog_->addMessageBottom(boost::shared_ptr<ChatSnippet>(new MessageSnippet(htmlString, Qt::escape(P2QSTRING(senderName)), B2QDATE(time), qAvatarPath, senderIsSelf, appendToPrevious, theme_, P2QSTRING(id))));
 
 	previousMessageWasSelf_ = senderIsSelf;
 	previousSenderName_ = P2QSTRING(senderName);
@@ -633,7 +633,7 @@ std::string QtChatWindow::addFileTransfer(const std::string& senderName, bool se
 	}
 	QString qAvatarPath = "qrc:/icons/avatar.png";
 	std::string id = "ftmessage" + boost::lexical_cast<std::string>(idCounter_++);
-	messageLog_->addMessage(boost::shared_ptr<ChatSnippet>(new MessageSnippet(htmlString, Qt::escape(P2QSTRING(senderName)), B2QDATE(boost::posix_time::second_clock::local_time()), qAvatarPath, senderIsSelf, appendToPrevious, theme_, P2QSTRING(id))));
+	messageLog_->addMessageBottom(boost::shared_ptr<ChatSnippet>(new MessageSnippet(htmlString, Qt::escape(P2QSTRING(senderName)), B2QDATE(boost::posix_time::second_clock::local_time()), qAvatarPath, senderIsSelf, appendToPrevious, theme_, P2QSTRING(id))));
 
 	previousMessageWasSelf_ = senderIsSelf;
 	previousSenderName_ = P2QSTRING(senderName);
@@ -701,7 +701,7 @@ void QtChatWindow::addErrorMessage(const std::string& errorMessage) {
 
 	QString errorMessageHTML(Qt::escape(P2QSTRING(errorMessage)));
 	errorMessageHTML.replace("\n","<br/>");
-	messageLog_->addMessage(boost::shared_ptr<ChatSnippet>(new SystemMessageSnippet("<span class=\"error\">" + errorMessageHTML + "</span>", QDateTime::currentDateTime(), false, theme_)));
+	messageLog_->addMessageBottom(boost::shared_ptr<ChatSnippet>(new SystemMessageSnippet("<span class=\"error\">" + errorMessageHTML + "</span>", QDateTime::currentDateTime(), false, theme_)));
 
 	previousMessageWasSelf_ = false;
 	previousMessageKind_ = PreviousMessageWasSystem;
@@ -714,7 +714,7 @@ void QtChatWindow::addSystemMessage(const std::string& message) {
 
 	QString messageHTML(P2QSTRING(message));
 	messageHTML = linkimoticonify(messageHTML);
-	messageLog_->addMessage(boost::shared_ptr<ChatSnippet>(new SystemMessageSnippet(messageHTML, QDateTime::currentDateTime(), false, theme_)));
+	messageLog_->addMessageBottom(boost::shared_ptr<ChatSnippet>(new SystemMessageSnippet(messageHTML, QDateTime::currentDateTime(), false, theme_)));
 
 	previousMessageKind_ = PreviousMessageWasSystem;
 }
@@ -753,7 +753,7 @@ void QtChatWindow::addPresenceMessage(const std::string& message) {
 
 	QString messageHTML(P2QSTRING(message));
 	messageHTML = linkimoticonify(messageHTML);
-	messageLog_->addMessage(boost::shared_ptr<ChatSnippet>(new SystemMessageSnippet(messageHTML, QDateTime::currentDateTime(), false, theme_)));
+	messageLog_->addMessageBottom(boost::shared_ptr<ChatSnippet>(new SystemMessageSnippet(messageHTML, QDateTime::currentDateTime(), false, theme_)));
 
 	previousMessageKind_ = PreviousMessageWasPresence;
 }
@@ -950,7 +950,7 @@ void QtChatWindow::addMUCInvitation(const std::string& senderName, const JID& ji
 	}
 	QString qAvatarPath = "qrc:/icons/avatar.png";
 
-	messageLog_->addMessage(boost::shared_ptr<ChatSnippet>(new MessageSnippet(htmlString, Qt::escape(P2QSTRING(senderName)), B2QDATE(boost::posix_time::second_clock::local_time()), qAvatarPath, false, appendToPrevious, theme_, id)));
+	messageLog_->addMessageBottom(boost::shared_ptr<ChatSnippet>(new MessageSnippet(htmlString, Qt::escape(P2QSTRING(senderName)), B2QDATE(boost::posix_time::second_clock::local_time()), qAvatarPath, false, appendToPrevious, theme_, id)));
 	previousMessageWasSelf_ = false;
 	previousSenderName_ = P2QSTRING(senderName);
 	previousMessageKind_ = PreviousMessageWasMUCInvite;
diff --git a/Swift/QtUI/QtHistoryWindow.cpp b/Swift/QtUI/QtHistoryWindow.cpp
index 95a47ac..36c899c 100644
--- a/Swift/QtUI/QtHistoryWindow.cpp
+++ b/Swift/QtUI/QtHistoryWindow.cpp
@@ -29,6 +29,7 @@ QtHistoryWindow::QtHistoryWindow(SettingsProvider* settings, UIEventStream* even
 	ui_.setupUi(this);
 
 	theme_ = new QtChatTheme("");
+	idCounter_ = 0;
 
 	delete ui_.conversation_;
 	conversation_ = new QtChatView(theme_, this);
@@ -53,6 +54,8 @@ QtHistoryWindow::QtHistoryWindow(SettingsProvider* settings, UIEventStream* even
 
 	conversationRoster_->onSomethingSelectedChanged.connect(boost::bind(&QtHistoryWindow::handleSomethingSelectedChanged, this, _1));
 	connect(conversation_, SIGNAL(scrollRequested(int)), this, SLOT(handleScrollRequested(int)));
+	connect(conversation_, SIGNAL(scrollReachedTop()), this, SLOT(handleScrollReachedTop()));
+	connect(conversation_, SIGNAL(scrollReachedBottom()), this, SLOT(handleScrollReachedBottom()));
 }
 
 QtHistoryWindow::~QtHistoryWindow() {
@@ -90,9 +93,11 @@ void QtHistoryWindow::addMessage(const std::string &message, const std::string &
 	QDateTime qTime = B2QDATE(time);
 	QDate date = qTime.date();
 
+	std::string id = "id" + boost::lexical_cast<std::string>(idCounter_++);
+
 	QString qAvatarPath =  scaledAvatarPath.isEmpty() ? "qrc:/icons/avatar.png" : QUrl::fromLocalFile(scaledAvatarPath).toEncoded();
 
-	conversation_->addMessage(boost::shared_ptr<ChatSnippet>(new MessageSnippet(messageHTML, Qt::escape(P2QSTRING(senderName)), qTime, qAvatarPath, senderIsSelf, false, theme_, "id")));
+	conversation_->addMessageBottom(boost::shared_ptr<ChatSnippet>(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)) {
@@ -128,5 +133,10 @@ void QtHistoryWindow::handleScrollRequested(int pos) {
 		ui_.calendarWidget_->setSelectedDate(currentDate_);
 	}
 }
+void QtHistoryWindow::handleScrollReachedTop() {
+}
+
+void QtHistoryWindow::handleScrollReachedBottom() {
+}
 
 }
diff --git a/Swift/QtUI/QtHistoryWindow.h b/Swift/QtUI/QtHistoryWindow.h
index 448780f..f9d9a30 100644
--- a/Swift/QtUI/QtHistoryWindow.h
+++ b/Swift/QtUI/QtHistoryWindow.h
@@ -31,6 +31,8 @@ namespace Swift {
 
 		protected slots:
 			void handleScrollRequested(int pos);
+			void handleScrollReachedTop();
+			void handleScrollReachedBottom();
 
 		private:
 			void handleSomethingSelectedChanged(RosterItem* item);
@@ -41,5 +43,6 @@ namespace Swift {
 			QtTreeWidget* conversationRoster_;
 			std::set<QDate> dates_;
 			QDate currentDate_;
+			int idCounter_;
 	};
 }
-- 
cgit v0.10.2-6-g49f6