summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'Swift/QtUI/QtChatView.cpp')
-rw-r--r--Swift/QtUI/QtChatView.cpp482
1 files changed, 5 insertions, 477 deletions
diff --git a/Swift/QtUI/QtChatView.cpp b/Swift/QtUI/QtChatView.cpp
index 31b9915..db4fe51 100644
--- a/Swift/QtUI/QtChatView.cpp
+++ b/Swift/QtUI/QtChatView.cpp
@@ -1,492 +1,20 @@
/*
- * Copyright (c) 2010 Remko Tronçon
+ * Copyright (c) 2013 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
-#include "QtChatView.h"
-
-#include <QtDebug>
-#include <QEventLoop>
-#include <QFile>
-#include <QDesktopServices>
-#include <QVBoxLayout>
-#include <QWebFrame>
-#include <QKeyEvent>
-#include <QStackedWidget>
-#include <QTimer>
-#include <QMessageBox>
-#include <QApplication>
-
-#include <Swiften/Base/Log.h>
-
-#include "QtWebView.h"
-#include "QtChatTheme.h"
-#include "QtChatWindow.h"
-#include "QtSwiftUtil.h"
+#include <Swift/QtUI/QtChatView.h>
namespace Swift {
-QtChatView::QtChatView(QtChatTheme* theme, QWidget* parent, bool disableAutoScroll) : QWidget(parent), fontSizeSteps_(0), disableAutoScroll_(disableAutoScroll) {
- theme_ = theme;
-
- QVBoxLayout* mainLayout = new QVBoxLayout(this);
- mainLayout->setSpacing(0);
- mainLayout->setContentsMargins(0,0,0,0);
- webView_ = new QtWebView(this);
- connect(webView_, SIGNAL(linkClicked(const QUrl&)), SLOT(handleLinkClicked(const QUrl&)));
- connect(webView_, SIGNAL(loadFinished(bool)), SLOT(handleViewLoadFinished(bool)));
- connect(webView_, SIGNAL(gotFocus()), SIGNAL(gotFocus()));
- connect(webView_, SIGNAL(clearRequested()), SLOT(handleClearRequested()));
- connect(webView_, SIGNAL(fontGrowRequested()), SLOT(increaseFontSize()));
- connect(webView_, SIGNAL(fontShrinkRequested()), SLOT(decreaseFontSize()));
-#if defined (Q_OS_UNIX) && !defined(Q_OS_MAC)
- /* To give a border on Linux, where it looks bad without */
- QStackedWidget* stack = new QStackedWidget(this);
- stack->addWidget(webView_);
- stack->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
- stack->setLineWidth(2);
- mainLayout->addWidget(stack);
-#else
- mainLayout->addWidget(webView_);
-#endif
-
-#ifdef SWIFT_EXPERIMENTAL_FT
- setAcceptDrops(true);
-#endif
-
- webPage_ = new QWebPage(this);
- webPage_->setLinkDelegationPolicy(QWebPage::DelegateAllLinks);
- if (Log::getLogLevel() == Log::debug) {
- 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;
- resetView();
-}
-
-void QtChatView::handleClearRequested() {
- QMessageBox messageBox(this);
- messageBox.setWindowTitle(tr("Clear log"));
- messageBox.setText(tr("You are about to clear the contents of your chat log."));
- messageBox.setInformativeText(tr("Are you sure?"));
- messageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
- messageBox.setDefaultButton(QMessageBox::Yes);
- int button = messageBox.exec();
- if (button == QMessageBox::Yes) {
- logCleared();
- resetView();
- }
-}
-
-void QtChatView::handleKeyPressEvent(QKeyEvent* event) {
- webView_->keyPressEvent(event);
-}
-
-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);
- }
-}
-
-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");
- Q_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());
- Q_ASSERT(!newElement.isNull());
- return newElement;
-}
-
-void QtChatView::addToDOM(boost::shared_ptr<ChatSnippet> snippet) {
- //qDebug() << snippet->getContent();
- rememberScrolledToBottom();
- bool insert = snippet->getAppendToPrevious();
- QWebElement continuationElement = lastElement_.findFirst("#insert");
- bool fallback = insert && 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();
- newInsertPoint_.prependOutside(newElement);
- }
- lastElement_ = newElement;
- if (fontSizeSteps_ != 0) {
- double size = 1.0 + 0.2 * fontSizeSteps_;
- QString sizeString(QString().setNum(size, 'g', 3) + "em");
- const QWebElementCollection spans = lastElement_.findAll("span.swift_resizable");
- Q_FOREACH (QWebElement span, spans) {
- span.setStyleProperty("font-size", sizeString);
- }
- }
- //qDebug() << "-----------------";
- //qDebug() << webPage_->mainFrame()->toHtml();
-}
-
-void QtChatView::addLastSeenLine() {
- if (lineSeparator_.isNull()) {
- lineSeparator_ = newInsertPoint_.clone();
- lineSeparator_.setInnerXml(QString("<hr/>"));
- newInsertPoint_.prependOutside(lineSeparator_);
- }
- else {
- QWebElement lineSeparatorC = lineSeparator_.clone();
- lineSeparatorC.removeFromDocument();
- }
- newInsertPoint_.prependOutside(lineSeparator_);
-}
-
-void QtChatView::replaceLastMessage(const QString& newMessage) {
- assert(viewReady_);
- rememberScrolledToBottom();
- assert(!lastElement_.isNull());
- QWebElement replace = lastElement_.findFirst("span.swift_message");
- assert(!replace.isNull());
- QString old = lastElement_.toOuterXml();
- replace.setInnerXml(ChatSnippet::escape(newMessage));
-}
-
-void QtChatView::replaceLastMessage(const QString& newMessage, const QString& note) {
- rememberScrolledToBottom();
- replaceLastMessage(newMessage);
- QWebElement replace = lastElement_.findFirst("span.swift_time");
- assert(!replace.isNull());
- replace.setInnerXml(ChatSnippet::escape(note));
-}
-
-QString QtChatView::getLastSentMessage() {
- return lastElement_.toPlainText();
-}
-
-void QtChatView::addToJSEnvironment(const QString& name, QObject* obj) {
- webView_->page()->currentFrame()->addToJavaScriptWindowObject(name, obj);
-}
-
-void QtChatView::replaceMessage(const QString& newMessage, const QString& id, const QDateTime& editTime) {
- rememberScrolledToBottom();
- QWebElement message = document_.findFirst("#" + id);
- if (!message.isNull()) {
- QWebElement replaceContent = message.findFirst("span.swift_inner_message");
- assert(!replaceContent.isNull());
- QString old = replaceContent.toOuterXml();
- replaceContent.setInnerXml(ChatSnippet::escape(newMessage));
- QWebElement replaceTime = message.findFirst("span.swift_time");
- assert(!replaceTime.isNull());
- old = replaceTime.toOuterXml();
- replaceTime.setInnerXml(ChatSnippet::escape(tr("%1 edited").arg(ChatSnippet::timeToEscapedString(editTime))));
- }
- else {
- qWarning() << "Trying to replace element with id " << id << " but it's not there.";
- }
-}
-
-void QtChatView::showEmoticons(bool show) {
- {
- const QWebElementCollection spans = document_.findAll("span.swift_emoticon_image");
- Q_FOREACH (QWebElement span, spans) {
- span.setStyleProperty("display", show ? "inline" : "none");
- }
- }
- {
- const QWebElementCollection spans = document_.findAll("span.swift_emoticon_text");
- Q_FOREACH (QWebElement span, spans) {
- span.setStyleProperty("display", show ? "none" : "inline");
- }
- }
-}
-
-void QtChatView::copySelectionToClipboard() {
- if (!webPage_->selectedText().isEmpty()) {
- webPage_->triggerAction(QWebPage::Copy);
- }
-}
-
-void QtChatView::setAckXML(const QString& id, const QString& xml) {
- QWebElement message = document_.findFirst("#" + id);
- /* Deliberately not asserting here, so that when we start expiring old messages it won't hit us */
- if (message.isNull()) return;
- QWebElement ackElement = message.findFirst("span.swift_ack");
- assert(!ackElement.isNull());
- ackElement.setInnerXml(xml);
-}
-
-void QtChatView::setReceiptXML(const QString& id, const QString& xml) {
- QWebElement message = document_.findFirst("#" + id);
- if (message.isNull()) return;
- QWebElement receiptElement = message.findFirst("span.swift_receipt");
- assert(!receiptElement.isNull());
- receiptElement.setInnerXml(xml);
-}
-
-void QtChatView::displayReceiptInfo(const QString& id, bool showIt) {
- QWebElement message = document_.findFirst("#" + id);
- if (message.isNull()) return;
- QWebElement receiptElement = message.findFirst("span.swift_receipt");
- assert(!receiptElement.isNull());
- receiptElement.setStyleProperty("display", showIt ? "inline" : "none");
-}
-
-void QtChatView::rememberScrolledToBottom() {
- isAtBottom_ = webPage_->mainFrame()->scrollBarValue(Qt::Vertical) >= (webPage_->mainFrame()->scrollBarMaximum(Qt::Vertical) - 1);
-}
-
-void QtChatView::scrollToBottom() {
- isAtBottom_ = true;
- webPage_->mainFrame()->setScrollBarValue(Qt::Vertical, webPage_->mainFrame()->scrollBarMaximum(Qt::Vertical));
- webView_->update(); /* Work around redraw bug in some versions of Qt. */
-}
-
-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;
- }
+QtChatView::QtChatView(QWidget* parent) : QWidget(parent) {
- if (isAtBottom_ && !disableAutoScroll_) {
- scrollToBottom();
- }
}
-void QtChatView::handleLinkClicked(const QUrl& url) {
- QDesktopServices::openUrl(url);
-}
-
-void QtChatView::handleViewLoadFinished(bool ok) {
- Q_ASSERT(ok);
- viewReady_ = true;
-}
-
-void QtChatView::increaseFontSize(int numSteps) {
- //qDebug() << "Increasing";
- fontSizeSteps_ += numSteps;
- emit fontResized(fontSizeSteps_);
-}
-
-void QtChatView::decreaseFontSize() {
- fontSizeSteps_--;
- if (fontSizeSteps_ < 0) {
- fontSizeSteps_ = 0;
- }
- emit fontResized(fontSizeSteps_);
-}
-
-void QtChatView::resizeFont(int fontSizeSteps) {
- fontSizeSteps_ = fontSizeSteps;
- double size = 1.0 + 0.2 * fontSizeSteps_;
- QString sizeString(QString().setNum(size, 'g', 3) + "em");
- //qDebug() << "Setting to " << sizeString;
- const QWebElementCollection spans = document_.findAll("span.swift_resizable");
- Q_FOREACH (QWebElement span, spans) {
- span.setStyleProperty("font-size", sizeString);
- }
- webView_->setFontSizeIsMinimal(size == 1.0);
-}
-
-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());
- if (pageHTML.count("%@") > 3) {
- pageHTML.replace(pageHTML.indexOf("%@"), 2, theme_->getMainCSS());
- }
- pageHTML.replace(pageHTML.indexOf("%@"), 2, "Variants/Blue on Green.css");
- pageHTML.replace(pageHTML.indexOf("%@"), 2, ""/*headerSnippet.getContent()*/);
- pageHTML.replace(pageHTML.indexOf("%@"), 2, ""/*footerSnippet.getContent()*/);
- QEventLoop syncLoop;
- connect(webView_, SIGNAL(loadFinished(bool)), &syncLoop, SLOT(quit()));
- webPage_->mainFrame()->setHtml(pageHTML);
- while (!viewReady_) {
- QTimer t;
- t.setSingleShot(true);
- connect(&t, SIGNAL(timeout()), &syncLoop, SLOT(quit()));
- t.start(50);
- 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);
-}
-
-static QWebElement findElementWithID(QWebElement document, QString elementName, QString id) {
- QWebElementCollection elements = document.findAll(elementName);
- Q_FOREACH(QWebElement element, elements) {
- if (element.attribute("id") == id) {
- return element;
- }
- }
- return QWebElement();
-}
-
-void QtChatView::setFileTransferProgress(QString id, const int percentageDone) {
- QWebElement ftElement = findElementWithID(document_, "div", id);
- if (ftElement.isNull()) {
- SWIFT_LOG(debug) << "Tried to access FT UI via invalid id!" << std::endl;
- return;
- }
- QWebElement progressBar = ftElement.findFirst("div.progressbar");
- progressBar.setStyleProperty("width", QString::number(percentageDone) + "%");
-
- QWebElement progressBarValue = ftElement.findFirst("div.progressbar-value");
- progressBarValue.setInnerXml(QString::number(percentageDone) + " %");
-}
-
-void QtChatView::setFileTransferStatus(QString id, const ChatWindow::FileTransferState state, const QString& /* msg */) {
- QWebElement ftElement = findElementWithID(document_, "div", id);
- if (ftElement.isNull()) {
- SWIFT_LOG(debug) << "Tried to access FT UI via invalid id! id = " << Q2PSTRING(id) << std::endl;
- return;
- }
-
- QString newInnerHTML = "";
- if (state == ChatWindow::WaitingForAccept) {
- newInnerHTML = tr("Waiting for other side to accept the transfer.") + "<br/>" +
- QtChatWindow::buildChatWindowButton(tr("Cancel"), QtChatWindow::ButtonFileTransferCancel, id);
- }
- if (state == ChatWindow::Negotiating) {
- // replace with text "Negotiaging" + Cancel button
- newInnerHTML = tr("Negotiating...") + "<br/>" +
- QtChatWindow::buildChatWindowButton(tr("Cancel"), QtChatWindow::ButtonFileTransferCancel, id);
- }
- else if (state == ChatWindow::Transferring) {
- // progress bar + Cancel Button
- newInnerHTML = "<div style=\"position: relative; width: 90%; height: 20px; border: 2px solid grey; -webkit-border-radius: 10px;\">"
- "<div class=\"progressbar\" style=\"width: 0%; height: 100%; background: #AAA; -webkit-border-radius: 6px;\">"
- "<div class=\"progressbar-value\" style=\"position: absolute; top: 0px; left: 0px; width: 100%; text-align: center; padding-top: 2px;\">"
- "0%"
- "</div>"
- "</div>"
- "</div>" +
- QtChatWindow::buildChatWindowButton(tr("Cancel"), QtChatWindow::ButtonFileTransferCancel, id);
- }
- else if (state == ChatWindow::Canceled) {
- newInnerHTML = tr("Transfer has been canceled!");
- }
- else if (state == ChatWindow::Finished) {
- // text "Successful transfer"
- newInnerHTML = tr("Transfer completed successfully.");
- }
- else if (state == ChatWindow::FTFailed) {
- newInnerHTML = tr("Transfer failed.");
- }
-
- ftElement.setInnerXml(newInnerHTML);
-}
-
-void QtChatView::setWhiteboardSessionStatus(QString id, const ChatWindow::WhiteboardSessionState state) {
- QWebElement divElement = findElementWithID(document_, "div", id);
- QString newInnerHTML;
- if (state == ChatWindow::WhiteboardAccepted) {
- newInnerHTML = tr("Started whiteboard chat") + "<br/>" +
- QtChatWindow::buildChatWindowButton(tr("Show whiteboard"), QtChatWindow::ButtonWhiteboardShowWindow, id);
- } else if (state == ChatWindow::WhiteboardTerminated) {
- newInnerHTML = tr("Whiteboard chat has been canceled");
- } else if (state == ChatWindow::WhiteboardRejected) {
- newInnerHTML = tr("Whiteboard chat request has been rejected");
- }
- divElement.setInnerXml(newInnerHTML);
-}
-
-void QtChatView::setMUCInvitationJoined(QString id) {
- QWebElement divElement = findElementWithID(document_, "div", id);
- QWebElement buttonElement = findElementWithID(divElement, "input", "mucinvite");
- if (!buttonElement.isNull()) {
- buttonElement.setAttribute("value", tr("Return to room"));
- }
-}
-
-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_);
+QtChatView::~QtChatView() {
+
}
}