diff options
Diffstat (limited to 'Swift/Controllers/Chat')
-rw-r--r-- | Swift/Controllers/Chat/ChatController.cpp | 15 | ||||
-rw-r--r-- | Swift/Controllers/Chat/ChatController.h | 5 | ||||
-rw-r--r-- | Swift/Controllers/Chat/ChatControllerBase.cpp | 39 | ||||
-rw-r--r-- | Swift/Controllers/Chat/ChatControllerBase.h | 22 | ||||
-rw-r--r-- | Swift/Controllers/Chat/ChatsManager.cpp | 10 | ||||
-rw-r--r-- | Swift/Controllers/Chat/ChatsManager.h | 4 | ||||
-rw-r--r-- | Swift/Controllers/Chat/MUCController.cpp | 41 | ||||
-rw-r--r-- | Swift/Controllers/Chat/MUCController.h | 8 | ||||
-rw-r--r-- | Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp | 7 | ||||
-rw-r--r-- | Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp | 11 | ||||
-rw-r--r-- | Swift/Controllers/Chat/UnitTest/MockChatListWindow.h | 8 |
11 files changed, 114 insertions, 56 deletions
diff --git a/Swift/Controllers/Chat/ChatController.cpp b/Swift/Controllers/Chat/ChatController.cpp index 16b22fe..0ffef0c 100644 --- a/Swift/Controllers/Chat/ChatController.cpp +++ b/Swift/Controllers/Chat/ChatController.cpp @@ -32,7 +32,7 @@ #include <Swiften/Elements/DeliveryReceipt.h> #include <Swiften/Elements/DeliveryReceiptRequest.h> #include <Swift/Controllers/SettingConstants.h> - +#include <Swift/Controllers/Highlighter.h> #include <Swiften/Base/Log.h> namespace Swift { @@ -40,8 +40,8 @@ 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, bool userWantsReceipts, SettingsProvider* settings, HistoryController* historyController, MUCRegistry* mucRegistry) - : ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, contact, presenceOracle, avatarManager, useDelayForLatency, eventStream, eventController, timerFactory, entityCapsProvider, historyController, mucRegistry), eventStream_(eventStream), userWantsReceipts_(userWantsReceipts), settings_(settings) { +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, bool userWantsReceipts, SettingsProvider* settings, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager) + : ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, contact, presenceOracle, avatarManager, useDelayForLatency, eventStream, eventController, timerFactory, entityCapsProvider, historyController, mucRegistry, highlightManager), eventStream_(eventStream), userWantsReceipts_(userWantsReceipts), settings_(settings) { isInMUC_ = isInMUC; lastWasPresence_ = false; chatStateNotifier_ = new ChatStateNotifier(stanzaChannel, contact, entityCapsProvider); @@ -174,8 +174,11 @@ void ChatController::preHandleIncomingMessage(boost::shared_ptr<MessageEvent> me } } -void ChatController::postHandleIncomingMessage(boost::shared_ptr<MessageEvent> messageEvent) { +void ChatController::postHandleIncomingMessage(boost::shared_ptr<MessageEvent> messageEvent, const HighlightAction& highlight) { eventController_->handleIncomingEvent(messageEvent); + if (!messageEvent->getConcluded()) { + highlighter_->handleHighlightAction(highlight); + } } @@ -211,9 +214,9 @@ void ChatController::postSendMessage(const std::string& body, boost::shared_ptr< boost::shared_ptr<Replace> replace = sentStanza->getPayload<Replace>(); if (replace) { eraseIf(unackedStanzas_, PairSecondEquals<boost::shared_ptr<Stanza>, std::string>(myLastMessageUIID_)); - replaceMessage(body, myLastMessageUIID_, boost::posix_time::microsec_clock::universal_time()); + replaceMessage(body, myLastMessageUIID_, boost::posix_time::microsec_clock::universal_time(), HighlightAction()); } else { - myLastMessageUIID_ = addMessage(body, QT_TRANSLATE_NOOP("", "me"), true, labelsEnabled_ ? chatWindow_->getSelectedSecurityLabel().getLabel() : boost::shared_ptr<SecurityLabel>(), std::string(avatarManager_->getAvatarPath(selfJID_).string()), boost::posix_time::microsec_clock::universal_time()); + myLastMessageUIID_ = addMessage(body, QT_TRANSLATE_NOOP("", "me"), true, labelsEnabled_ ? chatWindow_->getSelectedSecurityLabel().getLabel() : boost::shared_ptr<SecurityLabel>(), std::string(avatarManager_->getAvatarPath(selfJID_).string()), boost::posix_time::microsec_clock::universal_time(), HighlightAction()); } if (stanzaChannel_->getStreamManagementEnabled() && !myLastMessageUIID_.empty() ) { diff --git a/Swift/Controllers/Chat/ChatController.h b/Swift/Controllers/Chat/ChatController.h index 66ec37d..6021ec1 100644 --- a/Swift/Controllers/Chat/ChatController.h +++ b/Swift/Controllers/Chat/ChatController.h @@ -22,10 +22,11 @@ namespace Swift { class FileTransferController; class SettingsProvider; class HistoryController; + class HighlightManager; class ChatController : public ChatControllerBase { public: - 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, bool userWantsReceipts, SettingsProvider* settings, HistoryController* historyController, MUCRegistry* mucRegistry); + 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, bool userWantsReceipts, SettingsProvider* settings, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager); virtual ~ChatController(); virtual void setToJID(const JID& jid); virtual void setOnline(bool online); @@ -45,7 +46,7 @@ namespace Swift { bool isIncomingMessageFromMe(boost::shared_ptr<Message> message); void postSendMessage(const std::string &body, boost::shared_ptr<Stanza> sentStanza); void preHandleIncomingMessage(boost::shared_ptr<MessageEvent> messageEvent); - void postHandleIncomingMessage(boost::shared_ptr<MessageEvent> messageEvent); + void postHandleIncomingMessage(boost::shared_ptr<MessageEvent> messageEvent, const HighlightAction&); void preSendMessageRequest(boost::shared_ptr<Message>); std::string senderDisplayNameFromMessage(const JID& from); virtual boost::optional<boost::posix_time::ptime> getMessageTimestamp(boost::shared_ptr<Message>) const; diff --git a/Swift/Controllers/Chat/ChatControllerBase.cpp b/Swift/Controllers/Chat/ChatControllerBase.cpp index 50709f7..ad7f76a 100644 --- a/Swift/Controllers/Chat/ChatControllerBase.cpp +++ b/Swift/Controllers/Chat/ChatControllerBase.cpp @@ -13,6 +13,7 @@ #include <boost/shared_ptr.hpp> #include <boost/smart_ptr/make_shared.hpp> #include <boost/date_time/posix_time/posix_time.hpp> +#include <boost/numeric/conversion/cast.hpp> #include <boost/algorithm/string.hpp> #include <Swift/Controllers/Intl.h> @@ -30,15 +31,18 @@ #include <Swiften/Queries/Requests/GetSecurityLabelsCatalogRequest.h> #include <Swiften/Avatars/AvatarManager.h> #include <Swift/Controllers/XMPPEvents/MUCInviteEvent.h> +#include <Swift/Controllers/HighlightManager.h> +#include <Swift/Controllers/Highlighter.h> 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, EntityCapsProvider* entityCapsProvider, HistoryController* historyController, MUCRegistry* mucRegistry) : selfJID_(self), stanzaChannel_(stanzaChannel), iqRouter_(iqRouter), chatWindowFactory_(chatWindowFactory), toJID_(toJID), labelsEnabled_(false), presenceOracle_(presenceOracle), avatarManager_(avatarManager), useDelayForLatency_(useDelayForLatency), eventController_(eventController), timerFactory_(timerFactory), entityCapsProvider_(entityCapsProvider), historyController_(historyController), mucRegistry_(mucRegistry) { +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, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager) : selfJID_(self), stanzaChannel_(stanzaChannel), iqRouter_(iqRouter), chatWindowFactory_(chatWindowFactory), toJID_(toJID), labelsEnabled_(false), presenceOracle_(presenceOracle), avatarManager_(avatarManager), useDelayForLatency_(useDelayForLatency), eventController_(eventController), timerFactory_(timerFactory), entityCapsProvider_(entityCapsProvider), historyController_(historyController), mucRegistry_(mucRegistry) { chatWindow_ = chatWindowFactory_->createChatWindow(toJID, eventStream); chatWindow_->onAllMessagesRead.connect(boost::bind(&ChatControllerBase::handleAllMessagesRead, this)); chatWindow_->onSendMessageRequest.connect(boost::bind(&ChatControllerBase::handleSendMessageRequest, this, _1, _2)); chatWindow_->onLogCleared.connect(boost::bind(&ChatControllerBase::handleLogCleared, this)); entityCapsProvider_->onCapsChanged.connect(boost::bind(&ChatControllerBase::handleCapsChanged, this, _1)); + highlighter_ = highlightManager->createHighlighter(); setOnline(stanzaChannel->isAvailable() && iqRouter->isAvailable()); createDayChangeTimer(); } @@ -62,7 +66,7 @@ void ChatControllerBase::createDayChangeTimer() { boost::posix_time::ptime now = boost::posix_time::second_clock::local_time(); boost::posix_time::ptime midnight(now.date() + boost::gregorian::days(1)); long millisecondsUntilMidnight = (midnight - now).total_milliseconds(); - dateChangeTimer_ = boost::shared_ptr<Timer>(timerFactory_->createTimer(millisecondsUntilMidnight)); + dateChangeTimer_ = boost::shared_ptr<Timer>(timerFactory_->createTimer(boost::numeric_cast<int>(millisecondsUntilMidnight))); dateChangeTimer_->onTick.connect(boost::bind(&ChatControllerBase::handleDayChangeTick, this)); dateChangeTimer_->start(); } @@ -112,7 +116,7 @@ void ChatControllerBase::handleAllMessagesRead() { } int ChatControllerBase::getUnreadCount() { - return targetedUnreadMessages_.size(); + return boost::numeric_cast<int>(targetedUnreadMessages_.size()); } void ChatControllerBase::handleSendMessageRequest(const std::string &body, bool isCorrectionMessage) { @@ -175,19 +179,19 @@ void ChatControllerBase::activateChatWindow() { chatWindow_->activate(); } -std::string ChatControllerBase::addMessage(const std::string& message, const std::string& senderName, bool senderIsSelf, const boost::shared_ptr<SecurityLabel> label, const std::string& avatarPath, const boost::posix_time::ptime& time) { +std::string ChatControllerBase::addMessage(const std::string& message, const std::string& senderName, bool senderIsSelf, const boost::shared_ptr<SecurityLabel> label, const std::string& avatarPath, const boost::posix_time::ptime& time, const HighlightAction& highlight) { if (boost::starts_with(message, "/me ")) { - return chatWindow_->addAction(String::getSplittedAtFirst(message, ' ').second, senderName, senderIsSelf, label, avatarPath, time); + return chatWindow_->addAction(String::getSplittedAtFirst(message, ' ').second, senderName, senderIsSelf, label, avatarPath, time, highlight); } else { - return chatWindow_->addMessage(message, senderName, senderIsSelf, label, avatarPath, time); + return chatWindow_->addMessage(message, senderName, senderIsSelf, label, avatarPath, time, highlight); } } -void ChatControllerBase::replaceMessage(const std::string& message, const std::string& id, const boost::posix_time::ptime& time) { +void ChatControllerBase::replaceMessage(const std::string& message, const std::string& id, const boost::posix_time::ptime& time, const HighlightAction& highlight) { if (boost::starts_with(message, "/me ")) { - chatWindow_->replaceWithAction(String::getSplittedAtFirst(message, ' ').second, id, time); + chatWindow_->replaceWithAction(String::getSplittedAtFirst(message, ' ').second, id, time, highlight); } else { - chatWindow_->replaceMessage(message, id, time); + chatWindow_->replaceMessage(message, id, time, highlight); } } @@ -205,6 +209,7 @@ void ChatControllerBase::handleIncomingMessage(boost::shared_ptr<MessageEvent> m } boost::shared_ptr<Message> message = messageEvent->getStanza(); std::string body = message->getBody(); + HighlightAction highlight; if (message->isError()) { std::string errorMessage = str(format(QT_TRANSLATE_NOOP("", "Couldn't send message: %1%")) % getErrorMessage(message->getPayload<ErrorPayload>())); chatWindow_->addErrorMessage(errorMessage); @@ -243,6 +248,11 @@ void ChatControllerBase::handleIncomingMessage(boost::shared_ptr<MessageEvent> m } onActivity(body); + // Highlight + if (!isIncomingMessageFromMe(message)) { + highlight = highlighter_->findAction(body, senderDisplayNameFromMessage(from)); + } + boost::shared_ptr<Replace> replace = message->getPayload<Replace>(); if (replace) { std::string body = message->getBody(); @@ -250,19 +260,19 @@ void ChatControllerBase::handleIncomingMessage(boost::shared_ptr<MessageEvent> m std::map<JID, std::string>::iterator lastMessage; lastMessage = lastMessagesUIID_.find(from); if (lastMessage != lastMessagesUIID_.end()) { - replaceMessage(body, lastMessagesUIID_[from], timeStamp); + replaceMessage(body, lastMessagesUIID_[from], timeStamp, highlight); } } else { - lastMessagesUIID_[from] = addMessage(body, senderDisplayNameFromMessage(from), isIncomingMessageFromMe(message), label, std::string(avatarManager_->getAvatarPath(from).string()), timeStamp); + lastMessagesUIID_[from] = addMessage(body, senderDisplayNameFromMessage(from), isIncomingMessageFromMe(message), label, std::string(avatarManager_->getAvatarPath(from).string()), timeStamp, highlight); } logMessage(body, from, selfJID_, timeStamp, true); } chatWindow_->show(); - chatWindow_->setUnreadMessageCount(unreadMessages_.size()); + chatWindow_->setUnreadMessageCount(boost::numeric_cast<int>(unreadMessages_.size())); onUnreadCountChanged(); - postHandleIncomingMessage(messageEvent); + postHandleIncomingMessage(messageEvent, highlight); } std::string ChatControllerBase::getErrorMessage(boost::shared_ptr<ErrorPayload> error) { @@ -296,13 +306,14 @@ std::string ChatControllerBase::getErrorMessage(boost::shared_ptr<ErrorPayload> case ErrorPayload::UnexpectedRequest: return QT_TRANSLATE_NOOP("", "Unexpected request"); } } + assert(false); return defaultMessage; } void ChatControllerBase::handleGeneralMUCInvitation(MUCInviteEvent::ref event) { unreadMessages_.push_back(event); chatWindow_->show(); - chatWindow_->setUnreadMessageCount(unreadMessages_.size()); + chatWindow_->setUnreadMessageCount(boost::numeric_cast<int>(unreadMessages_.size())); onUnreadCountChanged(); chatWindow_->addMUCInvitation(senderDisplayNameFromMessage(event->getInviter()), event->getRoomJID(), event->getReason(), event->getPassword(), event->getDirect()); eventController_->handleIncomingEvent(event); diff --git a/Swift/Controllers/Chat/ChatControllerBase.h b/Swift/Controllers/Chat/ChatControllerBase.h index b26af02..baef9e6 100644 --- a/Swift/Controllers/Chat/ChatControllerBase.h +++ b/Swift/Controllers/Chat/ChatControllerBase.h @@ -29,6 +29,7 @@ #include "Swiften/Base/IDGenerator.h" #include <Swift/Controllers/HistoryController.h> #include <Swiften/MUC/MUCRegistry.h> +#include <Swift/Controllers/HighlightManager.h> namespace Swift { class IQRouter; @@ -39,6 +40,8 @@ namespace Swift { class UIEventStream; class EventController; class EntityCapsProvider; + class HighlightManager; + class Highlighter; class ChatControllerBase : public boost::bsignals::trackable { public: @@ -47,11 +50,11 @@ namespace Swift { void activateChatWindow(); void setAvailableServerFeatures(boost::shared_ptr<DiscoInfo> info); void handleIncomingMessage(boost::shared_ptr<MessageEvent> message); - std::string addMessage(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); - void replaceMessage(const std::string& message, const std::string& id, const boost::posix_time::ptime& time); + std::string addMessage(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, const HighlightAction& highlight); + void replaceMessage(const std::string& message, const std::string& id, const boost::posix_time::ptime& time, const HighlightAction& highlight); virtual void setOnline(bool online); virtual void setEnabled(bool enabled); - virtual void setToJID(const JID& jid) {toJID_ = jid;}; + virtual void setToJID(const JID& jid) {toJID_ = jid;} /** Used for determining when something is recent.*/ boost::signal<void (const std::string& /*activity*/)> onActivity; boost::signal<void ()> onUnreadCountChanged; @@ -60,20 +63,20 @@ namespace Swift { 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, EntityCapsProvider* entityCapsProvider, HistoryController* historyController, MUCRegistry* mucRegistry); + 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, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager); /** * Pass the Message appended, and the stanza used to send it. */ - virtual void postSendMessage(const std::string&, boost::shared_ptr<Stanza>) {}; + virtual void postSendMessage(const std::string&, boost::shared_ptr<Stanza>) {} virtual std::string senderDisplayNameFromMessage(const JID& from) = 0; virtual bool isIncomingMessageFromMe(boost::shared_ptr<Message>) = 0; - virtual void preHandleIncomingMessage(boost::shared_ptr<MessageEvent>) {}; - virtual void postHandleIncomingMessage(boost::shared_ptr<MessageEvent>) {}; - virtual void preSendMessageRequest(boost::shared_ptr<Message>) {}; + virtual void preHandleIncomingMessage(boost::shared_ptr<MessageEvent>) {} + virtual void postHandleIncomingMessage(boost::shared_ptr<MessageEvent>, const HighlightAction&) {} + virtual void preSendMessageRequest(boost::shared_ptr<Message>) {} 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 dayTicked() {} virtual void handleBareJIDCapsChanged(const JID& jid) = 0; std::string getErrorMessage(boost::shared_ptr<ErrorPayload>); virtual void setContactIsReceivingPresence(bool /* isReceivingPresence */) {} @@ -116,5 +119,6 @@ namespace Swift { SecurityLabelsCatalog::Item lastLabel_; HistoryController* historyController_; MUCRegistry* mucRegistry_; + Highlighter* highlighter_; }; } diff --git a/Swift/Controllers/Chat/ChatsManager.cpp b/Swift/Controllers/Chat/ChatsManager.cpp index 1e0e9c2..dba8565 100644 --- a/Swift/Controllers/Chat/ChatsManager.cpp +++ b/Swift/Controllers/Chat/ChatsManager.cpp @@ -74,7 +74,8 @@ ChatsManager::ChatsManager( bool eagleMode, SettingsProvider* settings, HistoryController* historyController, - WhiteboardManager* whiteboardManager) : + WhiteboardManager* whiteboardManager, + HighlightManager* highlightManager) : jid_(jid), joinMUCWindowFactory_(joinMUCWindowFactory), useDelayForLatency_(useDelayForLatency), @@ -86,7 +87,8 @@ ChatsManager::ChatsManager( eagleMode_(eagleMode), settings_(settings), historyController_(historyController), - whiteboardManager_(whiteboardManager) { + whiteboardManager_(whiteboardManager), + highlightManager_(highlightManager) { timerFactory_ = timerFactory; eventController_ = eventController; stanzaChannel_ = stanzaChannel; @@ -521,7 +523,7 @@ ChatController* ChatsManager::getChatControllerOrFindAnother(const JID &contact) ChatController* ChatsManager::createNewChatController(const JID& contact) { assert(chatControllers_.find(contact) == chatControllers_.end()); - ChatController* controller = new ChatController(jid_, stanzaChannel_, iqRouter_, chatWindowFactory_, contact, nickResolver_, presenceOracle_, avatarManager_, mucRegistry_->isMUC(contact.toBare()), useDelayForLatency_, uiEventStream_, eventController_, timerFactory_, entityCapsProvider_, userWantsReceipts_, settings_, historyController_, mucRegistry_); + ChatController* controller = new ChatController(jid_, stanzaChannel_, iqRouter_, chatWindowFactory_, contact, nickResolver_, presenceOracle_, avatarManager_, mucRegistry_->isMUC(contact.toBare()), useDelayForLatency_, uiEventStream_, eventController_, timerFactory_, entityCapsProvider_, userWantsReceipts_, settings_, historyController_, mucRegistry_, highlightManager_); chatControllers_[contact] = controller; controller->setAvailableServerFeatures(serverDiscoInfo_); controller->onActivity.connect(boost::bind(&ChatsManager::handleChatActivity, this, contact, _1, false)); @@ -594,7 +596,7 @@ void ChatsManager::handleJoinMUCRequest(const JID &mucJID, const boost::optional if (createAsReservedIfNew) { muc->setCreateAsReservedIfNew(); } - MUCController* controller = new MUCController(jid_, muc, password, nick, stanzaChannel_, iqRouter_, chatWindowFactory_, presenceOracle_, avatarManager_, uiEventStream_, false, timerFactory_, eventController_, entityCapsProvider_, roster_, historyController_, mucRegistry_); + MUCController* controller = new MUCController(jid_, muc, password, nick, stanzaChannel_, iqRouter_, chatWindowFactory_, presenceOracle_, avatarManager_, uiEventStream_, false, timerFactory_, eventController_, entityCapsProvider_, roster_, historyController_, mucRegistry_, highlightManager_); mucControllers_[mucJID] = controller; controller->setAvailableServerFeatures(serverDiscoInfo_); controller->onUserLeft.connect(boost::bind(&ChatsManager::handleUserLeftMUC, this, controller)); diff --git a/Swift/Controllers/Chat/ChatsManager.h b/Swift/Controllers/Chat/ChatsManager.h index 5b8b785..55e62b9 100644 --- a/Swift/Controllers/Chat/ChatsManager.h +++ b/Swift/Controllers/Chat/ChatsManager.h @@ -50,10 +50,11 @@ namespace Swift { class SettingsProvider; class WhiteboardManager; class HistoryController; + class HighlightManager; class ChatsManager { public: - ChatsManager(JID jid, StanzaChannel* stanzaChannel, IQRouter* iqRouter, EventController* eventController, ChatWindowFactory* chatWindowFactory, JoinMUCWindowFactory* joinMUCWindowFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, PresenceSender* presenceSender, UIEventStream* uiEventStream, ChatListWindowFactory* chatListWindowFactory, bool useDelayForLatency, TimerFactory* timerFactory, MUCRegistry* mucRegistry, EntityCapsProvider* entityCapsProvider, MUCManager* mucManager, MUCSearchWindowFactory* mucSearchWindowFactory, ProfileSettingsProvider* profileSettings, FileTransferOverview* ftOverview, XMPPRoster* roster, bool eagleMode, SettingsProvider* settings, HistoryController* historyController_, WhiteboardManager* whiteboardManager); + ChatsManager(JID jid, StanzaChannel* stanzaChannel, IQRouter* iqRouter, EventController* eventController, ChatWindowFactory* chatWindowFactory, JoinMUCWindowFactory* joinMUCWindowFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, PresenceSender* presenceSender, UIEventStream* uiEventStream, ChatListWindowFactory* chatListWindowFactory, bool useDelayForLatency, TimerFactory* timerFactory, MUCRegistry* mucRegistry, EntityCapsProvider* entityCapsProvider, MUCManager* mucManager, MUCSearchWindowFactory* mucSearchWindowFactory, ProfileSettingsProvider* profileSettings, FileTransferOverview* ftOverview, XMPPRoster* roster, bool eagleMode, SettingsProvider* settings, HistoryController* historyController_, WhiteboardManager* whiteboardManager, HighlightManager* highlightManager); virtual ~ChatsManager(); void setAvatarManager(AvatarManager* avatarManager); void setOnline(bool enabled); @@ -136,5 +137,6 @@ namespace Swift { SettingsProvider* settings_; HistoryController* historyController_; WhiteboardManager* whiteboardManager_; + HighlightManager* highlightManager_; }; } diff --git a/Swift/Controllers/Chat/MUCController.cpp b/Swift/Controllers/Chat/MUCController.cpp index 50eee68..a61b5f0 100644 --- a/Swift/Controllers/Chat/MUCController.cpp +++ b/Swift/Controllers/Chat/MUCController.cpp @@ -24,6 +24,7 @@ #include <Swift/Controllers/UIEvents/UIEventStream.h> #include <Swift/Controllers/UIEvents/RequestChatUIEvent.h> #include <Swift/Controllers/UIEvents/RequestAddUserDialogUIEvent.h> +#include <Swift/Controllers/UIEvents/ShowProfileForRosterItemUIEvent.h> #include <Swift/Controllers/Roster/GroupRosterItem.h> #include <Swift/Controllers/Roster/ContactRosterItem.h> #include <Swiften/Avatars/AvatarManager.h> @@ -35,6 +36,7 @@ #include <Swift/Controllers/Roster/SetPresence.h> #include <Swiften/Disco/EntityCapsProvider.h> #include <Swiften/Roster/XMPPRoster.h> +#include <Swift/Controllers/Highlighter.h> #define MUC_JOIN_WARNING_TIMEOUT_MILLISECONDS 60000 @@ -61,8 +63,9 @@ MUCController::MUCController ( EntityCapsProvider* entityCapsProvider, XMPPRoster* roster, HistoryController* historyController, - MUCRegistry* mucRegistry) : - ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, muc->getJID(), presenceOracle, avatarManager, useDelayForLatency, uiEventStream, eventController, timerFactory, entityCapsProvider, historyController, mucRegistry), muc_(muc), nick_(nick), desiredNick_(nick), password_(password) { + MUCRegistry* mucRegistry, + HighlightManager* highlightManager) : + ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, muc->getJID(), presenceOracle, avatarManager, useDelayForLatency, uiEventStream, eventController, timerFactory, entityCapsProvider, historyController, mucRegistry, highlightManager), muc_(muc), nick_(nick), desiredNick_(nick), password_(password) { parting_ = true; joined_ = false; lastWasPresence_ = false; @@ -98,6 +101,8 @@ MUCController::MUCController ( muc_->onConfigurationFormReceived.connect(boost::bind(&MUCController::handleConfigurationFormReceived, this, _1)); muc_->onRoleChangeFailed.connect(boost::bind(&MUCController::handleOccupantRoleChangeFailed, this, _1, _2, _3)); muc_->onAffiliationListReceived.connect(boost::bind(&MUCController::handleAffiliationListReceived, this, _1, _2)); + highlighter_->setMode(Highlighter::MUCMode); + highlighter_->setNick(nick_); if (timerFactory) { loginCheckTimer_ = boost::shared_ptr<Timer>(timerFactory->createTimer(MUC_JOIN_WARNING_TIMEOUT_MILLISECONDS)); loginCheckTimer_->onTick.connect(boost::bind(&MUCController::handleJoinTimeoutTick, this)); @@ -146,6 +151,7 @@ void MUCController::handleWindowOccupantSelectionChanged(ContactRosterItem* item if (muc_->getOccupant(item->getJID().getResource()).getRealJID()) { actions.push_back(ChatWindow::AddContact); } + actions.push_back(ChatWindow::ShowProfile); } chatWindow_->setAvailableOccupantActions(actions); } @@ -164,6 +170,7 @@ void MUCController::handleActionRequestedOnOccupant(ChatWindow::OccupantAction a case ChatWindow::MakeParticipant: muc_->changeOccupantRole(mucJID, MUCOccupant::Participant);break; case ChatWindow::MakeVisitor: muc_->changeOccupantRole(mucJID, MUCOccupant::Visitor);break; case ChatWindow::AddContact: if (occupant.getRealJID()) events_->send(boost::make_shared<RequestAddUserDialogUIEvent>(realJID, occupant.getNick()));break; + case ChatWindow::ShowProfile: events_->send(boost::make_shared<ShowProfileForRosterItemUIEvent>(mucJID));break; } } @@ -228,6 +235,9 @@ void MUCController::receivedActivity() { } } +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wswitch-enum" + void MUCController::handleJoinFailed(boost::shared_ptr<ErrorPayload> error) { receivedActivity(); std::string errorMessage = QT_TRANSLATE_NOOP("", "Unable to enter this room"); @@ -270,16 +280,18 @@ void MUCController::handleJoinFailed(boost::shared_ptr<ErrorPayload> error) { chatWindow_->addErrorMessage(errorMessage); parting_ = true; if (!rejoinNick.empty()) { - nick_ = rejoinNick; + setNick(rejoinNick); rejoin(); } } +#pragma clang diagnostic pop + void MUCController::handleJoinComplete(const std::string& nick) { receivedActivity(); joined_ = true; std::string joinMessage = str(format(QT_TRANSLATE_NOOP("", "You have entered room %1% as %2%.")) % toJID_.toString() % nick); - nick_ = nick; + setNick(nick); chatWindow_->addSystemMessage(joinMessage); #ifdef SWIFT_EXPERIMENTAL_HISTORY @@ -386,6 +398,7 @@ std::string MUCController::roleToFriendlyName(MUCOccupant::Role role) { case MUCOccupant::Visitor: return QT_TRANSLATE_NOOP("", "visitor"); case MUCOccupant::NoRole: return ""; } + assert(false); return ""; } @@ -396,6 +409,7 @@ std::string MUCController::roleToSortName(MUCOccupant::Role role) { case MUCOccupant::Visitor: return "3"; case MUCOccupant::NoRole: return "4"; } + assert(false); return "5"; } @@ -448,10 +462,13 @@ void MUCController::preHandleIncomingMessage(boost::shared_ptr<MessageEvent> mes } } -void MUCController::postHandleIncomingMessage(boost::shared_ptr<MessageEvent> messageEvent) { +void MUCController::postHandleIncomingMessage(boost::shared_ptr<MessageEvent> messageEvent, const HighlightAction& highlight) { boost::shared_ptr<Message> message = messageEvent->getStanza(); if (joined_ && messageEvent->getStanza()->getFrom().getResource() != nick_ && messageTargetsMe(message) && !message->getPayload<Delay>()) { eventController_->handleIncomingEvent(messageEvent); + if (!messageEvent->getConcluded()) { + highlighter_->handleHighlightAction(highlight); + } } } @@ -487,7 +504,6 @@ std::string MUCController::roleToGroupName(MUCOccupant::Role role) { case MUCOccupant::Participant: result = QT_TRANSLATE_NOOP("", "Participants"); break; case MUCOccupant::Visitor: result = QT_TRANSLATE_NOOP("", "Visitors"); break; case MUCOccupant::NoRole: result = QT_TRANSLATE_NOOP("", "Occupants"); break; - default: assert(false); } return result; } @@ -504,7 +520,7 @@ void MUCController::setOnline(bool online) { if (loginCheckTimer_) { loginCheckTimer_->start(); } - nick_ = desiredNick_; + setNick(desiredNick_); rejoin(); } } @@ -611,7 +627,8 @@ void MUCController::appendToJoinParts(std::vector<NickJoinPart>& joinParts, cons switch (newEvent.type) { case Join: type = (type == Part) ? PartThenJoin : Join; break; case Part: type = (type == Join) ? JoinThenPart : Part; break; - default: /*Nothing to see here */;break; + case PartThenJoin: break; + case JoinThenPart: break; } (*it).type = type; break; @@ -811,7 +828,7 @@ void MUCController::addRecentLogs() { bool senderIsSelf = nick_ == message.getFromJID().getResource(); // the chatWindow uses utc timestamps - addMessage(message.getMessage(), senderDisplayNameFromMessage(message.getFromJID()), senderIsSelf, boost::shared_ptr<SecurityLabel>(new SecurityLabel()), std::string(avatarManager_->getAvatarPath(message.getFromJID()).string()), message.getTime() - boost::posix_time::hours(message.getOffset())); + addMessage(message.getMessage(), senderDisplayNameFromMessage(message.getFromJID()), senderIsSelf, boost::shared_ptr<SecurityLabel>(new SecurityLabel()), std::string(avatarManager_->getAvatarPath(message.getFromJID()).string()), message.getTime() - boost::posix_time::hours(message.getOffset()), HighlightAction()); } } @@ -840,4 +857,10 @@ void MUCController::checkDuplicates(boost::shared_ptr<Message> newMessage) { } } +void MUCController::setNick(const std::string& nick) +{ + nick_ = nick; + highlighter_->setNick(nick_); +} + } diff --git a/Swift/Controllers/Chat/MUCController.h b/Swift/Controllers/Chat/MUCController.h index 63893d0..11fe0ff 100644 --- a/Swift/Controllers/Chat/MUCController.h +++ b/Swift/Controllers/Chat/MUCController.h @@ -33,18 +33,19 @@ namespace Swift { class TabComplete; class InviteToChatWindow; class XMPPRoster; + class HighlightManager; enum JoinPart {Join, Part, JoinThenPart, PartThenJoin}; struct NickJoinPart { - NickJoinPart(const std::string& nick, JoinPart type) : nick(nick), type(type) {}; + NickJoinPart(const std::string& nick, JoinPart type) : nick(nick), type(type) {} std::string nick; JoinPart type; }; class MUCController : public ChatControllerBase { public: - MUCController(const JID& self, MUC::ref muc, const boost::optional<std::string>& password, const std::string &nick, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, PresenceOracle* presenceOracle, AvatarManager* avatarManager, UIEventStream* events, bool useDelayForLatency, TimerFactory* timerFactory, EventController* eventController, EntityCapsProvider* entityCapsProvider, XMPPRoster* roster, HistoryController* historyController, MUCRegistry* mucRegistry); + MUCController(const JID& self, MUC::ref muc, const boost::optional<std::string>& password, const std::string &nick, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, PresenceOracle* presenceOracle, AvatarManager* avatarManager, UIEventStream* events, bool useDelayForLatency, TimerFactory* timerFactory, EventController* eventController, EntityCapsProvider* entityCapsProvider, XMPPRoster* roster, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager); ~MUCController(); boost::signal<void ()> onUserLeft; boost::signal<void ()> onUserJoined; @@ -62,7 +63,7 @@ namespace Swift { std::string senderDisplayNameFromMessage(const JID& from); boost::optional<boost::posix_time::ptime> getMessageTimestamp(boost::shared_ptr<Message> message) const; void preHandleIncomingMessage(boost::shared_ptr<MessageEvent>); - void postHandleIncomingMessage(boost::shared_ptr<MessageEvent>); + void postHandleIncomingMessage(boost::shared_ptr<MessageEvent>, const HighlightAction&); void cancelReplaces(); void logMessage(const std::string& message, const JID& fromJID, const JID& toJID, const boost::posix_time::ptime& timeStamp, bool isIncoming); @@ -108,6 +109,7 @@ namespace Swift { void handleInviteToMUCWindowCompleted(); void addRecentLogs(); void checkDuplicates(boost::shared_ptr<Message> newMessage); + void setNick(const std::string& nick); private: MUC::ref muc_; diff --git a/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp b/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp index 482b19c..dd90d66 100644 --- a/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp +++ b/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp @@ -106,14 +106,16 @@ public: avatarManager_ = new NullAvatarManager(); wbSessionManager_ = new WhiteboardSessionManager(iqRouter_, stanzaChannel_, presenceOracle_, entityCapsManager_); wbManager_ = new WhiteboardManager(whiteboardWindowFactory_, uiEventStream_, nickResolver_, wbSessionManager_); + highlightManager_ = new HighlightManager(settings_); mocks_->ExpectCall(chatListWindowFactory_, ChatListWindowFactory::createChatListWindow).With(uiEventStream_).Return(chatListWindow_); - manager_ = new ChatsManager(jid_, stanzaChannel_, iqRouter_, eventController_, chatWindowFactory_, joinMUCWindowFactory_, nickResolver_, presenceOracle_, directedPresenceSender_, uiEventStream_, chatListWindowFactory_, true, NULL, mucRegistry_, entityCapsManager_, mucManager_, mucSearchWindowFactory_, profileSettings_, ftOverview_, xmppRoster_, false, settings_, NULL, wbManager_); + manager_ = new ChatsManager(jid_, stanzaChannel_, iqRouter_, eventController_, chatWindowFactory_, joinMUCWindowFactory_, nickResolver_, presenceOracle_, directedPresenceSender_, uiEventStream_, chatListWindowFactory_, true, NULL, mucRegistry_, entityCapsManager_, mucManager_, mucSearchWindowFactory_, profileSettings_, ftOverview_, xmppRoster_, false, settings_, NULL, wbManager_, highlightManager_); manager_->setAvatarManager(avatarManager_); - }; + } void tearDown() { + delete highlightManager_; //delete chatListWindowFactory delete profileSettings_; delete avatarManager_; @@ -481,6 +483,7 @@ private: FileTransferManager* ftManager_; WhiteboardSessionManager* wbSessionManager_; WhiteboardManager* wbManager_; + HighlightManager* highlightManager_; }; CPPUNIT_TEST_SUITE_REGISTRATION(ChatsManagerTest); diff --git a/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp b/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp index 4f37229..f1fcf79 100644 --- a/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp +++ b/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp @@ -26,6 +26,7 @@ #include "Swiften/Network/TimerFactory.h" #include "Swiften/Elements/MUCUserPayload.h" #include "Swiften/Disco/DummyEntityCapsProvider.h" +#include <Swift/Controllers/Settings/DummySettingsProvider.h> using namespace Swift; @@ -62,12 +63,16 @@ public: window_ = new MockChatWindow(); mucRegistry_ = new MUCRegistry(); entityCapsProvider_ = new DummyEntityCapsProvider(); + settings_ = new DummySettingsProvider(); + highlightManager_ = new HighlightManager(settings_); muc_ = boost::make_shared<MUC>(stanzaChannel_, iqRouter_, directedPresenceSender_, mucJID_, mucRegistry_); mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(muc_->getJID(), uiEventStream_).Return(window_); - controller_ = new MUCController (self_, muc_, boost::optional<std::string>(), nick_, stanzaChannel_, iqRouter_, chatWindowFactory_, presenceOracle_, avatarManager_, uiEventStream_, false, timerFactory, eventController_, entityCapsProvider_, NULL, NULL, mucRegistry_); - }; + controller_ = new MUCController (self_, muc_, boost::optional<std::string>(), nick_, stanzaChannel_, iqRouter_, chatWindowFactory_, presenceOracle_, avatarManager_, uiEventStream_, false, timerFactory, eventController_, entityCapsProvider_, NULL, NULL, mucRegistry_, highlightManager_); + } void tearDown() { + delete highlightManager_; + delete settings_; delete entityCapsProvider_; delete controller_; delete eventController_; @@ -338,6 +343,8 @@ private: MockChatWindow* window_; MUCRegistry* mucRegistry_; DummyEntityCapsProvider* entityCapsProvider_; + DummySettingsProvider* settings_; + HighlightManager* highlightManager_; }; CPPUNIT_TEST_SUITE_REGISTRATION(MUCControllerTest); diff --git a/Swift/Controllers/Chat/UnitTest/MockChatListWindow.h b/Swift/Controllers/Chat/UnitTest/MockChatListWindow.h index 5bbd490..5fa264d 100644 --- a/Swift/Controllers/Chat/UnitTest/MockChatListWindow.h +++ b/Swift/Controllers/Chat/UnitTest/MockChatListWindow.h @@ -12,12 +12,12 @@ namespace Swift { class MockChatListWindow : public ChatListWindow { public: - MockChatListWindow() {}; - virtual ~MockChatListWindow() {}; + MockChatListWindow() {} + virtual ~MockChatListWindow() {} void addMUCBookmark(const MUCBookmark& /*bookmark*/) {} void removeMUCBookmark(const MUCBookmark& /*bookmark*/) {} - void addWhiteboardSession(const ChatListWindow::Chat& /*chat*/) {}; - void removeWhiteboardSession(const JID& /*jid*/) {}; + void addWhiteboardSession(const ChatListWindow::Chat& /*chat*/) {} + void removeWhiteboardSession(const JID& /*jid*/) {} void setBookmarksEnabled(bool /*enabled*/) {} void setRecents(const std::list<ChatListWindow::Chat>& /*recents*/) {} void setUnreadCount(int /*unread*/) {} |