diff options
author | Tobias Markmann <tm@ayena.de> | 2011-11-11 15:01:32 (GMT) |
---|---|---|
committer | Kevin Smith <git@kismith.co.uk> | 2011-11-28 16:44:22 (GMT) |
commit | 86aad702d1f2e831c8e27bbe4ca1402626e4c542 (patch) | |
tree | 3be5a8ed23aef3877c9b313d0ee0f58afb54f57a /Swift/QtUI | |
parent | 81a7776d5ab523894a7c4745baee3988ad9f1ef9 (diff) | |
download | swift-contrib-86aad702d1f2e831c8e27bbe4ca1402626e4c542.zip swift-contrib-86aad702d1f2e831c8e27bbe4ca1402626e4c542.tar.bz2 |
Message Receipts (XEP-0184) support for 1-to-1 conversations (including 1-to-1 MUC).
Warn icon from already existing theme. Check icon from Wikipedia. See Swift/resources/icons/license_info.txt for details.
License: This patch is BSD-licensed, see http://www.opensource.org/licenses/bsd-license.php
Diffstat (limited to 'Swift/QtUI')
-rw-r--r-- | Swift/QtUI/MessageSnippet.cpp | 2 | ||||
-rw-r--r-- | Swift/QtUI/QtChatView.cpp | 16 | ||||
-rw-r--r-- | Swift/QtUI/QtChatView.h | 3 | ||||
-rw-r--r-- | Swift/QtUI/QtChatWindow.cpp | 23 | ||||
-rw-r--r-- | Swift/QtUI/QtChatWindow.h | 4 | ||||
-rw-r--r-- | Swift/QtUI/QtLoginWindow.cpp | 4 | ||||
-rw-r--r-- | Swift/QtUI/QtLoginWindow.h | 9 | ||||
-rw-r--r-- | Swift/QtUI/QtMainWindow.cpp | 19 | ||||
-rw-r--r-- | Swift/QtUI/QtMainWindow.h | 6 | ||||
-rw-r--r-- | Swift/QtUI/QtUIFactory.cpp | 2 | ||||
-rw-r--r-- | Swift/QtUI/Swift.qrc | 2 |
11 files changed, 83 insertions, 7 deletions
diff --git a/Swift/QtUI/MessageSnippet.cpp b/Swift/QtUI/MessageSnippet.cpp index 47cb1a0..a2e4651 100644 --- a/Swift/QtUI/MessageSnippet.cpp +++ b/Swift/QtUI/MessageSnippet.cpp @@ -26,19 +26,19 @@ MessageSnippet::MessageSnippet(const QString& message, const QString& sender, co else { if (appendToPrevious) { content_ = theme->getOutgoingNextContent(); } else { content_ = theme->getOutgoingContent(); } } - content_.replace("%message%", "<span class='swift_message'>" + escape(message) + "</span><span class='swift_ack'></span>"); + content_.replace("%message%", "<span class='swift_message'>" + escape(message) + "</span><span class='swift_ack'></span><span class='swift_receipt'></span>"); content_.replace("%sender%", escape(sender)); content_.replace("%time%", "<span class='swift_time'>" + timeToEscapedString(time) + "</span>"); content_.replace("%userIconPath%", escape(iconURI)); content_ = "<div id='" + id + "'>" + content_ + "</div>"; } MessageSnippet::~MessageSnippet() { } diff --git a/Swift/QtUI/QtChatView.cpp b/Swift/QtUI/QtChatView.cpp index 1c3dd37..db00ba0 100644 --- a/Swift/QtUI/QtChatView.cpp +++ b/Swift/QtUI/QtChatView.cpp @@ -190,18 +190,34 @@ void QtChatView::copySelectionToClipboard() { 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); } 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. */ } diff --git a/Swift/QtUI/QtChatView.h b/Swift/QtUI/QtChatView.h index cf47029..0cc521a 100644 --- a/Swift/QtUI/QtChatView.h +++ b/Swift/QtUI/QtChatView.h @@ -29,18 +29,21 @@ namespace Swift { public: QtChatView(QtChatTheme* theme, QWidget* parent); void addMessage(boost::shared_ptr<ChatSnippet> snippet); void addLastSeenLine(); void replaceLastMessage(const QString& newMessage); void replaceLastMessage(const QString& newMessage, const QString& note); void replaceMessage(const QString& newMessage, const QString& id, const QDateTime& time); void rememberScrolledToBottom(); void setAckXML(const QString& id, const QString& xml); + void setReceiptXML(const QString& id, const QString& xml); + void displayReceiptInfo(const QString& id, bool showIt); + QString getLastSentMessage(); void addToJSEnvironment(const QString&, QObject*); void setFileTransferProgress(QString id, const int percentageDone); void setFileTransferStatus(QString id, const ChatWindow::FileTransferState state, const QString& msg); signals: void gotFocus(); void fontResized(int); diff --git a/Swift/QtUI/QtChatWindow.cpp b/Swift/QtUI/QtChatWindow.cpp index f0f268d..88f326f 100644 --- a/Swift/QtUI/QtChatWindow.cpp +++ b/Swift/QtUI/QtChatWindow.cpp @@ -469,25 +469,44 @@ std::string QtChatWindow::addMessage(const std::string &message, const std::stri } void QtChatWindow::flash() { emit requestFlash(); } void QtChatWindow::setAckState(std::string const& id, ChatWindow::AckState state) { QString xml; switch (state) { - case ChatWindow::Pending: xml = "<img src='qrc:/icons/throbber.gif' alt='" + tr("This message has not been received by your server yet.") + "'/>"; break; - case ChatWindow::Received: xml = ""; break; + case ChatWindow::Pending: + xml = "<img src='qrc:/icons/throbber.gif' alt='" + tr("This message has not been received by your server yet.") + "'/>"; + messageLog_->displayReceiptInfo(P2QSTRING(id), false); + break; + case ChatWindow::Received: + xml = ""; + messageLog_->displayReceiptInfo(P2QSTRING(id), true); + break; case ChatWindow::Failed: xml = "<img src='qrc:/icons/error.png' alt='" + tr("This message may not have been transmitted.") + "'/>"; break; } messageLog_->setAckXML(P2QSTRING(id), xml); } +void QtChatWindow::setMessageReceiptState(const std::string& id, ChatWindow::ReceiptState state) { + QString xml; + switch (state) { + case ChatWindow::ReceiptReceived: + xml = "<img src='qrc:/icons/check.png' alt'" + tr("The receipt for this message has been received.") + "'/>"; + break; + case ChatWindow::ReceiptRequested: + xml = "<img src='qrc:/icons/warn.png' alt='" + tr("The receipt for this message has not yet been received. The receipient(s) might not have received this message.") + "'/>"; + break; + } + messageLog_->setReceiptXML(P2QSTRING(id), xml); +} + int QtChatWindow::getCount() { return unreadCount_; } std::string QtChatWindow::addAction(const std::string &message, const std::string &senderName, bool senderIsSelf, boost::shared_ptr<SecurityLabel> label, const std::string& avatarPath, const boost::posix_time::ptime& time) { return addMessage(" *" + message + "*", senderName, senderIsSelf, label, avatarPath, "font-style:italic ", time); } std::string formatSize(const boost::uintmax_t bytes) { diff --git a/Swift/QtUI/QtChatWindow.h b/Swift/QtUI/QtChatWindow.h index 233f2bc..55e929d 100644 --- a/Swift/QtUI/QtChatWindow.h +++ b/Swift/QtUI/QtChatWindow.h @@ -62,18 +62,22 @@ namespace Swift { void setName(const std::string& name); void setInputEnabled(bool enabled); QtTabbable::AlertType getWidgetAlertState(); void setContactChatState(ChatState::ChatStateType state); void setRosterModel(Roster* roster); void setTabComplete(TabComplete* completer); int getCount(); void replaceLastMessage(const std::string& message); void setAckState(const std::string& id, AckState state); + + // message receipts + void setMessageReceiptState(const std::string& id, ChatWindow::ReceiptState state); + void flash(); QByteArray getSplitterState(); virtual void setAvailableOccupantActions(const std::vector<OccupantAction>& actions); void setSubject(const std::string& subject); void showRoomConfigurationForm(Form::ref); void addMUCInvitation(const JID& jid, const std::string& reason, const std::string& password); void setAffiliations(MUCOccupant::Affiliation, const std::vector<JID>&); public slots: diff --git a/Swift/QtUI/QtLoginWindow.cpp b/Swift/QtUI/QtLoginWindow.cpp index e339d79..5a8b9ab 100644 --- a/Swift/QtUI/QtLoginWindow.cpp +++ b/Swift/QtUI/QtLoginWindow.cpp @@ -449,18 +449,22 @@ void QtLoginWindow::bringToFront() { window()->hide(); #endif } } void QtLoginWindow::hide() { window()->hide(); } +QtLoginWindow::QtMenus QtLoginWindow::getMenus() const { + return QtMenus(swiftMenu_, generalMenu_); +} + void QtLoginWindow::resizeEvent(QResizeEvent*) { emit geometryChanged(); } void QtLoginWindow::moveEvent(QMoveEvent*) { emit geometryChanged(); } bool QtLoginWindow::askUserToTrustCertificatePermanently(const std::string& message, Certificate::ref certificate) { diff --git a/Swift/QtUI/QtLoginWindow.h b/Swift/QtUI/QtLoginWindow.h index acf327f..a830af5 100644 --- a/Swift/QtUI/QtLoginWindow.h +++ b/Swift/QtUI/QtLoginWindow.h @@ -21,31 +21,38 @@ class QLabel; class QToolButton; class QComboBox; namespace Swift { class QtLoginWindow : public QMainWindow, public LoginWindow { Q_OBJECT public: + struct QtMenus { + QtMenus(QMenu* swiftMenu, QMenu* generalMenu) : swiftMenu(swiftMenu), generalMenu(generalMenu) {} + QMenu* swiftMenu; + QMenu* generalMenu; + }; + + public: QtLoginWindow(UIEventStream* uiEventStream, bool eagleMode); void morphInto(MainWindow *mainWindow); virtual void loggedOut(); virtual void setMessage(const std::string& message); virtual void addAvailableAccount(const std::string& defaultJID, const std::string& defaultPassword, const std::string& defaultCertificate); virtual void removeAvailableAccount(const std::string& jid); virtual void setLoginAutomatically(bool loginAutomatically); virtual void setIsLoggingIn(bool loggingIn); void selectUser(const std::string& user); bool askUserToTrustCertificatePermanently(const std::string& message, Certificate::ref certificate); void hide(); - + QtMenus getMenus() const; virtual void quit(); signals: void geometryChanged(); private slots: void loginClicked(); void handleCertficateChecked(bool); void handleQuit(); diff --git a/Swift/QtUI/QtMainWindow.cpp b/Swift/QtUI/QtMainWindow.cpp index a4ce98e..199e388 100644 --- a/Swift/QtUI/QtMainWindow.cpp +++ b/Swift/QtUI/QtMainWindow.cpp @@ -19,32 +19,34 @@ #include <QMenuBar> #include <QToolBar> #include <QAction> #include <QTabWidget> #include <Swift/QtUI/QtSwiftUtil.h> #include <Swift/QtUI/QtTabWidget.h> #include <Swift/QtUI/QtSettingsProvider.h> #include <Swift/QtUI/QtUIPreferences.h> +#include <Swift/QtUI/QtLoginWindow.h> #include <Roster/QtRosterWidget.h> #include <Swift/Controllers/UIEvents/RequestJoinMUCUIEvent.h> #include <Swift/Controllers/UIEvents/RequestAddUserDialogUIEvent.h> #include <Swift/Controllers/UIEvents/RequestChatWithUserDialogUIEvent.h> #include <Swift/Controllers/UIEvents/RequestProfileEditorUIEvent.h> #include <Swift/Controllers/UIEvents/JoinMUCUIEvent.h> #include <Swift/Controllers/UIEvents/ToggleShowOfflineUIEvent.h> #include <Swift/Controllers/UIEvents/RequestAdHocUIEvent.h> +#include <Swift/Controllers/UIEvents/ToggleRequestDeliveryReceiptsUIEvent.h> namespace Swift { #define CURRENT_ROSTER_TAB "current_roster_tab" -QtMainWindow::QtMainWindow(QtSettingsProvider* settings, UIEventStream* uiEventStream, QtUIPreferences* uiPreferences) : QWidget(), MainWindow(false) { +QtMainWindow::QtMainWindow(QtSettingsProvider* settings, UIEventStream* uiEventStream, QtUIPreferences* uiPreferences, QtLoginWindow::QtMenus loginMenus) : QWidget(), MainWindow(false), loginMenus_(loginMenus) { uiEventStream_ = uiEventStream; uiPreferences_ = uiPreferences; settings_ = settings; setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding)); QBoxLayout *mainLayout = new QBoxLayout(QBoxLayout::TopToBottom, this); mainLayout->setContentsMargins(0,0,0,0); mainLayout->setSpacing(0); meView_ = new QtRosterHeader(settings, this); mainLayout->addWidget(meView_); @@ -117,18 +119,24 @@ QtMainWindow::QtMainWindow(QtSettingsProvider* settings, UIEventStream* uiEventS connect(chatUserAction_, SIGNAL(triggered(bool)), this, SLOT(handleChatUserActionTriggered(bool))); actionsMenu->addAction(chatUserAction_); serverAdHocMenu_ = new QMenu(tr("Run Server Command"), this); actionsMenu->addMenu(serverAdHocMenu_); actionsMenu->addSeparator(); QAction* signOutAction = new QAction(tr("&Sign Out"), this); connect(signOutAction, SIGNAL(triggered()), SLOT(handleSignOutAction())); actionsMenu->addAction(signOutAction); + toggleRequestDeliveryReceipts_ = new QAction(tr("&Request Delivery Receipts"), this); + toggleRequestDeliveryReceipts_->setCheckable(true); + toggleRequestDeliveryReceipts_->setChecked(false); + connect(toggleRequestDeliveryReceipts_, SIGNAL(toggled(bool)), SLOT(handleToggleRequestDeliveryReceipts(bool))); + loginMenus_.generalMenu->addAction(toggleRequestDeliveryReceipts_); + treeWidget_->onSomethingSelectedChanged.connect(boost::bind(&QAction::setEnabled, editUserAction_, _1)); setAvailableAdHocCommands(std::vector<DiscoItems::Item>()); QAction* adHocAction = new QAction(tr("Collecting commands..."), this); adHocAction->setEnabled(false); serverAdHocMenu_->addAction(adHocAction); serverAdHocCommandActions_.append(adHocAction); lastOfflineState_ = false; @@ -137,18 +145,22 @@ QtMainWindow::QtMainWindow(QtSettingsProvider* settings, UIEventStream* uiEventS QtMainWindow::~QtMainWindow() { uiEventStream_->onUIEvent.disconnect(boost::bind(&QtMainWindow::handleUIEvent, this, _1)); } void QtMainWindow::handleTabChanged(int index) { settings_->storeInt(CURRENT_ROSTER_TAB, index); } +void QtMainWindow::handleToggleRequestDeliveryReceipts(bool enabled) { + uiEventStream_->send(boost::make_shared<ToggleRequestDeliveryReceiptsUIEvent>(enabled)); +} + QtEventWindow* QtMainWindow::getEventWindow() { return eventWindow_; } QtChatListWindow* QtMainWindow::getChatListWindow() { return chatListWindow_; } void QtMainWindow::setRosterModel(Roster* roster) { @@ -186,18 +198,19 @@ void QtMainWindow::handleAddUserActionTriggered(bool /*checked*/) { uiEventStream_->send(event); } void QtMainWindow::handleChatUserActionTriggered(bool /*checked*/) { boost::shared_ptr<UIEvent> event(new RequestChatWithUserDialogUIEvent()); uiEventStream_->send(event); } void QtMainWindow::handleSignOutAction() { + loginMenus_.generalMenu->removeAction(toggleRequestDeliveryReceipts_); onSignOutRequest(); } void QtMainWindow::handleEditProfileAction() { uiEventStream_->send(boost::make_shared<RequestProfileEditorUIEvent>()); } void QtMainWindow::handleJoinMUCAction() { uiEventStream_->send(boost::make_shared<RequestJoinMUCUIEvent>()); @@ -206,18 +219,22 @@ void QtMainWindow::handleJoinMUCAction() { void QtMainWindow::handleStatusChanged(StatusShow::Type showType, const QString &statusMessage) { onChangeStatusRequest(showType, Q2PSTRING(statusMessage)); } void QtMainWindow::handleUIEvent(boost::shared_ptr<UIEvent> event) { boost::shared_ptr<ToggleShowOfflineUIEvent> toggleEvent = boost::dynamic_pointer_cast<ToggleShowOfflineUIEvent>(event); if (toggleEvent) { handleShowOfflineToggled(toggleEvent->getShow()); } + boost::shared_ptr<ToggleRequestDeliveryReceiptsUIEvent> deliveryReceiptEvent = boost::dynamic_pointer_cast<ToggleRequestDeliveryReceiptsUIEvent>(event); + if (deliveryReceiptEvent) { + toggleRequestDeliveryReceipts_->setChecked(deliveryReceiptEvent->getEnabled()); + } } void QtMainWindow::handleShowOfflineToggled(bool state) { if (state != lastOfflineState_) { lastOfflineState_ = state; showOfflineAction_->setChecked(state); uiEventStream_->onUIEvent(boost::shared_ptr<UIEvent>(new ToggleShowOfflineUIEvent(state))); } } diff --git a/Swift/QtUI/QtMainWindow.h b/Swift/QtUI/QtMainWindow.h index afcb57c..3c8bdec 100644 --- a/Swift/QtUI/QtMainWindow.h +++ b/Swift/QtUI/QtMainWindow.h @@ -7,18 +7,19 @@ #pragma once #include <QWidget> #include <QMenu> #include <QList> #include "Swift/Controllers/UIInterfaces/MainWindow.h" #include "Swift/QtUI/QtRosterHeader.h" #include "Swift/QtUI/EventViewer/QtEventWindow.h" #include "Swift/QtUI/ChatList/QtChatListWindow.h" +#include "Swift/QtUI/QtLoginWindow.h" #include <vector> class QComboBox; class QLineEdit; class QPushButton; class QToolBar; class QAction; class QMenu; @@ -29,19 +30,19 @@ namespace Swift { class TreeWidget; class UIEventStream; class QtTabWidget; class QtSettingsProvider; class QtUIPreferences; class QtMainWindow : public QWidget, public MainWindow { Q_OBJECT public: - QtMainWindow(QtSettingsProvider*, UIEventStream* eventStream, QtUIPreferences* uiPreferences); + QtMainWindow(QtSettingsProvider*, UIEventStream* eventStream, QtUIPreferences* uiPreferences, QtLoginWindow::QtMenus loginMenus); virtual ~QtMainWindow(); std::vector<QMenu*> getMenus() {return menus_;} void setMyNick(const std::string& name); void setMyJID(const JID& jid); void setMyAvatarPath(const std::string& path); void setMyStatusText(const std::string& status); void setMyStatusType(StatusShow::Type type); void setConnecting(); QtEventWindow* getEventWindow(); @@ -56,28 +57,31 @@ namespace Swift { void handleSignOutAction(); void handleEditProfileAction(); void handleAddUserActionTriggered(bool checked); void handleChatUserActionTriggered(bool checked); void handleAdHocActionTriggered(bool checked); void handleEventCountUpdated(int count); void handleChatCountUpdated(int count); void handleEditProfileRequest(); void handleTabChanged(int index); + void handleToggleRequestDeliveryReceipts(bool enabled); private: QtSettingsProvider* settings_; + QtLoginWindow::QtMenus loginMenus_; std::vector<QMenu*> menus_; QtRosterWidget* treeWidget_; QtRosterHeader* meView_; QAction* addUserAction_; QAction* editUserAction_; QAction* chatUserAction_; QAction* showOfflineAction_; + QAction* toggleRequestDeliveryReceipts_; QMenu* serverAdHocMenu_; QtTabWidget* tabs_; QWidget* contactsTabWidget_; QWidget* eventsTabWidget_; QtEventWindow* eventWindow_; QtChatListWindow* chatListWindow_; UIEventStream* uiEventStream_; bool lastOfflineState_; std::vector<DiscoItems::Item> serverAdHocCommands_; diff --git a/Swift/QtUI/QtUIFactory.cpp b/Swift/QtUI/QtUIFactory.cpp index 8a026f2..88da781 100644 --- a/Swift/QtUI/QtUIFactory.cpp +++ b/Swift/QtUI/QtUIFactory.cpp @@ -49,19 +49,19 @@ FileTransferListWidget* QtUIFactory::createFileTransferListWidget() { tabs->addTab(widget); if (!tabs->isVisible()) { tabs->show(); } widget->show(); return widget; } MainWindow* QtUIFactory::createMainWindow(UIEventStream* eventStream) { - lastMainWindow = new QtMainWindow(settings, eventStream, uiPreferences); + lastMainWindow = new QtMainWindow(settings, eventStream, uiPreferences, loginWindow->getMenus()); return lastMainWindow; } LoginWindow* QtUIFactory::createLoginWindow(UIEventStream* eventStream) { loginWindow = new QtLoginWindow(eventStream, eagleMode); if (netbookSplitter) { netbookSplitter->insertWidget(0, loginWindow); } connect(systemTray, SIGNAL(clicked()), loginWindow, SLOT(bringToFront())); diff --git a/Swift/QtUI/Swift.qrc b/Swift/QtUI/Swift.qrc index d2798e4..61d8cc0 100644 --- a/Swift/QtUI/Swift.qrc +++ b/Swift/QtUI/Swift.qrc @@ -5,18 +5,20 @@ <file alias="logo-chat-16.png">../resources/logo/logo-chat-16.png</file> <file alias="logo-shaded-text.256.png">../resources/logo/logo-shaded-text.256.png</file> <file alias="icons/online.png">../resources/icons/online.png</file> <file alias="icons/connecting.mng">../resources/icons/connecting.mng</file> <file alias="icons/away.png">../resources/icons/away.png</file> <file alias="icons/dnd.png">../resources/icons/dnd.png</file> <file alias="icons/offline.png">../resources/icons/offline.png</file> <file alias="icons/certificate.png">../resources/icons/certificate.png</file> <file alias="icons/error.png">../resources/icons/error.png</file> + <file alias="icons/warn.png">../resources/icons/warn.png</file> + <file alias="icons/check.png">../resources/icons/check.png</file> <file alias="icons/throbber.gif">../resources/icons/throbber.gif</file> <file alias="icons/avatar.png">../resources/icons/avatar.png</file> <file alias="icons/no-avatar.png">../resources/icons/no-avatar.png</file> <file alias="icons/tray-standard.png">../resources/icons/tray-standard.png</file> <file alias="icons/new-chat.png">../resources/icons/new-chat.png</file> <file alias="icons/actions.png">../resources/icons/actions.png</file> <file alias="COPYING">../../COPYING</file> </qresource> </RCC> |