summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin Smith <git@kismith.co.uk>2010-09-03 15:07:47 (GMT)
committerKevin Smith <git@kismith.co.uk>2010-09-03 19:06:29 (GMT)
commita0185934b0c929622c5526b84235b86cd44aad1d (patch)
tree2b377a5e8754c35e1a40fe7405dd75804e66fd73
parentfde15d66a75334b23ca8bbd56b44e33893c813c4 (diff)
downloadswift-a0185934b0c929622c5526b84235b86cd44aad1d.zip
swift-a0185934b0c929622c5526b84235b86cd44aad1d.tar.bz2
XEP-0198 Ack support in the UI
Resolves: #7
-rw-r--r--Swift/Controllers/Chat/ChatController.cpp30
-rw-r--r--Swift/Controllers/Chat/ChatController.h5
-rw-r--r--Swift/Controllers/Chat/ChatControllerBase.cpp8
-rw-r--r--Swift/Controllers/Chat/ChatControllerBase.h8
-rw-r--r--Swift/Controllers/Chat/ChatsManager.cpp2
-rw-r--r--Swift/Controllers/Chat/ChatsManager.h2
-rw-r--r--Swift/Controllers/UIInterfaces/ChatWindow.h12
-rw-r--r--Swift/Controllers/UnitTest/MockChatWindow.h5
-rw-r--r--Swift/QtUI/MessageSnippet.cpp5
-rw-r--r--Swift/QtUI/MessageSnippet.h2
-rw-r--r--Swift/QtUI/QtChatView.cpp9
-rw-r--r--Swift/QtUI/QtChatView.h1
-rw-r--r--Swift/QtUI/QtChatWindow.cpp24
-rw-r--r--Swift/QtUI/QtChatWindow.h10
-rw-r--r--Swift/QtUI/Swift.qrc1
-rw-r--r--Swift/resources/icons/throbber.gifbin0 -> 673 bytes
-rw-r--r--Swiften/Client/Client.h1
-rw-r--r--Swiften/Client/DummyStanzaChannel.h4
-rw-r--r--Swiften/Client/StanzaChannel.h2
19 files changed, 102 insertions, 29 deletions
diff --git a/Swift/Controllers/Chat/ChatController.cpp b/Swift/Controllers/Chat/ChatController.cpp
index 52288c2..9154b9a 100644
--- a/Swift/Controllers/Chat/ChatController.cpp
+++ b/Swift/Controllers/Chat/ChatController.cpp
@@ -12,6 +12,7 @@
#include "Swiften/Chat/ChatStateNotifier.h"
#include "Swiften/Chat/ChatStateMessageSender.h"
#include "Swiften/Chat/ChatStateTracker.h"
+#include "Swiften/Client/StanzaChannel.h"
#include "Swift/Controllers/UIInterfaces/ChatWindow.h"
#include "Swift/Controllers/UIInterfaces/ChatWindowFactory.h"
#include "Swift/Controllers/NickResolver.h"
@@ -32,6 +33,7 @@ ChatController::ChatController(const JID& self, StanzaChannel* stanzaChannel, IQ
nickResolver_ = nickResolver;
presenceOracle_->onPresenceChange.connect(boost::bind(&ChatController::handlePresenceChange, this, _1, _2));
chatStateTracker_->onChatStateChange.connect(boost::bind(&ChatWindow::setContactChatState, chatWindow_, _1));
+ stanzaChannel_->onStanzaAcked.connect(boost::bind(&ChatController::handleStanzaAcked, this, _1));
String nick = nickResolver_->jidToNick(toJID_);
chatWindow_->setName(nick);
String startMessage("Starting chat with " + nick);
@@ -43,6 +45,7 @@ ChatController::ChatController(const JID& self, StanzaChannel* stanzaChannel, IQ
chatWindow_->addSystemMessage(startMessage);
chatWindow_->onUserTyping.connect(boost::bind(&ChatStateNotifier::setUserIsTyping, chatStateNotifier_));
chatWindow_->onUserCancelsTyping.connect(boost::bind(&ChatStateNotifier::userCancelledNewMessage, chatStateNotifier_));
+
}
ChatController::~ChatController() {
@@ -80,12 +83,35 @@ void ChatController::preSendMessageRequest(boost::shared_ptr<Message> message) {
}
}
-void ChatController::postSendMessage(const String& body) {
- addMessage(body, "me", true, labelsEnabled_ ? chatWindow_->getSelectedSecurityLabel() : boost::optional<SecurityLabel>(), String(avatarManager_->getAvatarPath(selfJID_).string()), boost::posix_time::microsec_clock::universal_time());
+void ChatController::postSendMessage(const String& body, boost::shared_ptr<Stanza> sentStanza) {
+ String id = addMessage(body, "me", true, labelsEnabled_ ? chatWindow_->getSelectedSecurityLabel() : boost::optional<SecurityLabel>(), String(avatarManager_->getAvatarPath(selfJID_).string()), boost::posix_time::microsec_clock::universal_time());
+ if (stanzaChannel_->getStreamManagementEnabled()) {
+ chatWindow_->setAckState(id, ChatWindow::Pending);
+ unackedStanzas_[sentStanza] = id;
+ }
lastWasPresence_ = false;
chatStateNotifier_->userSentMessage();
}
+void ChatController::handleStanzaAcked(boost::shared_ptr<Stanza> stanza) {
+ String id = unackedStanzas_[stanza];
+ if (id != "") {
+ chatWindow_->setAckState(id, ChatWindow::Received);
+ }
+ unackedStanzas_.erase(unackedStanzas_.find(stanza));
+}
+
+void ChatController::setEnabled(bool enabled) {
+ if (!enabled) {
+ std::map<boost::shared_ptr<Stanza>, String>::iterator it = unackedStanzas_.begin();
+ for ( ; it != unackedStanzas_.end(); it++) {
+ chatWindow_->setAckState(it->second, ChatWindow::Failed);
+ }
+ unackedStanzas_.clear();
+ }
+ ChatControllerBase::setEnabled(enabled);
+}
+
String ChatController::senderDisplayNameFromMessage(const JID& from) {
return nickResolver_->jidToNick(from);
}
diff --git a/Swift/Controllers/Chat/ChatController.h b/Swift/Controllers/Chat/ChatController.h
index d833094..971fca9 100644
--- a/Swift/Controllers/Chat/ChatController.h
+++ b/Swift/Controllers/Chat/ChatController.h
@@ -20,16 +20,18 @@ namespace Swift {
ChatController(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &contact, NickResolver* nickResolver, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool isInMUC, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController);
virtual ~ChatController();
virtual void setToJID(const JID& jid);
+ virtual void setEnabled(bool enabled);
private:
void handlePresenceChange(boost::shared_ptr<Presence> newPresence, boost::shared_ptr<Presence> previousPresence);
String getStatusChangeString(boost::shared_ptr<Presence> presence);
bool isIncomingMessageFromMe(boost::shared_ptr<Message> message);
- void postSendMessage(const String &body);
+ void postSendMessage(const String &body, boost::shared_ptr<Stanza> sentStanza);
void preHandleIncomingMessage(boost::shared_ptr<MessageEvent> messageEvent);
void preSendMessageRequest(boost::shared_ptr<Message>);
String senderDisplayNameFromMessage(const JID& from);
virtual boost::optional<boost::posix_time::ptime> getMessageTimestamp(boost::shared_ptr<Message>) const;
+ void handleStanzaAcked(boost::shared_ptr<Stanza> stanza);
private:
NickResolver* nickResolver_;
@@ -39,6 +41,7 @@ namespace Swift {
ChatStateTracker* chatStateTracker_;
bool isInMUC_;
bool lastWasPresence_;
+ std::map<boost::shared_ptr<Stanza>, String> unackedStanzas_;
};
}
#endif
diff --git a/Swift/Controllers/Chat/ChatControllerBase.cpp b/Swift/Controllers/Chat/ChatControllerBase.cpp
index e38d12d..b7dd1c0 100644
--- a/Swift/Controllers/Chat/ChatControllerBase.cpp
+++ b/Swift/Controllers/Chat/ChatControllerBase.cpp
@@ -79,7 +79,7 @@ void ChatControllerBase::handleSendMessageRequest(const String &body) {
message->addPayload(boost::shared_ptr<Delay>(new Delay(now, selfJID_)));
}
stanzaChannel_->sendMessage(message);
- postSendMessage(message->getBody());
+ postSendMessage(message->getBody(), boost::dynamic_pointer_cast<Stanza>(message));
}
void ChatControllerBase::handleSecurityLabelsCatalogResponse(boost::shared_ptr<SecurityLabelsCatalog> catalog, const boost::optional<ErrorPayload>& error) {
@@ -106,11 +106,11 @@ void ChatControllerBase::activateChatWindow() {
chatWindow_->activate();
}
-void ChatControllerBase::addMessage(const String& message, const String& senderName, bool senderIsSelf, const boost::optional<SecurityLabel>& label, const String& avatarPath, const boost::posix_time::ptime& time) {
+String ChatControllerBase::addMessage(const String& message, const String& senderName, bool senderIsSelf, const boost::optional<SecurityLabel>& label, const String& avatarPath, const boost::posix_time::ptime& time) {
if (message.beginsWith("/me ")) {
- chatWindow_->addAction(message.getSplittedAtFirst(' ').second, senderName, senderIsSelf, label, avatarPath, time);
+ return chatWindow_->addAction(message.getSplittedAtFirst(' ').second, senderName, senderIsSelf, label, avatarPath, time);
} else {
- chatWindow_->addMessage(message, senderName, senderIsSelf, label, avatarPath, time);
+ return chatWindow_->addMessage(message, senderName, senderIsSelf, label, avatarPath, time);
}
}
diff --git a/Swift/Controllers/Chat/ChatControllerBase.h b/Swift/Controllers/Chat/ChatControllerBase.h
index 61d0ab7..2466690 100644
--- a/Swift/Controllers/Chat/ChatControllerBase.h
+++ b/Swift/Controllers/Chat/ChatControllerBase.h
@@ -15,6 +15,7 @@
#include <boost/optional.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
+#include "Swiften/Elements/Stanza.h"
#include "Swiften/Base/String.h"
#include "Swiften/Elements/DiscoInfo.h"
#include "Swiften/Events/MessageEvent.h"
@@ -40,13 +41,16 @@ namespace Swift {
void activateChatWindow();
void setAvailableServerFeatures(boost::shared_ptr<DiscoInfo> info);
void handleIncomingMessage(boost::shared_ptr<MessageEvent> message);
- void addMessage(const String& message, const String& senderName, bool senderIsSelf, const boost::optional<SecurityLabel>& label, const String& avatarPath, const boost::posix_time::ptime& time);
+ String addMessage(const String& message, const String& senderName, bool senderIsSelf, const boost::optional<SecurityLabel>& label, const String& avatarPath, const boost::posix_time::ptime& time);
virtual void setEnabled(bool enabled);
virtual void setToJID(const JID& jid) {toJID_ = jid;};
protected:
ChatControllerBase(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &toJID, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController);
- virtual void postSendMessage(const String&) {};
+ /**
+ * Pass the Message appended, and the stanza used to send it.
+ */
+ virtual void postSendMessage(const String&, boost::shared_ptr<Stanza>) {};
virtual String senderDisplayNameFromMessage(const JID& from) = 0;
virtual bool isIncomingMessageFromMe(boost::shared_ptr<Message>) = 0;
virtual void preHandleIncomingMessage(boost::shared_ptr<MessageEvent>) {};
diff --git a/Swift/Controllers/Chat/ChatsManager.cpp b/Swift/Controllers/Chat/ChatsManager.cpp
index dfe75d6..acc5e1d 100644
--- a/Swift/Controllers/Chat/ChatsManager.cpp
+++ b/Swift/Controllers/Chat/ChatsManager.cpp
@@ -8,8 +8,6 @@
#include <boost/bind.hpp>
-#include "Swiften/Client/Client.h"
-
#include "Swift/Controllers/Chat/ChatController.h"
#include "Swift/Controllers/EventController.h"
#include "Swift/Controllers/Chat/MUCController.h"
diff --git a/Swift/Controllers/Chat/ChatsManager.h b/Swift/Controllers/Chat/ChatsManager.h
index d7a6275..3efd507 100644
--- a/Swift/Controllers/Chat/ChatsManager.h
+++ b/Swift/Controllers/Chat/ChatsManager.h
@@ -61,7 +61,7 @@ namespace Swift {
EventController* eventController_;
JID jid_;
StanzaChannel* stanzaChannel_;
- IQRouter* iqRouter_;;
+ IQRouter* iqRouter_;
ChatWindowFactory* chatWindowFactory_;
NickResolver* nickResolver_;
PresenceOracle* presenceOracle_;
diff --git a/Swift/Controllers/UIInterfaces/ChatWindow.h b/Swift/Controllers/UIInterfaces/ChatWindow.h
index 4d00dca..1ee632c 100644
--- a/Swift/Controllers/UIInterfaces/ChatWindow.h
+++ b/Swift/Controllers/UIInterfaces/ChatWindow.h
@@ -25,11 +25,18 @@ namespace Swift {
class ChatWindow {
public:
+ enum AckState {Pending, Received, Failed};
ChatWindow() {}
virtual ~ChatWindow() {};
- virtual void addMessage(const String& message, const String& senderName, bool senderIsSelf, const boost::optional<SecurityLabel>& label, const String& avatarPath, const boost::posix_time::ptime& time) = 0;
- virtual void addAction(const String& message, const String& senderName, bool senderIsSelf, const boost::optional<SecurityLabel>& label, const String& avatarPath, const boost::posix_time::ptime& time) = 0;
+ /** Add message to window.
+ * @return id of added message (for acks).
+ */
+ virtual String addMessage(const String& message, const String& senderName, bool senderIsSelf, const boost::optional<SecurityLabel>& label, const String& avatarPath, const boost::posix_time::ptime& time) = 0;
+ /** Adds action to window.
+ * @return id of added message (for acks);
+ */
+ virtual String addAction(const String& message, const String& senderName, bool senderIsSelf, const boost::optional<SecurityLabel>& label, const String& avatarPath, const boost::posix_time::ptime& time) = 0;
virtual void addSystemMessage(const String& message) = 0;
virtual void addPresenceMessage(const String& message) = 0;
virtual void addErrorMessage(const String& message) = 0;
@@ -49,6 +56,7 @@ namespace Swift {
virtual void setRosterModel(Roster* model) = 0;
virtual void setTabComplete(TabComplete* completer) = 0;
virtual void replaceLastMessage(const String& message) = 0;
+ virtual void setAckState(const String& id, AckState state) = 0;
boost::signal<void ()> onClosed;
boost::signal<void ()> onAllMessagesRead;
diff --git a/Swift/Controllers/UnitTest/MockChatWindow.h b/Swift/Controllers/UnitTest/MockChatWindow.h
index 822a128..4e7a117 100644
--- a/Swift/Controllers/UnitTest/MockChatWindow.h
+++ b/Swift/Controllers/UnitTest/MockChatWindow.h
@@ -14,8 +14,8 @@ namespace Swift {
MockChatWindow() {};
virtual ~MockChatWindow();
- virtual void addMessage(const String& message, const String& /*senderName*/, bool /*senderIsSelf*/, const boost::optional<SecurityLabel>& /*label*/, const String& /*avatarPath*/, const boost::posix_time::ptime&) {lastMessageBody_ = message;};
- virtual void addAction(const String& message, const String& /*senderName*/, bool /*senderIsSelf*/, const boost::optional<SecurityLabel>& /*label*/, const String& /*avatarPath*/, const boost::posix_time::ptime&) {lastMessageBody_ = message;};
+ virtual String addMessage(const String& message, const String& /*senderName*/, bool /*senderIsSelf*/, const boost::optional<SecurityLabel>& /*label*/, const String& /*avatarPath*/, const boost::posix_time::ptime&) {lastMessageBody_ = message; return "";};
+ virtual String addAction(const String& message, const String& /*senderName*/, bool /*senderIsSelf*/, const boost::optional<SecurityLabel>& /*label*/, const String& /*avatarPath*/, const boost::posix_time::ptime&) {lastMessageBody_ = message; return "";};
virtual void addSystemMessage(const String& /*message*/) {};
virtual void addErrorMessage(const String& /*message*/) {};
virtual void addPresenceMessage(const String& /*message*/) {};
@@ -34,6 +34,7 @@ namespace Swift {
virtual void setRosterModel(Roster* /*roster*/) {};
virtual void setTabComplete(TabComplete*) {};
virtual void replaceLastMessage(const Swift::String&) {};
+ void setAckState(const String& /*id*/, AckState /*state*/) {};
boost::signal<void ()> onClosed;
boost::signal<void ()> onAllMessagesRead;
diff --git a/Swift/QtUI/MessageSnippet.cpp b/Swift/QtUI/MessageSnippet.cpp
index 0159386..1c8ddca 100644
--- a/Swift/QtUI/MessageSnippet.cpp
+++ b/Swift/QtUI/MessageSnippet.cpp
@@ -11,7 +11,7 @@
namespace Swift {
-MessageSnippet::MessageSnippet(const QString& message, const QString& sender, const QDateTime& time, const QString& iconURI, bool isIncoming, bool appendToPrevious, QtChatTheme* theme) : ChatSnippet(appendToPrevious) {
+MessageSnippet::MessageSnippet(const QString& message, const QString& sender, const QDateTime& time, const QString& iconURI, bool isIncoming, bool appendToPrevious, QtChatTheme* theme, const QString& id) : ChatSnippet(appendToPrevious) {
if (isIncoming) {
if (appendToPrevious) {
content_ = theme->getIncomingNextContent();
@@ -29,10 +29,11 @@ MessageSnippet::MessageSnippet(const QString& message, const QString& sender, co
}
}
- content_.replace("%message%", "<span class='swift_message'>" + escape(message) + "</span>");
+ content_.replace("%message%", "<span class='swift_ack'></span><span class='swift_message'>" + escape(message) + "</span>");
content_.replace("%sender%", escape(sender));
content_.replace("%time%", "<span class='swift_time'>" + escape(time.toString("h:mm")) + "</span>");
content_.replace("%userIconPath%", escape(iconURI));
+ content_ = "<div id='" + id + "'>" + content_ + "</div>";
}
MessageSnippet::~MessageSnippet() {
diff --git a/Swift/QtUI/MessageSnippet.h b/Swift/QtUI/MessageSnippet.h
index 4918c19..c7425e9 100644
--- a/Swift/QtUI/MessageSnippet.h
+++ b/Swift/QtUI/MessageSnippet.h
@@ -15,7 +15,7 @@ class QDateTime;
namespace Swift {
class MessageSnippet : public ChatSnippet {
public:
- MessageSnippet(const QString& message, const QString& sender, const QDateTime& time, const QString& iconURI, bool isIncoming, bool appendToPrevious, QtChatTheme* theme);
+ MessageSnippet(const QString& message, const QString& sender, const QDateTime& time, const QString& iconURI, bool isIncoming, bool appendToPrevious, QtChatTheme* theme, const QString& id);
virtual ~MessageSnippet();
const QString& getContent() const {
return content_;
diff --git a/Swift/QtUI/QtChatView.cpp b/Swift/QtUI/QtChatView.cpp
index d48365b..145371f 100644
--- a/Swift/QtUI/QtChatView.cpp
+++ b/Swift/QtUI/QtChatView.cpp
@@ -129,6 +129,15 @@ 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);
+}
+
bool QtChatView::isScrolledToBottom() const {
return webPage_->mainFrame()->scrollBarValue(Qt::Vertical) == webPage_->mainFrame()->scrollBarMaximum(Qt::Vertical);
}
diff --git a/Swift/QtUI/QtChatView.h b/Swift/QtUI/QtChatView.h
index ce1f8bc..e60c92f 100644
--- a/Swift/QtUI/QtChatView.h
+++ b/Swift/QtUI/QtChatView.h
@@ -31,6 +31,7 @@ namespace Swift {
void replaceLastMessage(const QString& newMessage);
void replaceLastMessage(const QString& newMessage, const QString& note);
bool isScrolledToBottom() const;
+ void setAckXML(const QString& id, const QString& xml);
signals:
void gotFocus();
diff --git a/Swift/QtUI/QtChatWindow.cpp b/Swift/QtUI/QtChatWindow.cpp
index 70bde4b..2955ee4 100644
--- a/Swift/QtUI/QtChatWindow.cpp
+++ b/Swift/QtUI/QtChatWindow.cpp
@@ -245,11 +245,11 @@ void QtChatWindow::updateTitleWithUnreadCount() {
emit titleUpdated();
}
-void QtChatWindow::addMessage(const String &message, const String &senderName, bool senderIsSelf, const boost::optional<SecurityLabel>& label, const String& avatarPath, const boost::posix_time::ptime& time) {
- addMessage(message, senderName, senderIsSelf, label, avatarPath, "", time);
+String QtChatWindow::addMessage(const String &message, const String &senderName, bool senderIsSelf, const boost::optional<SecurityLabel>& label, const String& avatarPath, const boost::posix_time::ptime& time) {
+ return addMessage(message, senderName, senderIsSelf, label, avatarPath, "", time);
}
-void QtChatWindow::addMessage(const String &message, const String &senderName, bool senderIsSelf, const boost::optional<SecurityLabel>& label, const String& avatarPath, const QString& style, const boost::posix_time::ptime& time) {
+String QtChatWindow::addMessage(const String &message, const String &senderName, bool senderIsSelf, const boost::optional<SecurityLabel>& label, const String& avatarPath, const QString& style, const boost::posix_time::ptime& time) {
if (isWidgetSelected()) {
onAllMessagesRead();
}
@@ -268,20 +268,32 @@ void QtChatWindow::addMessage(const String &message, const String &senderName, b
bool appendToPrevious = !previousMessageWasSystem_ && !previousMessageWasPresence_ && ((senderIsSelf && previousMessageWasSelf_) || (!senderIsSelf && !previousMessageWasSelf_ && previousSenderName_ == P2QSTRING(senderName)));
QString qAvatarPath = avatarPath.isEmpty() ? "qrc:/icons/avatar.png" : QUrl::fromLocalFile(P2QSTRING(avatarPath)).toEncoded();
- messageLog_->addMessage(boost::shared_ptr<ChatSnippet>(new MessageSnippet(htmlString, Qt::escape(P2QSTRING(senderName)), B2QDATE(time), qAvatarPath, senderIsSelf, appendToPrevious, theme_)));
+ String id = id_.generateID();
+ messageLog_->addMessage(boost::shared_ptr<ChatSnippet>(new MessageSnippet(htmlString, Qt::escape(P2QSTRING(senderName)), B2QDATE(time), qAvatarPath, senderIsSelf, appendToPrevious, theme_, P2QSTRING(id))));
previousMessageWasSelf_ = senderIsSelf;
previousSenderName_ = P2QSTRING(senderName);
previousMessageWasSystem_ = false;
previousMessageWasPresence_ = false;
+ return id;
+}
+
+void QtChatWindow::setAckState(String const& id, ChatWindow::AckState state) {
+ QString xml;
+ switch (state) {
+ case ChatWindow::Pending: xml = "<img src='qrc:/icons/throbber.gif' alt='This message has not been received by your server yet.'/>"; break;
+ case ChatWindow::Received: xml = ""; break;
+ case ChatWindow::Failed: xml = "<img src='qrc:/icons/error.png' alt='This message may not have been transmitted.'/>"; break;
+ }
+ messageLog_->setAckXML(P2QSTRING(id), xml);
}
int QtChatWindow::getCount() {
return unreadCount_;
}
-void QtChatWindow::addAction(const String &message, const String &senderName, bool senderIsSelf, const boost::optional<SecurityLabel>& label, const String& avatarPath, const boost::posix_time::ptime& time) {
- addMessage(" *" + message + "*", senderName, senderIsSelf, label, avatarPath, "font-style:italic ", time);
+String QtChatWindow::addAction(const String &message, const String &senderName, bool senderIsSelf, const boost::optional<SecurityLabel>& label, const String& avatarPath, const boost::posix_time::ptime& time) {
+ return addMessage(" *" + message + "*", senderName, senderIsSelf, label, avatarPath, "font-style:italic ", time);
}
void QtChatWindow::addErrorMessage(const String& errorMessage) {
diff --git a/Swift/QtUI/QtChatWindow.h b/Swift/QtUI/QtChatWindow.h
index a51b866..333aa44 100644
--- a/Swift/QtUI/QtChatWindow.h
+++ b/Swift/QtUI/QtChatWindow.h
@@ -11,6 +11,8 @@
#include "QtTabbable.h"
+#include "Swiften/Base/IDGenerator.h"
+
class QTextEdit;
class QLineEdit;
class QComboBox;
@@ -28,8 +30,8 @@ namespace Swift {
public:
QtChatWindow(const QString &contact, QtChatTheme* theme, UIEventStream* eventStream);
~QtChatWindow();
- void addMessage(const String &message, const String &senderName, bool senderIsSelf, const boost::optional<SecurityLabel>& label, const String& avatarPath, const boost::posix_time::ptime& time);
- void addAction(const String &message, const String &senderName, bool senderIsSelf, const boost::optional<SecurityLabel>& label, const String& avatarPath, const boost::posix_time::ptime& time);
+ String addMessage(const String &message, const String &senderName, bool senderIsSelf, const boost::optional<SecurityLabel>& label, const String& avatarPath, const boost::posix_time::ptime& time);
+ String addAction(const String &message, const String &senderName, bool senderIsSelf, const boost::optional<SecurityLabel>& label, const String& avatarPath, const boost::posix_time::ptime& time);
void addSystemMessage(const String& message);
void addPresenceMessage(const String& message);
void addErrorMessage(const String& errorMessage);
@@ -50,6 +52,7 @@ namespace Swift {
void setTabComplete(TabComplete* completer);
int getCount();
void replaceLastMessage(const String& message);
+ void setAckState(const String& id, AckState state);
signals:
void geometryChanged();
@@ -71,7 +74,7 @@ namespace Swift {
private:
void updateTitleWithUnreadCount();
void tabComplete();
- void addMessage(const String &message, const String &senderName, bool senderIsSelf, const boost::optional<SecurityLabel>& label, const String& avatarPath, const QString& style, const boost::posix_time::ptime& time);
+ String addMessage(const String &message, const String &senderName, bool senderIsSelf, const boost::optional<SecurityLabel>& label, const String& avatarPath, const QString& style, const boost::posix_time::ptime& time);
int unreadCount_;
bool contactIsTyping_;
@@ -90,6 +93,7 @@ namespace Swift {
bool inputClearing_;
UIEventStream* eventStream_;
bool inputEnabled_;
+ IDGenerator id_;
};
}
diff --git a/Swift/QtUI/Swift.qrc b/Swift/QtUI/Swift.qrc
index 4da687c..6c8e027 100644
--- a/Swift/QtUI/Swift.qrc
+++ b/Swift/QtUI/Swift.qrc
@@ -10,6 +10,7 @@
<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/throbber.gif">../resources/icons/throbber.gif</file>
<file alias="icons/avatar.png">../resources/icons/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>
diff --git a/Swift/resources/icons/throbber.gif b/Swift/resources/icons/throbber.gif
new file mode 100644
index 0000000..d0bce15
--- /dev/null
+++ b/Swift/resources/icons/throbber.gif
Binary files differ
diff --git a/Swiften/Client/Client.h b/Swiften/Client/Client.h
index 10e7c38..57228ef 100644
--- a/Swiften/Client/Client.h
+++ b/Swiften/Client/Client.h
@@ -55,7 +55,6 @@ namespace Swift {
boost::signal<void ()> onConnected;
boost::signal<void (const String&)> onDataRead;
boost::signal<void (const String&)> onDataWritten;
- boost::signal<void (boost::shared_ptr<Stanza>)> onStanzaAcked;
private:
void handleConnectorFinished(boost::shared_ptr<Connection>, Connector::ref);
diff --git a/Swiften/Client/DummyStanzaChannel.h b/Swiften/Client/DummyStanzaChannel.h
index b35ed92..d43d68a 100644
--- a/Swiften/Client/DummyStanzaChannel.h
+++ b/Swiften/Client/DummyStanzaChannel.h
@@ -39,6 +39,10 @@ namespace Swift {
return true;
}
+ virtual bool getStreamManagementEnabled() const {
+ return false;
+ }
+
template<typename T> bool isRequestAtIndex(int index, const JID& jid, IQ::Type type) {
boost::shared_ptr<IQ> iqStanza = boost::dynamic_pointer_cast<IQ>(sentStanzas[index]);
return iqStanza && iqStanza->getType() == type && iqStanza->getTo() == jid && iqStanza->getPayload<T>();
diff --git a/Swiften/Client/StanzaChannel.h b/Swiften/Client/StanzaChannel.h
index bfde05c..09a6db3 100644
--- a/Swiften/Client/StanzaChannel.h
+++ b/Swiften/Client/StanzaChannel.h
@@ -19,8 +19,10 @@ namespace Swift {
virtual void sendMessage(boost::shared_ptr<Message>) = 0;
virtual void sendPresence(boost::shared_ptr<Presence>) = 0;
virtual bool isAvailable() = 0;
+ virtual bool getStreamManagementEnabled() const = 0;
boost::signal<void (boost::shared_ptr<Message>)> onMessageReceived;
boost::signal<void (boost::shared_ptr<Presence>) > onPresenceReceived;
+ boost::signal<void (boost::shared_ptr<Stanza>)> onStanzaAcked;
};
}