diff options
Diffstat (limited to 'Swift/QtUI/QtChatView.cpp')
-rw-r--r-- | Swift/QtUI/QtChatView.cpp | 94 |
1 files changed, 90 insertions, 4 deletions
diff --git a/Swift/QtUI/QtChatView.cpp b/Swift/QtUI/QtChatView.cpp index 49e5974..eaec3b6 100644 --- a/Swift/QtUI/QtChatView.cpp +++ b/Swift/QtUI/QtChatView.cpp @@ -28,7 +28,7 @@ namespace Swift { -QtChatView::QtChatView(QtChatTheme* theme, QWidget* parent) : QWidget(parent), fontSizeSteps_(0) { +QtChatView::QtChatView(QtChatTheme* theme, QWidget* parent, bool disableAutoScroll) : QWidget(parent), fontSizeSteps_(0), disableAutoScroll_(disableAutoScroll) { theme_ = theme; QVBoxLayout* mainLayout = new QVBoxLayout(this); @@ -61,6 +61,7 @@ QtChatView::QtChatView(QtChatTheme* theme, QWidget* parent) : QWidget(parent), f //webPage_->settings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, true); webView_->setPage(webPage_); connect(webPage_, SIGNAL(selectionChanged()), SLOT(copySelectionToClipboard())); + connect(webPage_, SIGNAL(scrollRequested(int, int, const QRect&)), SLOT(handleScrollRequested(int, int, const QRect&))); viewReady_ = false; isAtBottom_ = true; @@ -85,7 +86,7 @@ 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 { @@ -94,6 +95,45 @@ void QtChatView::addMessage(boost::shared_ptr<ChatSnippet> snippet) { } } +void QtChatView::addMessageTop(boost::shared_ptr<ChatSnippet> snippet) { + // save scrollbar maximum value + if (!topMessageAdded_) { + scrollBarMaximum_ = webPage_->mainFrame()->scrollBarMaximum(Qt::Vertical); + } + topMessageAdded_ = true; + + QWebElement continuationElement = firstElement_.findFirst("#insert"); + + bool insert = snippet->getAppendToPrevious(); + bool fallback = continuationElement.isNull(); + + boost::shared_ptr<ChatSnippet> newSnippet = (insert && fallback) ? snippet->getContinuationFallbackSnippet() : snippet; + QWebElement newElement = snippetToDOM(newSnippet); + + if (insert && !fallback) { + Q_ASSERT(!continuationElement.isNull()); + continuationElement.replace(newElement); + } else { + continuationElement.removeFromDocument(); + topInsertPoint_.prependOutside(newElement); + } + + firstElement_ = newElement; + + if (lastElement_.isNull()) { + lastElement_ = firstElement_; + } + + if (fontSizeSteps_ != 0) { + double size = 1.0 + 0.2 * fontSizeSteps_; + QString sizeString(QString().setNum(size, 'g', 3) + "em"); + const QWebElementCollection spans = firstElement_.findAll("span.swift_resizable"); + foreach (QWebElement span, spans) { + span.setStyleProperty("font-size", sizeString); + } + } +} + QWebElement QtChatView::snippetToDOM(boost::shared_ptr<ChatSnippet> snippet) { QWebElement newElement = newInsertPoint_.clone(); newElement.setInnerXml(snippet->getContent()); @@ -230,7 +270,7 @@ void QtChatView::displayReceiptInfo(const QString& id, bool showIt) { } void QtChatView::rememberScrolledToBottom() { - isAtBottom_ = webPage_->mainFrame()->scrollBarValue(Qt::Vertical) == webPage_->mainFrame()->scrollBarMaximum(Qt::Vertical); + isAtBottom_ = webPage_->mainFrame()->scrollBarValue(Qt::Vertical) >= (webPage_->mainFrame()->scrollBarMaximum(Qt::Vertical) - 1); } void QtChatView::scrollToBottom() { @@ -240,7 +280,14 @@ void QtChatView::scrollToBottom() { } void QtChatView::handleFrameSizeChanged() { - if (isAtBottom_) { + if (topMessageAdded_) { + // adjust new scrollbar position + int newMaximum = webPage_->mainFrame()->scrollBarMaximum(Qt::Vertical); + webPage_->mainFrame()->setScrollBarValue(Qt::Vertical, newMaximum - scrollBarMaximum_); + topMessageAdded_ = false; + } + + if (isAtBottom_ && !disableAutoScroll_) { scrollToBottom(); } } @@ -282,6 +329,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()); @@ -302,12 +352,16 @@ void QtChatView::resetView() { syncLoop.exec(); } document_ = webPage_->mainFrame()->documentElement(); + + resetTopInsertPoint(); QWebElement chatElement = document_.findFirst("#Chat"); newInsertPoint_ = chatElement.clone(); newInsertPoint_.setOuterXml("<div id='swift_insert'/>"); chatElement.appendInside(newInsertPoint_); Q_ASSERT(!newInsertPoint_.isNull()); + scrollToBottom(); + connect(webPage_->mainFrame(), SIGNAL(contentsSizeChanged(const QSize&)), this, SLOT(handleFrameSizeChanged()), Qt::UniqueConnection); } @@ -384,4 +438,36 @@ void QtChatView::setMUCInvitationJoined(QString id) { } } +void QtChatView::handleScrollRequested(int, int dy, const QRect&) { + 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) { + QWebElement message = webPage_->mainFrame()->documentElement().findFirst(".date" + date.toString(Qt::ISODate)); + + return message.geometry().top(); +} + +void QtChatView::resetTopInsertPoint() { + QWebElement continuationElement = firstElement_.findFirst("#insert"); + continuationElement.removeFromDocument(); + firstElement_ = QWebElement(); + + topInsertPoint_.removeFromDocument(); + QWebElement chatElement = document_.findFirst("#Chat"); + topInsertPoint_ = chatElement.clone(); + topInsertPoint_.setOuterXml("<div id='swift_insert'/>"); + chatElement.prependInside(topInsertPoint_); +} + } |