diff options
author | Kevin Smith <git@kismith.co.uk> | 2011-05-02 18:38:42 (GMT) |
---|---|---|
committer | Kevin Smith <git@kismith.co.uk> | 2011-08-21 18:08:37 (GMT) |
commit | 8d6a78665b79a382dc1871852ed7bd150263db79 (patch) | |
tree | 1fb975506939049a509cb5ea36350a9236b0b7b3 /Swift/Controllers | |
parent | 7c44520ffa37faa83731edd85dfe8196ba625d52 (diff) | |
download | swift-contrib-8d6a78665b79a382dc1871852ed7bd150263db79.zip swift-contrib-8d6a78665b79a382dc1871852ed7bd150263db79.tar.bz2 |
Warn when sending corrections without support.
Diffstat (limited to 'Swift/Controllers')
-rw-r--r-- | Swift/Controllers/Chat/ChatController.cpp | 35 | ||||
-rw-r--r-- | Swift/Controllers/Chat/ChatController.h | 1 | ||||
-rw-r--r-- | Swift/Controllers/Chat/ChatControllerBase.cpp | 10 | ||||
-rw-r--r-- | Swift/Controllers/Chat/ChatControllerBase.h | 6 | ||||
-rw-r--r-- | Swift/Controllers/Chat/ChatsManager.cpp | 2 | ||||
-rw-r--r-- | Swift/Controllers/Chat/MUCController.cpp | 24 | ||||
-rw-r--r-- | Swift/Controllers/Chat/MUCController.h | 3 | ||||
-rw-r--r-- | Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp | 6 | ||||
-rw-r--r-- | Swift/Controllers/MainController.cpp | 1 | ||||
-rw-r--r-- | Swift/Controllers/UIInterfaces/ChatWindow.h | 13 | ||||
-rw-r--r-- | Swift/Controllers/UnitTest/MockChatWindow.h | 3 |
11 files changed, 87 insertions, 17 deletions
diff --git a/Swift/Controllers/Chat/ChatController.cpp b/Swift/Controllers/Chat/ChatController.cpp index 513b446..f4aa745 100644 --- a/Swift/Controllers/Chat/ChatController.cpp +++ b/Swift/Controllers/Chat/ChatController.cpp @@ -12,16 +12,16 @@ #include <Swift/Controllers/Intl.h> #include <Swiften/Base/format.h> #include <Swiften/Base/Algorithm.h> -#include "Swiften/Avatars/AvatarManager.h" -#include "Swiften/Chat/ChatStateNotifier.h" -#include "Swiften/Chat/ChatStateTracker.h" -#include "Swiften/Client/StanzaChannel.h" -#include "Swiften/Disco/EntityCapsProvider.h" -#include "Swift/Controllers/UIInterfaces/ChatWindow.h" -#include "Swift/Controllers/UIInterfaces/ChatWindowFactory.h" -#include "Swiften/Client/NickResolver.h" -#include "Swift/Controllers/XMPPEvents/EventController.h" +#include <Swiften/Avatars/AvatarManager.h> +#include <Swiften/Chat/ChatStateNotifier.h> +#include <Swiften/Chat/ChatStateTracker.h> +#include <Swiften/Client/StanzaChannel.h> +#include <Swift/Controllers/UIInterfaces/ChatWindow.h> +#include <Swift/Controllers/UIInterfaces/ChatWindowFactory.h> +#include <Swiften/Client/NickResolver.h> +#include <Swift/Controllers/XMPPEvents/EventController.h> #include <Swift/Controllers/StatusUtil.h> +#include <Swiften/Disco/EntityCapsProvider.h> namespace Swift { @@ -29,7 +29,7 @@ namespace Swift { * The controller does not gain ownership of the stanzaChannel, nor the factory. */ ChatController::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, TimerFactory* timerFactory, EntityCapsProvider* entityCapsProvider) - : ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, contact, presenceOracle, avatarManager, useDelayForLatency, eventStream, eventController, timerFactory) { + : ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, contact, presenceOracle, avatarManager, useDelayForLatency, eventStream, eventController, timerFactory, entityCapsProvider) { isInMUC_ = isInMUC; lastWasPresence_ = false; chatStateNotifier_ = new ChatStateNotifier(stanzaChannel, contact, entityCapsProvider); @@ -60,6 +60,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_)); + handleBareJIDCapsChanged(toJID_); } @@ -75,6 +76,19 @@ ChatController::~ChatController() { delete chatStateTracker_; } +void ChatController::handleBareJIDCapsChanged(const JID& /*jid*/) { + DiscoInfo::ref disco = entityCapsProvider_->getCaps(toJID_); + if (disco) { + if (disco->hasFeature(DiscoInfo::MessageCorrectionFeature)) { + chatWindow_->setCorrectionEnabled(ChatWindow::Yes); + } else { + chatWindow_->setCorrectionEnabled(ChatWindow::No); + } + } else { + chatWindow_->setCorrectionEnabled(ChatWindow::Maybe); + } +} + void ChatController::setToJID(const JID& jid) { chatStateNotifier_->setContact(jid); ChatControllerBase::setToJID(jid); @@ -85,6 +99,7 @@ void ChatController::setToJID(const JID& jid) { presence = jid.isBare() ? presenceOracle_->getHighestPriorityPresence(jid.toBare()) : presenceOracle_->getLastPresence(jid); } chatStateNotifier_->setContactIsOnline(presence && presence->getType() == Presence::Available); + handleBareJIDCapsChanged(toJID_); } bool ChatController::isIncomingMessageFromMe(boost::shared_ptr<Message>) { diff --git a/Swift/Controllers/Chat/ChatController.h b/Swift/Controllers/Chat/ChatController.h index 4fafb44..f6b8763 100644 --- a/Swift/Controllers/Chat/ChatController.h +++ b/Swift/Controllers/Chat/ChatController.h @@ -35,6 +35,7 @@ namespace Swift { void handleStanzaAcked(boost::shared_ptr<Stanza> stanza); void dayTicked() {lastWasPresence_ = false;} void handleContactNickChanged(const JID& jid, const std::string& /*oldNick*/); + void handleBareJIDCapsChanged(const JID& jid); private: NickResolver* nickResolver_; diff --git a/Swift/Controllers/Chat/ChatControllerBase.cpp b/Swift/Controllers/Chat/ChatControllerBase.cpp index 5e3c45f..802a7cb 100644 --- a/Swift/Controllers/Chat/ChatControllerBase.cpp +++ b/Swift/Controllers/Chat/ChatControllerBase.cpp @@ -21,6 +21,7 @@ #include "Swiften/Elements/Delay.h" #include "Swiften/Base/foreach.h" #include "Swift/Controllers/XMPPEvents/EventController.h" +#include "Swiften/Disco/EntityCapsProvider.h" #include "Swift/Controllers/UIInterfaces/ChatWindow.h" #include "Swift/Controllers/UIInterfaces/ChatWindowFactory.h" #include "Swiften/Queries/Requests/GetSecurityLabelsCatalogRequest.h" @@ -28,10 +29,11 @@ namespace Swift { -ChatControllerBase::ChatControllerBase(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &toJID, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController, TimerFactory* timerFactory) : selfJID_(self), stanzaChannel_(stanzaChannel), iqRouter_(iqRouter), chatWindowFactory_(chatWindowFactory), toJID_(toJID), labelsEnabled_(false), presenceOracle_(presenceOracle), avatarManager_(avatarManager), useDelayForLatency_(useDelayForLatency), eventController_(eventController), timerFactory_(timerFactory) { +ChatControllerBase::ChatControllerBase(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &toJID, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController, TimerFactory* timerFactory, EntityCapsProvider* entityCapsProvider) : selfJID_(self), stanzaChannel_(stanzaChannel), iqRouter_(iqRouter), chatWindowFactory_(chatWindowFactory), toJID_(toJID), labelsEnabled_(false), presenceOracle_(presenceOracle), avatarManager_(avatarManager), useDelayForLatency_(useDelayForLatency), eventController_(eventController), timerFactory_(timerFactory), entityCapsProvider_(entityCapsProvider) { chatWindow_ = chatWindowFactory_->createChatWindow(toJID, eventStream); chatWindow_->onAllMessagesRead.connect(boost::bind(&ChatControllerBase::handleAllMessagesRead, this)); chatWindow_->onSendMessageRequest.connect(boost::bind(&ChatControllerBase::handleSendMessageRequest, this, _1, _2)); + entityCapsProvider_->onCapsChanged.connect(boost::bind(&ChatControllerBase::handleCapsChanged, this, _1)); setOnline(stanzaChannel->isAvailable() && iqRouter->isAvailable()); createDayChangeTimer(); } @@ -40,6 +42,12 @@ ChatControllerBase::~ChatControllerBase() { delete chatWindow_; } +void ChatControllerBase::handleCapsChanged(const JID& jid) { + if (jid.compare(toJID_, JID::WithoutResource) == 0) { + handleBareJIDCapsChanged(jid); + } +} + void ChatControllerBase::createDayChangeTimer() { if (timerFactory_) { boost::posix_time::ptime now = boost::posix_time::second_clock::local_time(); diff --git a/Swift/Controllers/Chat/ChatControllerBase.h b/Swift/Controllers/Chat/ChatControllerBase.h index 86c1ef2..79d376c 100644 --- a/Swift/Controllers/Chat/ChatControllerBase.h +++ b/Swift/Controllers/Chat/ChatControllerBase.h @@ -35,6 +35,7 @@ namespace Swift { class AvatarManager; class UIEventStream; class EventController; + class EntityCapsProvider; class ChatControllerBase : public boost::bsignals::trackable { public: @@ -52,8 +53,9 @@ namespace Swift { boost::signal<void ()> onUnreadCountChanged; int getUnreadCount(); const JID& getToJID() {return toJID_;} + void handleCapsChanged(const JID& 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, TimerFactory* timerFactory); + ChatControllerBase(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &toJID, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController, TimerFactory* timerFactory, EntityCapsProvider* entityCapsProvider); /** * Pass the Message appended, and the stanza used to send it. @@ -67,6 +69,7 @@ namespace Swift { virtual bool isFromContact(const JID& from); virtual boost::optional<boost::posix_time::ptime> getMessageTimestamp(boost::shared_ptr<Message>) const = 0; virtual void dayTicked() {}; + virtual void handleBareJIDCapsChanged(const JID& jid) = 0; private: IDGenerator idGenerator_; @@ -94,5 +97,6 @@ namespace Swift { EventController* eventController_; boost::shared_ptr<Timer> dateChangeTimer_; TimerFactory* timerFactory_; + EntityCapsProvider* entityCapsProvider_; }; } diff --git a/Swift/Controllers/Chat/ChatsManager.cpp b/Swift/Controllers/Chat/ChatsManager.cpp index 8b8b993..56f7a4c 100644 --- a/Swift/Controllers/Chat/ChatsManager.cpp +++ b/Swift/Controllers/Chat/ChatsManager.cpp @@ -480,7 +480,7 @@ void ChatsManager::handleJoinMUCRequest(const JID &mucJID, const boost::optional } else { std::string nick = nickMaybe ? nickMaybe.get() : jid_.getNode(); MUC::ref muc = mucManager->createMUC(mucJID); - MUCController* controller = new MUCController(jid_, muc, nick, stanzaChannel_, iqRouter_, chatWindowFactory_, presenceOracle_, avatarManager_, uiEventStream_, false, timerFactory_, eventController_); + MUCController* controller = new MUCController(jid_, muc, nick, stanzaChannel_, iqRouter_, chatWindowFactory_, presenceOracle_, avatarManager_, uiEventStream_, false, timerFactory_, eventController_, entityCapsProvider_); mucControllers_[mucJID] = controller; controller->setAvailableServerFeatures(serverDiscoInfo_); controller->onUserLeft.connect(boost::bind(&ChatsManager::handleUserLeftMUC, this, controller)); diff --git a/Swift/Controllers/Chat/MUCController.cpp b/Swift/Controllers/Chat/MUCController.cpp index 93ceb13..aa0a1e7 100644 --- a/Swift/Controllers/Chat/MUCController.cpp +++ b/Swift/Controllers/Chat/MUCController.cpp @@ -30,6 +30,7 @@ #include <Swift/Controllers/Roster/Roster.h> #include <Swift/Controllers/Roster/SetAvatar.h> #include <Swift/Controllers/Roster/SetPresence.h> +#include <Swiften/Disco/EntityCapsProvider.h> #define MUC_JOIN_WARNING_TIMEOUT_MILLISECONDS 60000 @@ -51,8 +52,9 @@ MUCController::MUCController ( UIEventStream* uiEventStream, bool useDelayForLatency, TimerFactory* timerFactory, - EventController* eventController) : - ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, muc->getJID(), presenceOracle, avatarManager, useDelayForLatency, uiEventStream, eventController, timerFactory), muc_(muc), nick_(nick), desiredNick_(nick) { + EventController* eventController, + EntityCapsProvider* entityCapsProvider) : + ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, muc->getJID(), presenceOracle, avatarManager, useDelayForLatency, uiEventStream, eventController, timerFactory, entityCapsProvider), muc_(muc), nick_(nick), desiredNick_(nick) { parting_ = true; joined_ = false; lastWasPresence_ = false; @@ -82,6 +84,7 @@ MUCController::MUCController ( if (avatarManager_ != NULL) { avatarChangedConnection_ = (avatarManager_->onAvatarChanged.connect(boost::bind(&MUCController::handleAvatarChanged, this, _1))); } + handleBareJIDCapsChanged(muc->getJID()); } MUCController::~MUCController() { @@ -94,6 +97,23 @@ MUCController::~MUCController() { delete completer_; } +void MUCController::handleBareJIDCapsChanged(const JID& /*jid*/) { + ChatWindow::Tristate support = ChatWindow::Yes; + bool any = false; + foreach (const std::string& nick, currentOccupants_) { + DiscoInfo::ref disco = entityCapsProvider_->getCaps(toJID_.toBare().toString() + "/" + nick); + if (disco && disco->hasFeature(DiscoInfo::MessageCorrectionFeature)) { + any = true; + } else { + support = ChatWindow::Maybe; + } + } + if (!any) { + support = ChatWindow::No; + } + chatWindow_->setCorrectionEnabled(support); +} + /** * Join the MUC if not already in it. */ diff --git a/Swift/Controllers/Chat/MUCController.h b/Swift/Controllers/Chat/MUCController.h index c6901df..3a79920 100644 --- a/Swift/Controllers/Chat/MUCController.h +++ b/Swift/Controllers/Chat/MUCController.h @@ -41,7 +41,7 @@ namespace Swift { class MUCController : public ChatControllerBase { public: - MUCController(const JID& self, MUC::ref muc, const std::string &nick, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, PresenceOracle* presenceOracle, AvatarManager* avatarManager, UIEventStream* events, bool useDelayForLatency, TimerFactory* timerFactory, EventController* eventController); + MUCController(const JID& self, MUC::ref muc, const std::string &nick, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, PresenceOracle* presenceOracle, AvatarManager* avatarManager, UIEventStream* events, bool useDelayForLatency, TimerFactory* timerFactory, EventController* eventController, EntityCapsProvider* entityCapsProvider); ~MUCController(); boost::signal<void ()> onUserLeft; boost::signal<void ()> onUserJoined; @@ -83,6 +83,7 @@ namespace Swift { bool shouldUpdateJoinParts(); void dayTicked() {lastWasPresence_ = false;} void processUserPart(); + void handleBareJIDCapsChanged(const JID& jid); private: MUC::ref muc_; diff --git a/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp b/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp index 5f5e44d..ad5ceac 100644 --- a/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp +++ b/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp @@ -25,6 +25,7 @@ #include "Swiften/Presence/PresenceOracle.h" #include "Swiften/Network/TimerFactory.h" #include "Swiften/Elements/MUCUserPayload.h" +#include "Swiften/Disco/DummyEntityCapsProvider.h" using namespace Swift; @@ -56,12 +57,14 @@ public: TimerFactory* timerFactory = NULL; window_ = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>(); mucRegistry_ = new MUCRegistry(); + entityCapsProvider_ = new DummyEntityCapsProvider(); muc_ = MUC::ref(new MUC(stanzaChannel_, iqRouter_, directedPresenceSender_, JID("teaparty@rooms.wonderland.lit"), mucRegistry_)); mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(muc_->getJID(), uiEventStream_).Return(window_); - controller_ = new MUCController (self_, muc_, nick_, stanzaChannel_, iqRouter_, chatWindowFactory_, presenceOracle_, avatarManager_, uiEventStream_, false, timerFactory, eventController_); + controller_ = new MUCController (self_, muc_, nick_, stanzaChannel_, iqRouter_, chatWindowFactory_, presenceOracle_, avatarManager_, uiEventStream_, false, timerFactory, eventController_, entityCapsProvider_); }; void tearDown() { + delete entityCapsProvider_; delete controller_; delete eventController_; delete presenceOracle_; @@ -240,6 +243,7 @@ private: UIEventStream* uiEventStream_; MockChatWindow* window_; MUCRegistry* mucRegistry_; + DummyEntityCapsProvider* entityCapsProvider_; }; CPPUNIT_TEST_SUITE_REGISTRATION(MUCControllerTest); diff --git a/Swift/Controllers/MainController.cpp b/Swift/Controllers/MainController.cpp index 92bec85..2690343 100644 --- a/Swift/Controllers/MainController.cpp +++ b/Swift/Controllers/MainController.cpp @@ -288,6 +288,7 @@ void MainController::handleConnected() { discoInfo.addIdentity(DiscoInfo::Identity(CLIENT_NAME, "client", "pc")); discoInfo.addFeature(DiscoInfo::ChatStatesFeature); discoInfo.addFeature(DiscoInfo::SecurityLabelsFeature); + discoInfo.addFeature(DiscoInfo::MessageCorrectionFeature); client_->getDiscoManager()->setCapsNode(CLIENT_NODE); client_->getDiscoManager()->setDiscoInfo(discoInfo); diff --git a/Swift/Controllers/UIInterfaces/ChatWindow.h b/Swift/Controllers/UIInterfaces/ChatWindow.h index f65328d..e84116d 100644 --- a/Swift/Controllers/UIInterfaces/ChatWindow.h +++ b/Swift/Controllers/UIInterfaces/ChatWindow.h @@ -26,6 +26,7 @@ namespace Swift { class ChatWindow { public: enum AckState {Pending, Received, Failed}; + enum Tristate {Yes, No, Maybe}; ChatWindow() {} virtual ~ChatWindow() {}; @@ -48,6 +49,7 @@ namespace Swift { virtual void activate() = 0; virtual void setAvailableSecurityLabels(const std::vector<SecurityLabelsCatalog::Item>& labels) = 0; virtual void setSecurityLabelsEnabled(bool enabled) = 0; + virtual void setCorrectionEnabled(Tristate enabled) = 0; virtual void setUnreadMessageCount(int count) = 0; virtual void convertToMUC() = 0; // virtual TreeWidget *getTreeWidget() = 0; @@ -59,6 +61,16 @@ namespace Swift { virtual void replaceLastMessage(const std::string& message) = 0; virtual void setAckState(const std::string& id, AckState state) = 0; virtual void flash() = 0; + /** + * Set an alert on the window. + * @param alertText Description of alert (required). + * @param buttonText Button text to use (optional, no button is shown if empty). + */ + virtual void setAlert(const std::string& alertText, const std::string& buttonText = "") = 0; + /** + * Removes an alert. + */ + virtual void cancelAlert() = 0; boost::signal<void ()> onClosed; boost::signal<void ()> onAllMessagesRead; @@ -66,6 +78,7 @@ namespace Swift { boost::signal<void ()> onSendCorrectionMessageRequest; boost::signal<void ()> onUserTyping; boost::signal<void ()> onUserCancelsTyping; + boost::signal<void ()> onAlertButtonClicked; }; } #endif diff --git a/Swift/Controllers/UnitTest/MockChatWindow.h b/Swift/Controllers/UnitTest/MockChatWindow.h index a5765fd..7d6828f 100644 --- a/Swift/Controllers/UnitTest/MockChatWindow.h +++ b/Swift/Controllers/UnitTest/MockChatWindow.h @@ -37,6 +37,9 @@ namespace Swift { virtual void replaceMessage(const std::string&, const std::string&, const boost::posix_time::ptime&) {}; void setAckState(const std::string& /*id*/, AckState /*state*/) {}; virtual void flash() {}; + virtual void setAlert(const std::string& /*alertText*/, const std::string& /*buttonText*/) {}; + virtual void cancelAlert() {}; + virtual void setCorrectionEnabled(Tristate /*enabled*/) {} boost::signal<void ()> onClosed; boost::signal<void ()> onAllMessagesRead; |