summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'Swift/Controllers/Chat')
-rw-r--r--Swift/Controllers/Chat/ChatController.cpp9
-rw-r--r--Swift/Controllers/Chat/ChatControllerBase.cpp42
-rw-r--r--Swift/Controllers/Chat/ChatControllerBase.h24
-rw-r--r--Swift/Controllers/Chat/ChatMessageParser.cpp167
-rw-r--r--Swift/Controllers/Chat/ChatMessageParser.h30
-rw-r--r--Swift/Controllers/Chat/ChatsManager.cpp8
-rw-r--r--Swift/Controllers/Chat/MUCController.cpp13
-rw-r--r--Swift/Controllers/Chat/MUCController.h4
-rw-r--r--Swift/Controllers/Chat/UnitTest/ChatMessageParserTest.cpp487
-rw-r--r--Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp84
-rw-r--r--Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp10
11 files changed, 471 insertions, 407 deletions
diff --git a/Swift/Controllers/Chat/ChatController.cpp b/Swift/Controllers/Chat/ChatController.cpp
index a498067..d1cd1fe 100644
--- a/Swift/Controllers/Chat/ChatController.cpp
+++ b/Swift/Controllers/Chat/ChatController.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2016 Isode Limited.
+ * Copyright (c) 2010-2017 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -28,7 +28,7 @@
#include <Swift/Controllers/Chat/ChatMessageParser.h>
#include <Swift/Controllers/FileTransfer/FileTransferController.h>
-#include <Swift/Controllers/Highlighter.h>
+#include <Swift/Controllers/Highlighting/Highlighter.h>
#include <Swift/Controllers/Intl.h>
#include <Swift/Controllers/SettingConstants.h>
#include <Swift/Controllers/StatusUtil.h>
@@ -51,7 +51,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, bool userWantsReceipts, SettingsProvider* settings, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager, ClientBlockListManager* clientBlockListManager, std::shared_ptr<ChatMessageParser> chatMessageParser, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider)
- : ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, contact, presenceOracle, avatarManager, useDelayForLatency, eventStream, eventController, timerFactory, entityCapsProvider, historyController, mucRegistry, highlightManager, chatMessageParser, autoAcceptMUCInviteDecider), userWantsReceipts_(userWantsReceipts), settings_(settings), clientBlockListManager_(clientBlockListManager) {
+ : ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, contact, nickResolver, presenceOracle, avatarManager, useDelayForLatency, eventStream, eventController, timerFactory, entityCapsProvider, historyController, mucRegistry, highlightManager, chatMessageParser, autoAcceptMUCInviteDecider), userWantsReceipts_(userWantsReceipts), settings_(settings), clientBlockListManager_(clientBlockListManager) {
isInMUC_ = isInMUC;
lastWasPresence_ = false;
chatStateNotifier_ = new ChatStateNotifier(stanzaChannel, contact, entityCapsProvider);
@@ -210,9 +210,10 @@ void ChatController::preHandleIncomingMessage(std::shared_ptr<MessageEvent> mess
}
void ChatController::postHandleIncomingMessage(std::shared_ptr<MessageEvent> messageEvent, const ChatWindow::ChatMessage& chatMessage) {
+ highlighter_->handleSystemNotifications(chatMessage, messageEvent);
eventController_->handleIncomingEvent(messageEvent);
if (!messageEvent->getConcluded()) {
- handleHighlightActions(chatMessage);
+ highlighter_->handleSoundNotifications(chatMessage);
}
}
diff --git a/Swift/Controllers/Chat/ChatControllerBase.cpp b/Swift/Controllers/Chat/ChatControllerBase.cpp
index da9064e..5839d6c 100644
--- a/Swift/Controllers/Chat/ChatControllerBase.cpp
+++ b/Swift/Controllers/Chat/ChatControllerBase.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2016 Isode Limited.
+ * Copyright (c) 2010-2017 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -26,8 +26,8 @@
#include <Swift/Controllers/Chat/AutoAcceptMUCInviteDecider.h>
#include <Swift/Controllers/Chat/ChatMessageParser.h>
-#include <Swift/Controllers/HighlightManager.h>
-#include <Swift/Controllers/Highlighter.h>
+#include <Swift/Controllers/Highlighting/HighlightManager.h>
+#include <Swift/Controllers/Highlighting/Highlighter.h>
#include <Swift/Controllers/Intl.h>
#include <Swift/Controllers/UIEvents/JoinMUCUIEvent.h>
#include <Swift/Controllers/UIEvents/UIEventStream.h>
@@ -38,13 +38,13 @@
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, HighlightManager* highlightManager, std::shared_ptr<ChatMessageParser> chatMessageParser, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider) : 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), chatMessageParser_(chatMessageParser), autoAcceptMUCInviteDecider_(autoAcceptMUCInviteDecider), eventStream_(eventStream) {
+ChatControllerBase::ChatControllerBase(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &toJID, NickResolver* nickResolver, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController, TimerFactory* timerFactory, EntityCapsProvider* entityCapsProvider, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager, std::shared_ptr<ChatMessageParser> chatMessageParser, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider) : 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), chatMessageParser_(chatMessageParser), autoAcceptMUCInviteDecider_(autoAcceptMUCInviteDecider), eventStream_(eventStream) {
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();
+ highlighter_ = highlightManager->createHighlighter(nickResolver);
ChatControllerBase::setOnline(stanzaChannel->isAvailable() && iqRouter->isAvailable());
createDayChangeTimer();
}
@@ -204,30 +204,12 @@ bool ChatControllerBase::hasOpenWindow() const {
return chatWindow_ && chatWindow_->isVisible();
}
-ChatWindow::ChatMessage ChatControllerBase::buildChatWindowChatMessage(const std::string& message, bool senderIsSelf, const HighlightAction& fullMessageHighlightAction) {
+ChatWindow::ChatMessage ChatControllerBase::buildChatWindowChatMessage(const std::string& message, const std::string& senderName, bool senderIsSelf) {
ChatWindow::ChatMessage chatMessage;
- chatMessage = chatMessageParser_->parseMessageBody(message, highlighter_->getNick(), senderIsSelf);
- chatMessage.setFullMessageHighlightAction(fullMessageHighlightAction);
+ chatMessage = chatMessageParser_->parseMessageBody(message, senderName, senderIsSelf);
return chatMessage;
}
-void ChatControllerBase::handleHighlightActions(const ChatWindow::ChatMessage& chatMessage) {
- std::set<std::string> playedSounds;
- if (chatMessage.getFullMessageHighlightAction().playSound()) {
- highlighter_->handleHighlightAction(chatMessage.getFullMessageHighlightAction());
- playedSounds.insert(chatMessage.getFullMessageHighlightAction().getSoundFile());
- }
- for (std::shared_ptr<ChatWindow::ChatMessagePart> part : chatMessage.getParts()) {
- std::shared_ptr<ChatWindow::ChatHighlightingMessagePart> highlightMessage = std::dynamic_pointer_cast<ChatWindow::ChatHighlightingMessagePart>(part);
- if (highlightMessage && highlightMessage->action.playSound()) {
- if (playedSounds.find(highlightMessage->action.getSoundFile()) == playedSounds.end()) {
- highlighter_->handleHighlightAction(highlightMessage->action);
- playedSounds.insert(highlightMessage->action.getSoundFile());
- }
- }
- }
-}
-
void ChatControllerBase::updateMessageCount() {
chatWindow_->setUnreadMessageCount(boost::numeric_cast<int>(unreadMessages_.size()));
onUnreadCountChanged();
@@ -314,12 +296,6 @@ void ChatControllerBase::handleIncomingMessage(std::shared_ptr<MessageEvent> mes
}
onActivity(body);
- // Highlight
- HighlightAction fullMessageHighlight;
- if (!isIncomingMessageFromMe(message)) {
- fullMessageHighlight = highlighter_->findFirstFullMessageMatchAction(body, senderHighlightNameFromMessage(from));
- }
-
std::shared_ptr<Replace> replace = message->getPayload<Replace>();
bool senderIsSelf = isIncomingMessageFromMe(message);
if (replace) {
@@ -327,12 +303,12 @@ void ChatControllerBase::handleIncomingMessage(std::shared_ptr<MessageEvent> mes
std::map<JID, std::string>::iterator lastMessage;
lastMessage = lastMessagesUIID_.find(from);
if (lastMessage != lastMessagesUIID_.end()) {
- chatMessage = buildChatWindowChatMessage(body, senderIsSelf, fullMessageHighlight);
+ chatMessage = buildChatWindowChatMessage(body, senderHighlightNameFromMessage(from), senderIsSelf);
replaceMessage(chatMessage, lastMessagesUIID_[from], timeStamp);
}
}
else {
- chatMessage = buildChatWindowChatMessage(body, senderIsSelf, fullMessageHighlight);
+ chatMessage = buildChatWindowChatMessage(body, senderHighlightNameFromMessage(from), senderIsSelf);
addMessageHandleIncomingMessage(from, chatMessage, senderIsSelf, label, timeStamp);
}
diff --git a/Swift/Controllers/Chat/ChatControllerBase.h b/Swift/Controllers/Chat/ChatControllerBase.h
index 4255c19..7f118bd 100644
--- a/Swift/Controllers/Chat/ChatControllerBase.h
+++ b/Swift/Controllers/Chat/ChatControllerBase.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2016 Isode Limited.
+ * Copyright (c) 2010-2017 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -28,24 +28,25 @@
#include <Swiften/Presence/PresenceOracle.h>
#include <Swiften/Queries/IQRouter.h>
-#include <Swift/Controllers/HighlightManager.h>
+#include <Swift/Controllers/Highlighting/HighlightManager.h>
#include <Swift/Controllers/HistoryController.h>
#include <Swift/Controllers/UIInterfaces/ChatWindow.h>
#include <Swift/Controllers/XMPPEvents/MUCInviteEvent.h>
#include <Swift/Controllers/XMPPEvents/MessageEvent.h>
namespace Swift {
- class IQRouter;
- class StanzaChannel;
- class ChatWindowFactory;
+ class AutoAcceptMUCInviteDecider;
class AvatarManager;
- class UIEventStream;
- class EventController;
+ class ChatMessageParser;
+ class ChatWindowFactory;
class EntityCapsProvider;
+ class EventController;
class HighlightManager;
class Highlighter;
- class ChatMessageParser;
- class AutoAcceptMUCInviteDecider;
+ class IQRouter;
+ class NickResolver;
+ class StanzaChannel;
+ class UIEventStream;
class ChatControllerBase : public boost::signals2::trackable {
public:
@@ -73,7 +74,7 @@ namespace Swift {
boost::signals2::signal<void(ChatWindow* /*window to reuse*/, const std::vector<JID>& /*invite people*/, const std::string& /*reason*/)> onConvertToMUC;
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, HighlightManager* highlightManager, std::shared_ptr<ChatMessageParser> chatMessageParser, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider);
+ ChatControllerBase(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &toJID, NickResolver* nickResolver, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController, TimerFactory* timerFactory, EntityCapsProvider* entityCapsProvider, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager, std::shared_ptr<ChatMessageParser> chatMessageParser, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider);
/**
* Pass the Message appended, and the stanza used to send it.
@@ -96,8 +97,7 @@ namespace Swift {
/** JID any iq for account should go to - bare except for PMs */
virtual JID getBaseJID();
virtual void logMessage(const std::string& message, const JID& fromJID, const JID& toJID, const boost::posix_time::ptime& timeStamp, bool isIncoming) = 0;
- ChatWindow::ChatMessage buildChatWindowChatMessage(const std::string& message, bool senderIsSelf, const HighlightAction& fullMessageHighlightAction);
- void handleHighlightActions(const ChatWindow::ChatMessage& chatMessage);
+ ChatWindow::ChatMessage buildChatWindowChatMessage(const std::string& message, const std::string& senderName, bool senderIsSelf);
void updateMessageCount();
private:
diff --git a/Swift/Controllers/Chat/ChatMessageParser.cpp b/Swift/Controllers/Chat/ChatMessageParser.cpp
index ec7df6c..1a822a1 100644
--- a/Swift/Controllers/Chat/ChatMessageParser.cpp
+++ b/Swift/Controllers/Chat/ChatMessageParser.cpp
@@ -1,16 +1,18 @@
/*
- * Copyright (c) 2013-2016 Isode Limited.
+ * Copyright (c) 2013-2017 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#include <Swift/Controllers/Chat/ChatMessageParser.h>
+#include <algorithm>
#include <memory>
#include <utility>
#include <vector>
#include <boost/algorithm/string.hpp>
+#include <boost/regex.hpp>
#include <Swiften/Base/Regex.h>
#include <Swiften/Base/String.h>
@@ -19,14 +21,14 @@
namespace Swift {
- ChatMessageParser::ChatMessageParser(const std::map<std::string, std::string>& emoticons, HighlightRulesListPtr highlightRules, bool mucMode)
- : emoticons_(emoticons), highlightRules_(highlightRules), mucMode_(mucMode) {
+ ChatMessageParser::ChatMessageParser(const std::map<std::string, std::string>& emoticons, std::shared_ptr<HighlightConfiguration> highlightConfiguration, Mode mode) : emoticons_(emoticons), highlightConfiguration_(highlightConfiguration), mode_(mode) {
}
typedef std::pair<std::string, std::string> StringPair;
- ChatWindow::ChatMessage ChatMessageParser::parseMessageBody(const std::string& body, const std::string& nick, bool senderIsSelf) {
+ ChatWindow::ChatMessage ChatMessageParser::parseMessageBody(const std::string& body, const std::string& senderNickname, bool senderIsSelf) {
ChatWindow::ChatMessage parsedMessage;
+
std::string remaining = body;
if (boost::starts_with(body, "/me ")) {
remaining = String::getSplittedAtFirst(body, ' ').second;
@@ -60,8 +62,12 @@ namespace Swift {
parsedMessage = emoticonHighlight(parsedMessage);
if (!senderIsSelf) { /* do not highlight our own messsages */
- /* do word-based color highlighting */
- parsedMessage = splitHighlight(parsedMessage, nick);
+ // Highlight keywords and own mentions.
+ parsedMessage = splitHighlight(parsedMessage);
+
+ // Highlight full message events like, specific sender, general
+ // incoming group message, or general incoming direct message.
+ parsedMessage = fullMessageHighlight(parsedMessage, senderNickname);
}
return parsedMessage;
@@ -89,7 +95,7 @@ namespace Swift {
boost::regex emoticonRegex(regexString);
ChatWindow::ChatMessage newMessage;
- for (std::shared_ptr<ChatWindow::ChatMessagePart> part : parsedMessage.getParts()) {
+ for (const auto& part : parsedMessage.getParts()) {
std::shared_ptr<ChatWindow::ChatTextMessagePart> textPart;
if ((textPart = std::dynamic_pointer_cast<ChatWindow::ChatTextMessagePart>(part))) {
try {
@@ -137,61 +143,122 @@ namespace Swift {
}
parsedMessage.setParts(newMessage.getParts());
}
+
return parsedMessage;
}
- ChatWindow::ChatMessage ChatMessageParser::splitHighlight(const ChatWindow::ChatMessage& message, const std::string& nick) {
- ChatWindow::ChatMessage parsedMessage = message;
-
- for (size_t i = 0; i < highlightRules_->getSize(); ++i) {
- const HighlightRule& rule = highlightRules_->getRule(i);
- if (rule.getMatchMUC() && !mucMode_) {
- continue; /* this rule only applies to MUC's, and this is a CHAT */
- } else if (rule.getMatchChat() && mucMode_) {
- continue; /* this rule only applies to CHAT's, and this is a MUC */
- } else if (rule.getAction().getTextBackground().empty() && rule.getAction().getTextColor().empty()) {
- continue; /* do not try to highlight text, if no highlight color is specified */
+ ChatWindow::ChatMessage ChatMessageParser::splitHighlight(const ChatWindow::ChatMessage& message) {
+ auto keywordToRegEx = [](const std::string& keyword, bool matchCaseSensitive) {
+ std::string escaped = Regex::escape(keyword);
+ boost::regex::flag_type flags = boost::regex::normal;
+ if (!matchCaseSensitive) {
+ flags |= boost::regex::icase;
}
- const std::vector<boost::regex> keywordRegex = rule.getKeywordRegex(nick);
- for (const boost::regex& regex : keywordRegex) {
- ChatWindow::ChatMessage newMessage;
- for (std::shared_ptr<ChatWindow::ChatMessagePart> part : parsedMessage.getParts()) {
- std::shared_ptr<ChatWindow::ChatTextMessagePart> textPart;
- if ((textPart = std::dynamic_pointer_cast<ChatWindow::ChatTextMessagePart>(part))) {
- try {
- boost::match_results<std::string::const_iterator> match;
- const std::string& text = textPart->text;
- std::string::const_iterator start = text.begin();
- while (regex_search(start, text.end(), match, regex)) {
- std::string::const_iterator matchStart = match[0].first;
- std::string::const_iterator matchEnd = match[0].second;
- if (start != matchStart) {
- /* If we're skipping over plain text since the previous emoticon, record it as plain text */
- newMessage.append(std::make_shared<ChatWindow::ChatTextMessagePart>(std::string(start, matchStart)));
- }
- std::shared_ptr<ChatWindow::ChatHighlightingMessagePart> highlightPart = std::make_shared<ChatWindow::ChatHighlightingMessagePart>();
- highlightPart->text = match.str();
- highlightPart->action = rule.getAction();
- newMessage.append(highlightPart);
- start = matchEnd;
- }
- if (start != text.end()) {
- /* If there's plain text after the last emoticon, record it */
- newMessage.append(std::make_shared<ChatWindow::ChatTextMessagePart>(std::string(start, text.end())));
+ return boost::regex("\\b" + escaped + "\\b", flags);
+ };
+
+ auto highlightKeywordInChatMessage = [&](const ChatWindow::ChatMessage& message, const std::string& keyword, bool matchCaseSensitive, const HighlightAction& action) {
+ ChatWindow::ChatMessage resultMessage;
+
+ for (const auto& part : message.getParts()) {
+ std::shared_ptr<ChatWindow::ChatTextMessagePart> textPart;
+ if ((textPart = std::dynamic_pointer_cast<ChatWindow::ChatTextMessagePart>(part))) {
+ try {
+ boost::match_results<std::string::const_iterator> match;
+ const std::string& text = textPart->text;
+ std::string::const_iterator start = text.begin();
+ while (regex_search(start, text.end(), match, keywordToRegEx(keyword, matchCaseSensitive))) {
+ std::string::const_iterator matchStart = match[0].first;
+ std::string::const_iterator matchEnd = match[0].second;
+ if (start != matchStart) {
+ /* If we're skipping over plain text since the previous emoticon, record it as plain text */
+ resultMessage.append(std::make_shared<ChatWindow::ChatTextMessagePart>(std::string(start, matchStart)));
}
+ std::shared_ptr<ChatWindow::ChatHighlightingMessagePart> highlightPart = std::make_shared<ChatWindow::ChatHighlightingMessagePart>();
+ highlightPart->text = match.str();
+ highlightPart->action = action;
+ resultMessage.append(highlightPart);
+ start = matchEnd;
}
- catch (std::runtime_error) {
- /* Basically too expensive to compute the regex results and it gave up, so pass through as text */
- newMessage.append(part);
+ if (start != text.end()) {
+ /* If there's plain text after the last emoticon, record it */
+ resultMessage.append(std::make_shared<ChatWindow::ChatTextMessagePart>(std::string(start, text.end())));
}
- } else {
- newMessage.append(part);
}
+ catch (std::runtime_error) {
+ /* Basically too expensive to compute the regex results and it gave up, so pass through as text */
+ resultMessage.append(part);
+ }
+ } else {
+ resultMessage.append(part);
}
- parsedMessage.setParts(newMessage.getParts());
}
+ return resultMessage;
+ };
+
+ ChatWindow::ChatMessage parsedMessage = message;
+
+ // detect mentions of own nickname
+ HighlightAction ownMentionKeywordAction = highlightConfiguration_->ownMentionAction;
+ ownMentionKeywordAction.setSoundFilePath(boost::optional<std::string>());
+ ownMentionKeywordAction.setSystemNotificationEnabled(false);
+ if (!getNick().empty() && !highlightConfiguration_->ownMentionAction.isEmpty()) {
+ auto nicknameHighlightedMessage = highlightKeywordInChatMessage(parsedMessage, nick_, false, ownMentionKeywordAction);
+ auto highlightedParts = nicknameHighlightedMessage.getParts();
+ auto ownNicknamePart = std::find_if(highlightedParts.begin(), highlightedParts.end(), [&](std::shared_ptr<ChatWindow::ChatMessagePart>& part){
+ auto highlightPart = std::dynamic_pointer_cast<ChatWindow::ChatHighlightingMessagePart>(part);
+ if (highlightPart && highlightPart->text == nick_) {
+ return true;
+ }
+ return false;
+ });
+ if (ownNicknamePart != highlightedParts.end()) {
+ parsedMessage.setHighlightActionOwnMention(highlightConfiguration_->ownMentionAction);
+ }
+ parsedMessage.setParts(nicknameHighlightedMessage.getParts());
+ }
+
+ // detect keywords
+ for (const auto& keywordHighlight : highlightConfiguration_->keywordHighlights) {
+ if (keywordHighlight.keyword.empty() || keywordHighlight.action.isEmpty()) {
+ continue;
+ }
+ auto newMessage = highlightKeywordInChatMessage(parsedMessage, keywordHighlight.keyword, keywordHighlight.matchCaseSensitive, keywordHighlight.action);
+ parsedMessage.setParts(newMessage.getParts());
}
return parsedMessage;
}
+
+ ChatWindow::ChatMessage ChatMessageParser::fullMessageHighlight(const ChatWindow::ChatMessage& parsedMessage, const std::string& sender) {
+ auto fullHighlightedMessage = parsedMessage;
+
+ // contact highlighting
+ for (const auto& contactHighlight : highlightConfiguration_->contactHighlights) {
+ if (sender == contactHighlight.name) {
+ fullHighlightedMessage.setHighlightActionSender(contactHighlight.action);
+ break;
+ }
+ }
+
+ // general incoming messages
+ HighlightAction groupAction;
+ HighlightAction chatAction;
+
+ switch (mode_) {
+ case Mode::GroupChat:
+ groupAction.setSoundFilePath(highlightConfiguration_->playSoundOnIncomingGroupchatMessages ? boost::optional<std::string>("") : boost::optional<std::string>());
+ groupAction.setSystemNotificationEnabled(highlightConfiguration_->showNotificationOnIncomingGroupchatMessages);
+ fullHighlightedMessage.setHighlightActionGroupMessage(groupAction);
+ break;
+
+ case Mode::Chat:
+ chatAction.setSoundFilePath(highlightConfiguration_->playSoundOnIncomingDirectMessages ? boost::optional<std::string>("") : boost::optional<std::string>());
+ chatAction.setSystemNotificationEnabled(highlightConfiguration_->showNotificationOnIncomingDirectMessages);
+ fullHighlightedMessage.setHighlightActonDirectMessage(chatAction);
+ break;
+ }
+
+ return fullHighlightedMessage;
+ }
}
diff --git a/Swift/Controllers/Chat/ChatMessageParser.h b/Swift/Controllers/Chat/ChatMessageParser.h
index 4bed669..de5eac9 100644
--- a/Swift/Controllers/Chat/ChatMessageParser.h
+++ b/Swift/Controllers/Chat/ChatMessageParser.h
@@ -1,26 +1,44 @@
/*
- * Copyright (c) 2013-2014 Isode Limited.
+ * Copyright (c) 2013-2017 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#pragma once
+#include <memory>
#include <string>
+#include <Swift/Controllers/Highlighting/HighlightConfiguration.h>
#include <Swift/Controllers/UIInterfaces/ChatWindow.h>
namespace Swift {
+ /**
+ * @brief The ChatMessageParser class takes an emoticon map, a \ref HighlightConfiguration, and a boolean that indicates if the message context is in a MUC or not.
+ * The class handles parsing a message string and identifies emoticons, URLs, and various highlights.
+ */
class ChatMessageParser {
public:
- ChatMessageParser(const std::map<std::string, std::string>& emoticons, HighlightRulesListPtr highlightRules, bool mucMode = false);
- ChatWindow::ChatMessage parseMessageBody(const std::string& body, const std::string& nick = "", bool senderIsSelf = false);
+ enum class Mode { Chat, GroupChat };
+
+ public:
+ ChatMessageParser(const std::map<std::string, std::string>& emoticons, std::shared_ptr<HighlightConfiguration> highlightConfiguration, Mode mode = Mode::Chat);
+
+ void setNick(const std::string& nick) { nick_ = nick; }
+ std::string getNick() const { return nick_; }
+
+ ChatWindow::ChatMessage parseMessageBody(const std::string& body, const std::string& sender = "", bool senderIsSelf = false);
+
private:
ChatWindow::ChatMessage emoticonHighlight(const ChatWindow::ChatMessage& parsedMessage);
- ChatWindow::ChatMessage splitHighlight(const ChatWindow::ChatMessage& parsedMessage, const std::string& nick);
+ ChatWindow::ChatMessage splitHighlight(const ChatWindow::ChatMessage& parsedMessage);
+ ChatWindow::ChatMessage fullMessageHighlight(const ChatWindow::ChatMessage& parsedMessage, const std::string& sender);
+
+ private:
std::map<std::string, std::string> emoticons_;
- HighlightRulesListPtr highlightRules_;
- bool mucMode_;
+ std::shared_ptr<HighlightConfiguration> highlightConfiguration_;
+ Mode mode_;
+ std::string nick_;
};
}
diff --git a/Swift/Controllers/Chat/ChatsManager.cpp b/Swift/Controllers/Chat/ChatsManager.cpp
index f55df1e..fc96701 100644
--- a/Swift/Controllers/Chat/ChatsManager.cpp
+++ b/Swift/Controllers/Chat/ChatsManager.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2016 Isode Limited.
+ * Copyright (c) 2010-2017 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -746,7 +746,7 @@ ChatController* ChatsManager::getChatControllerOrFindAnother(const JID &contact)
ChatController* ChatsManager::createNewChatController(const JID& contact) {
assert(chatControllers_.find(contact) == chatControllers_.end());
- std::shared_ptr<ChatMessageParser> chatMessageParser = std::make_shared<ChatMessageParser>(emoticons_, highlightManager_->getRules(), false); /* a message parser that knows this is a chat (not a room/MUC) */
+ std::shared_ptr<ChatMessageParser> chatMessageParser = std::make_shared<ChatMessageParser>(emoticons_, highlightManager_->getConfiguration(), ChatMessageParser::Mode::Chat); /* a message parser that knows this is a chat (not a room/MUC) */
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_, clientBlockListManager_, chatMessageParser, autoAcceptMUCInviteDecider_);
chatControllers_[contact] = controller;
controller->setAvailableServerFeatures(serverDiscoInfo_);
@@ -835,8 +835,8 @@ MUC::ref ChatsManager::handleJoinMUCRequest(const JID &mucJID, const boost::opti
if (reuseChatwindow) {
chatWindowFactoryAdapter = new SingleChatWindowFactoryAdapter(reuseChatwindow);
}
- std::shared_ptr<ChatMessageParser> chatMessageParser = std::make_shared<ChatMessageParser>(emoticons_, highlightManager_->getRules(), true); /* a message parser that knows this is a room/MUC (not a chat) */
- controller = new MUCController(jid_, muc, password, nick, stanzaChannel_, iqRouter_, reuseChatwindow ? chatWindowFactoryAdapter : chatWindowFactory_, presenceOracle_, avatarManager_, uiEventStream_, false, timerFactory_, eventController_, entityCapsProvider_, roster_, historyController_, mucRegistry_, highlightManager_, clientBlockListManager_, chatMessageParser, isImpromptu, autoAcceptMUCInviteDecider_, vcardManager_, mucBookmarkManager_);
+ std::shared_ptr<ChatMessageParser> chatMessageParser = std::make_shared<ChatMessageParser>(emoticons_, highlightManager_->getConfiguration(), ChatMessageParser::Mode::GroupChat); /* a message parser that knows this is a room/MUC (not a chat) */
+ controller = new MUCController(jid_, muc, password, nick, stanzaChannel_, iqRouter_, reuseChatwindow ? chatWindowFactoryAdapter : chatWindowFactory_, nickResolver_, presenceOracle_, avatarManager_, uiEventStream_, false, timerFactory_, eventController_, entityCapsProvider_, roster_, historyController_, mucRegistry_, highlightManager_, clientBlockListManager_, chatMessageParser, isImpromptu, autoAcceptMUCInviteDecider_, vcardManager_, mucBookmarkManager_);
if (chatWindowFactoryAdapter) {
/* The adapters are only passed to chat windows, which are deleted in their
* controllers' dtor, which are deleted in ChatManager's dtor. The adapters
diff --git a/Swift/Controllers/Chat/MUCController.cpp b/Swift/Controllers/Chat/MUCController.cpp
index df54d73..c476cf3 100644
--- a/Swift/Controllers/Chat/MUCController.cpp
+++ b/Swift/Controllers/Chat/MUCController.cpp
@@ -34,7 +34,7 @@
#include <SwifTools/TabComplete.h>
#include <Swift/Controllers/Chat/ChatMessageParser.h>
-#include <Swift/Controllers/Highlighter.h>
+#include <Swift/Controllers/Highlighting/Highlighter.h>
#include <Swift/Controllers/Intl.h>
#include <Swift/Controllers/Roster/ContactRosterItem.h>
#include <Swift/Controllers/Roster/GroupRosterItem.h>
@@ -80,6 +80,7 @@ MUCController::MUCController (
StanzaChannel* stanzaChannel,
IQRouter* iqRouter,
ChatWindowFactory* chatWindowFactory,
+ NickResolver* nickResolver,
PresenceOracle* presenceOracle,
AvatarManager* avatarManager,
UIEventStream* uiEventStream,
@@ -97,7 +98,7 @@ MUCController::MUCController (
AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider,
VCardManager* vcardManager,
MUCBookmarkManager* mucBookmarkManager) :
- ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, muc->getJID(), presenceOracle, avatarManager, useDelayForLatency, uiEventStream, eventController, timerFactory, entityCapsProvider, historyController, mucRegistry, highlightManager, chatMessageParser, autoAcceptMUCInviteDecider), muc_(muc), nick_(nick), desiredNick_(nick), password_(password), renameCounter_(0), isImpromptu_(isImpromptu), isImpromptuAlreadyConfigured_(false), clientBlockListManager_(clientBlockListManager), mucBookmarkManager_(mucBookmarkManager) {
+ ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, muc->getJID(), nickResolver, presenceOracle, avatarManager, useDelayForLatency, uiEventStream, eventController, timerFactory, entityCapsProvider, historyController, mucRegistry, highlightManager, chatMessageParser, autoAcceptMUCInviteDecider), muc_(muc), nick_(nick), desiredNick_(nick), password_(password), renameCounter_(0), isImpromptu_(isImpromptu), isImpromptuAlreadyConfigured_(false), clientBlockListManager_(clientBlockListManager), mucBookmarkManager_(mucBookmarkManager) {
parting_ = true;
joined_ = false;
lastWasPresence_ = false;
@@ -134,8 +135,7 @@ MUCController::MUCController (
muc_->onAffiliationListReceived.connect(boost::bind(&MUCController::handleAffiliationListReceived, this, _1, _2));
muc_->onConfigurationFailed.connect(boost::bind(&MUCController::handleConfigurationFailed, this, _1));
muc_->onConfigurationFormReceived.connect(boost::bind(&MUCController::handleConfigurationFormReceived, this, _1));
- highlighter_->setMode(isImpromptu_ ? Highlighter::ChatMode : Highlighter::MUCMode);
- highlighter_->setNick(nick_);
+ chatMessageParser_->setNick(nick_);
if (timerFactory && stanzaChannel_->isAvailable()) {
loginCheckTimer_ = std::shared_ptr<Timer>(timerFactory->createTimer(MUC_JOIN_WARNING_TIMEOUT_MILLISECONDS));
loginCheckTimer_->onTick.connect(boost::bind(&MUCController::handleJoinTimeoutTick, this));
@@ -593,10 +593,11 @@ void MUCController::postHandleIncomingMessage(std::shared_ptr<MessageEvent> mess
std::shared_ptr<Message> message = messageEvent->getStanza();
if (joined_ && messageEvent->getStanza()->getFrom().getResource() != nick_ && !message->getPayload<Delay>()) {
if (messageTargetsMe(message) || isImpromptu_) {
+ highlighter_->handleSystemNotifications(chatMessage, messageEvent);
eventController_->handleIncomingEvent(messageEvent);
}
if (!messageEvent->getConcluded()) {
- handleHighlightActions(chatMessage);
+ highlighter_->handleSoundNotifications(chatMessage);
}
}
}
@@ -1111,7 +1112,7 @@ void MUCController::checkDuplicates(std::shared_ptr<Message> newMessage) {
void MUCController::setNick(const std::string& nick) {
nick_ = nick;
- highlighter_->setNick(nick_);
+ chatMessageParser_->setNick(nick);
}
Form::ref MUCController::buildImpromptuRoomConfiguration(Form::ref roomConfigurationForm) {
diff --git a/Swift/Controllers/Chat/MUCController.h b/Swift/Controllers/Chat/MUCController.h
index 7ec2eb4..6244f6d 100644
--- a/Swift/Controllers/Chat/MUCController.h
+++ b/Swift/Controllers/Chat/MUCController.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2016 Isode Limited.
+ * Copyright (c) 2010-2017 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -54,7 +54,7 @@ namespace Swift {
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* xmppRoster, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager, ClientBlockListManager* clientBlockListManager, std::shared_ptr<ChatMessageParser> chatMessageParser, bool isImpromptu, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider, VCardManager* vcardManager, MUCBookmarkManager* mucBookmarkManager);
+ MUCController(const JID& self, MUC::ref muc, const boost::optional<std::string>& password, const std::string &nick, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, AvatarManager* avatarManager, UIEventStream* events, bool useDelayForLatency, TimerFactory* timerFactory, EventController* eventController, EntityCapsProvider* entityCapsProvider, XMPPRoster* xmppRoster, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager, ClientBlockListManager* clientBlockListManager, std::shared_ptr<ChatMessageParser> chatMessageParser, bool isImpromptu, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider, VCardManager* vcardManager, MUCBookmarkManager* mucBookmarkManager);
virtual ~MUCController();
boost::signals2::signal<void ()> onUserLeft;
boost::signals2::signal<void ()> onUserJoined;
diff --git a/Swift/Controllers/Chat/UnitTest/ChatMessageParserTest.cpp b/Swift/Controllers/Chat/UnitTest/ChatMessageParserTest.cpp
index bc72b33..163a38a 100644
--- a/Swift/Controllers/Chat/UnitTest/ChatMessageParserTest.cpp
+++ b/Swift/Controllers/Chat/UnitTest/ChatMessageParserTest.cpp
@@ -1,30 +1,22 @@
/*
- * Copyright (c) 2013-2016 Isode Limited.
+ * Copyright (c) 2013-2017 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
-#include <cppunit/extensions/HelperMacros.h>
-#include <cppunit/extensions/TestFactoryRegistry.h>
-#include <hippomocks.h>
+#include <gtest/gtest.h>
#include <Swift/Controllers/Chat/ChatMessageParser.h>
+#include <Swift/Controllers/Highlighting/HighlightConfiguration.h>
+#include <Swift/Controllers/Highlighting/HighlightManager.h>
+#include <Swift/Controllers/Settings/DummySettingsProvider.h>
using namespace Swift;
-class ChatMessageParserTest : public CppUnit::TestFixture {
- CPPUNIT_TEST_SUITE(ChatMessageParserTest);
- CPPUNIT_TEST(testFullBody);
- CPPUNIT_TEST(testOneEmoticon);
- CPPUNIT_TEST(testBareEmoticon);
- CPPUNIT_TEST(testHiddenEmoticon);
- CPPUNIT_TEST(testEndlineEmoticon);
- CPPUNIT_TEST(testBoundedEmoticons);
- CPPUNIT_TEST(testNoColourNoHighlight);
- CPPUNIT_TEST_SUITE_END();
-
-public:
- void setUp() {
+// Common test state
+class ChatMessageParserTest : public ::testing::Test {
+protected:
+ virtual void SetUp() {
smile1_ = ":)";
smile1Path_ = "/blah/smile1.png";
smile2_ = ":(";
@@ -33,244 +25,54 @@ public:
emoticons_[smile2_] = smile2Path_;
}
- void tearDown() {
+ virtual void TearDown() {
emoticons_.clear();
}
- void assertText(const ChatWindow::ChatMessage& result, size_t index, const std::string& text) {
+ static void assertText(const ChatWindow::ChatMessage& result, size_t index, const std::string& text) {
+ ASSERT_LT(index, result.getParts().size());
std::shared_ptr<ChatWindow::ChatTextMessagePart> part = std::dynamic_pointer_cast<ChatWindow::ChatTextMessagePart>(result.getParts()[index]);
- CPPUNIT_ASSERT_EQUAL(text, part->text);
+ ASSERT_EQ(text, part->text);
}
- void assertEmoticon(const ChatWindow::ChatMessage& result, size_t index, const std::string& text, const std::string& path) {
+ static void assertEmoticon(const ChatWindow::ChatMessage& result, size_t index, const std::string& text, const std::string& path) {
+ ASSERT_LT(index, result.getParts().size());
std::shared_ptr<ChatWindow::ChatEmoticonMessagePart> part = std::dynamic_pointer_cast<ChatWindow::ChatEmoticonMessagePart>(result.getParts()[index]);
- CPPUNIT_ASSERT(!!part);
- CPPUNIT_ASSERT_EQUAL(text, part->alternativeText);
- CPPUNIT_ASSERT_EQUAL(path, part->imagePath);
+ ASSERT_NE(nullptr, part);
+ ASSERT_EQ(text, part->alternativeText);
+ ASSERT_EQ(path, part->imagePath);
}
-#define assertHighlight(RESULT, INDEX, TEXT, EXPECTED_HIGHLIGHT) \
- { \
- std::shared_ptr<ChatWindow::ChatHighlightingMessagePart> part = std::dynamic_pointer_cast<ChatWindow::ChatHighlightingMessagePart>(RESULT.getParts()[INDEX]); \
- CPPUNIT_ASSERT_EQUAL(std::string(TEXT), part->text); \
- CPPUNIT_ASSERT(EXPECTED_HIGHLIGHT == part->action); \
- }
-
- void assertURL(const ChatWindow::ChatMessage& result, size_t index, const std::string& text) {
+ static void assertURL(const ChatWindow::ChatMessage& result, size_t index, const std::string& text) {
+ ASSERT_LT(index, result.getParts().size());
std::shared_ptr<ChatWindow::ChatURIMessagePart> part = std::dynamic_pointer_cast<ChatWindow::ChatURIMessagePart>(result.getParts()[index]);
- CPPUNIT_ASSERT_EQUAL(text, part->target);
- }
-
- static HighlightRule ruleFromKeyword(const std::string& keyword, bool matchCase, bool matchWholeWord)
- {
- HighlightRule rule;
- std::vector<std::string> keywords;
- keywords.push_back(keyword);
- rule.setKeywords(keywords);
- rule.setMatchCase(matchCase);
- rule.setMatchWholeWords(matchWholeWord);
- rule.setMatchChat(true);
- rule.getAction().setTextBackground("white");
- return rule;
- }
-
- static const HighlightRulesListPtr ruleListFromKeyword(const std::string& keyword, bool matchCase, bool matchWholeWord)
- {
- std::shared_ptr<HighlightManager::HighlightRulesList> list = std::make_shared<HighlightManager::HighlightRulesList>();
- list->addRule(ruleFromKeyword(keyword, matchCase, matchWholeWord));
- return list;
- }
-
- static const HighlightRulesListPtr ruleListFromKeywords(const HighlightRule &rule1, const HighlightRule &rule2)
- {
- std::shared_ptr<HighlightManager::HighlightRulesList> list = std::make_shared<HighlightManager::HighlightRulesList>();
- list->addRule(rule1);
- list->addRule(rule2);
- return list;
- }
-
- static HighlightRulesListPtr ruleListWithNickHighlight(bool withHighlightColour = true)
- {
- HighlightRule rule;
- rule.setMatchChat(true);
- rule.setNickIsKeyword(true);
- rule.setMatchCase(true);
- rule.setMatchWholeWords(true);
- if (withHighlightColour) {
- rule.getAction().setTextBackground("white");
- }
- std::shared_ptr<HighlightManager::HighlightRulesList> list = std::make_shared<HighlightManager::HighlightRulesList>();
- list->addRule(rule);
- return list;
- }
-
- void testFullBody() {
- const std::string no_special_message = "a message with no special content";
- ChatMessageParser testling(emoticons_, std::make_shared<HighlightManager::HighlightRulesList>());
- ChatWindow::ChatMessage result = testling.parseMessageBody(no_special_message);
- assertText(result, 0, no_special_message);
-
- HighlightRulesListPtr highlightRuleList = ruleListFromKeyword("trigger", false, false);
- testling = ChatMessageParser(emoticons_, highlightRuleList);
- result = testling.parseMessageBody(":) shiny :( trigger :) http://wonderland.lit/blah http://denmark.lit boom boom");
- assertEmoticon(result, 0, smile1_, smile1Path_);
- assertText(result, 1, " shiny ");
- assertEmoticon(result, 2, smile2_, smile2Path_);
- assertText(result, 3, " ");
- assertHighlight(result, 4, "trigger", highlightRuleList->getRule(0).getAction());
- assertText(result, 5, " ");
- assertEmoticon(result, 6, smile1_, smile1Path_);
- assertText(result, 7, " ");
- assertURL(result, 8, "http://wonderland.lit/blah");
- assertText(result, 9, " ");
- assertURL(result, 10, "http://denmark.lit");
- assertText(result, 11, " boom boom");
-
- testling = ChatMessageParser(emoticons_, ruleListFromKeyword("trigger", false, false));
- result = testling.parseMessageBody("testtriggermessage");
- assertText(result, 0, "test");
- assertHighlight(result, 1, "trigger", highlightRuleList->getRule(0).getAction());
- assertText(result, 2, "message");
-
- testling = ChatMessageParser(emoticons_, ruleListFromKeyword("trigger", false, true));
- result = testling.parseMessageBody("testtriggermessage");
- assertText(result, 0, "testtriggermessage");
-
- testling = ChatMessageParser(emoticons_, ruleListFromKeyword("trigger", true, false));
- result = testling.parseMessageBody("TrIgGeR");
- assertText(result, 0, "TrIgGeR");
-
- testling = ChatMessageParser(emoticons_, ruleListFromKeyword("trigger", false, false));
- result = testling.parseMessageBody("TrIgGeR");
- assertHighlight(result, 0, "TrIgGeR", highlightRuleList->getRule(0).getAction());
-
- testling = ChatMessageParser(emoticons_, ruleListFromKeyword("trigger", false, false));
- result = testling.parseMessageBody("partialTrIgGeRmatch");
- assertText(result, 0, "partial");
- assertHighlight(result, 1, "TrIgGeR", highlightRuleList->getRule(0).getAction());
- assertText(result, 2, "match");
-
- testling = ChatMessageParser(emoticons_, ruleListFromKeywords(ruleFromKeyword("one", false, false), ruleFromKeyword("three", false, false)));
- result = testling.parseMessageBody("zero one two three");
- assertText(result, 0, "zero ");
- assertHighlight(result, 1, "one", highlightRuleList->getRule(0).getAction());
- assertText(result, 2, " two ");
- assertHighlight(result, 3, "three", highlightRuleList->getRule(0).getAction());
-
- testling = ChatMessageParser(emoticons_, ruleListFromKeywords(ruleFromKeyword("one", false, false), ruleFromKeyword("three", false, false)));
- result = testling.parseMessageBody("zero oNe two tHrEe");
- assertText(result, 0, "zero ");
- assertHighlight(result, 1, "oNe", highlightRuleList->getRule(0).getAction());
- assertText(result, 2, " two ");
- assertHighlight(result, 3, "tHrEe", highlightRuleList->getRule(0).getAction());
-
- testling = ChatMessageParser(emoticons_, ruleListFromKeywords(ruleFromKeyword("one", false, false), ruleFromKeyword("three", true, false)));
- result = testling.parseMessageBody("zero oNe two tHrEe");
- assertText(result, 0, "zero ");
- assertHighlight(result, 1, "oNe", highlightRuleList->getRule(0).getAction());
- assertText(result, 2, " two tHrEe");
-
- testling = ChatMessageParser(emoticons_, ruleListFromKeywords(ruleFromKeyword("one", true, false), ruleFromKeyword("three", true, false)));
- result = testling.parseMessageBody("zero oNe two tHrEe");
- assertText(result, 0, "zero oNe two tHrEe");
-
- testling = ChatMessageParser(emoticons_, ruleListFromKeywords(ruleFromKeyword("one", false, false), ruleFromKeyword("three", false, false)));
- result = testling.parseMessageBody("zeroonetwothree");
- assertText(result, 0, "zero");
- assertHighlight(result, 1, "one", highlightRuleList->getRule(0).getAction());
- assertText(result, 2, "two");
- assertHighlight(result, 3, "three", highlightRuleList->getRule(0).getAction());
-
- testling = ChatMessageParser(emoticons_, ruleListFromKeywords(ruleFromKeyword("one", true, false), ruleFromKeyword("three", false, false)));
- result = testling.parseMessageBody("zeroOnEtwoThReE");
- assertText(result, 0, "zeroOnEtwo");
- assertHighlight(result, 1, "ThReE", highlightRuleList->getRule(0).getAction());
-
- testling = ChatMessageParser(emoticons_, ruleListFromKeywords(ruleFromKeyword("one", false, true), ruleFromKeyword("three", false, false)));
- result = testling.parseMessageBody("zeroonetwothree");
- assertText(result, 0, "zeroonetwo");
- assertHighlight(result, 1, "three", highlightRuleList->getRule(0).getAction());
-
- testling = ChatMessageParser(emoticons_, ruleListFromKeywords(ruleFromKeyword("one", false, true), ruleFromKeyword("three", false, true)));
- result = testling.parseMessageBody("zeroonetwothree");
- assertText(result, 0, "zeroonetwothree");
-
- testling = ChatMessageParser(emoticons_, ruleListWithNickHighlight());
- result = testling.parseMessageBody("Alice", "Alice");
- assertHighlight(result, 0, "Alice", highlightRuleList->getRule(0).getAction());
-
- testling = ChatMessageParser(emoticons_, ruleListWithNickHighlight());
- result = testling.parseMessageBody("TextAliceText", "Alice");
- assertText(result, 0, "TextAliceText");
-
- testling = ChatMessageParser(emoticons_, ruleListWithNickHighlight());
- result = testling.parseMessageBody("Text Alice Text", "Alice");
- assertText(result, 0, "Text ");
- assertHighlight(result, 1, "Alice", highlightRuleList->getRule(0).getAction());
- assertText(result, 2, " Text");
-
- testling = ChatMessageParser(emoticons_, ruleListWithNickHighlight());
- result = testling.parseMessageBody("Alice Text", "Alice");
- assertHighlight(result, 0, "Alice", highlightRuleList->getRule(0).getAction());
- assertText(result, 1, " Text");
-
- testling = ChatMessageParser(emoticons_, ruleListWithNickHighlight());
- result = testling.parseMessageBody("Text Alice", "Alice");
- assertText(result, 0, "Text ");
- assertHighlight(result, 1, "Alice", highlightRuleList->getRule(0).getAction());
- }
-
- void testOneEmoticon() {
- ChatMessageParser testling(emoticons_, std::make_shared<HighlightManager::HighlightRulesList>());
- ChatWindow::ChatMessage result = testling.parseMessageBody(" :) ");
- assertText(result, 0, " ");
- assertEmoticon(result, 1, smile1_, smile1Path_);
- assertText(result, 2, " ");
- }
-
-
- void testBareEmoticon() {
- ChatMessageParser testling(emoticons_, std::make_shared<HighlightManager::HighlightRulesList>());
- ChatWindow::ChatMessage result = testling.parseMessageBody(":)");
- assertEmoticon(result, 0, smile1_, smile1Path_);
- }
-
- void testHiddenEmoticon() {
- ChatMessageParser testling(emoticons_, std::make_shared<HighlightManager::HighlightRulesList>());
- ChatWindow::ChatMessage result = testling.parseMessageBody("b:)a");
- assertText(result, 0, "b:)a");
- }
-
- void testEndlineEmoticon() {
- ChatMessageParser testling(emoticons_, std::make_shared<HighlightManager::HighlightRulesList>());
- ChatWindow::ChatMessage result = testling.parseMessageBody("Lazy:)");
- assertText(result, 0, "Lazy");
- assertEmoticon(result, 1, smile1_, smile1Path_);
+ ASSERT_EQ(text, part->target);
}
- void testBoundedEmoticons() {
- ChatMessageParser testling(emoticons_, std::make_shared<HighlightManager::HighlightRulesList>());
- ChatWindow::ChatMessage result = testling.parseMessageBody(":)Lazy:(");
- assertEmoticon(result, 0, smile1_, smile1Path_);
- assertText(result, 1, "Lazy");
- assertEmoticon(result, 2, smile2_, smile2Path_);
+ void assertHighlight(const ChatWindow::ChatMessage& result, size_t index, const std::string& text, const HighlightAction& action) {
+ ASSERT_LT(index, result.getParts().size());
+ std::shared_ptr<ChatWindow::ChatHighlightingMessagePart> part = std::dynamic_pointer_cast<ChatWindow::ChatHighlightingMessagePart>(result.getParts()[index]);
+ ASSERT_EQ(std::string(text), part->text);
+ ASSERT_EQ(action, part->action);
}
- void testEmoticonParenthesis() {
- ChatMessageParser testling(emoticons_, std::make_shared<HighlightManager::HighlightRulesList>());
- ChatWindow::ChatMessage result = testling.parseMessageBody("(Like this :))");
- assertText(result, 0, "(Like this ");
- assertEmoticon(result, 1, smile1_, smile1Path_);
- assertText(result, 2, ")");
+ static const std::shared_ptr<HighlightConfiguration> highlightConfigFromKeyword(const std::string& keyword, bool matchCase) {
+ std::shared_ptr<HighlightConfiguration> config = std::make_shared<HighlightConfiguration>();
+ HighlightConfiguration::KeywordHightlight keywordHighlight;
+ keywordHighlight.keyword = keyword;
+ keywordHighlight.matchCaseSensitive = matchCase;
+ keywordHighlight.action.setFrontColor(std::string("#121212"));
+ config->keywordHighlights.push_back(keywordHighlight);
+ return config;
}
- void testNoColourNoHighlight() {
- ChatMessageParser testling(emoticons_, ruleListWithNickHighlight(false));
- ChatWindow::ChatMessage result = testling.parseMessageBody("Alice", "Alice");
- assertText(result, 0, "Alice");
+ static const std::shared_ptr<HighlightConfiguration> mergeHighlightConfig(const std::shared_ptr<HighlightConfiguration>& configA, const std::shared_ptr<HighlightConfiguration>& configB) {
+ std::shared_ptr<HighlightConfiguration> config = std::make_shared<HighlightConfiguration>();
+ config->keywordHighlights.insert(config->keywordHighlights.end(), configA->keywordHighlights.begin(), configA->keywordHighlights.end());
+ config->keywordHighlights.insert(config->keywordHighlights.end(), configB->keywordHighlights.begin(), configB->keywordHighlights.end());
+ return config;
}
-private:
std::map<std::string, std::string> emoticons_;
std::string smile1_;
std::string smile1Path_;
@@ -278,4 +80,213 @@ private:
std::string smile2Path_;
};
-CPPUNIT_TEST_SUITE_REGISTRATION(ChatMessageParserTest);
+TEST_F(ChatMessageParserTest, testNoHighlightingWithEmtpyConfiguration) {
+ const std::string no_special_message = "a message with no special content";
+ ChatMessageParser testling(emoticons_, std::make_shared<HighlightConfiguration>());
+ auto result = testling.parseMessageBody(no_special_message);
+ assertText(result, 0, no_special_message);
+}
+
+TEST_F(ChatMessageParserTest, testSimpleHighlightAndEmojiAndUrlParsing) {
+ auto highlightConfig = highlightConfigFromKeyword("trigger", false);
+ auto testling = ChatMessageParser(emoticons_, highlightConfig);
+ auto result = testling.parseMessageBody(":) shiny :( trigger :) http://wonderland.lit/blah http://denmark.lit boom boom");
+ assertEmoticon(result, 0, smile1_, smile1Path_);
+ assertText(result, 1, " shiny ");
+ assertEmoticon(result, 2, smile2_, smile2Path_);
+ assertText(result, 3, " ");
+ assertHighlight(result, 4, "trigger", highlightConfig->keywordHighlights[0].action);
+ assertText(result, 5, " ");
+ assertEmoticon(result, 6, smile1_, smile1Path_);
+ assertText(result, 7, " ");
+ assertURL(result, 8, "http://wonderland.lit/blah");
+ assertText(result, 9, " ");
+ assertURL(result, 10, "http://denmark.lit");
+ assertText(result, 11, " boom boom");
+}
+
+TEST_F(ChatMessageParserTest, testNoKeywordHighlightAsPartOfLongerWords) {
+ auto testling = ChatMessageParser(emoticons_, highlightConfigFromKeyword("trigger", false));
+ auto result = testling.parseMessageBody("testtriggermessage");
+ assertText(result, 0, "testtriggermessage");
+}
+
+TEST_F(ChatMessageParserTest, testCaseInsensitiveKeyordHighlight) {
+ auto config = highlightConfigFromKeyword("trigger", true);
+ auto testling = ChatMessageParser(emoticons_, config);
+ auto result = testling.parseMessageBody("TrIgGeR");
+ assertText(result, 0, "TrIgGeR");
+
+ testling = ChatMessageParser(emoticons_, highlightConfigFromKeyword("trigger", false));
+ result = testling.parseMessageBody("TrIgGeR");
+ assertHighlight(result, 0, "TrIgGeR", config->keywordHighlights[0].action);
+}
+
+TEST_F(ChatMessageParserTest, testMultipleKeywordHighlights) {
+ auto config = mergeHighlightConfig(highlightConfigFromKeyword("one", false), highlightConfigFromKeyword("three", false));
+ auto testling = ChatMessageParser(emoticons_, config);
+ auto result = testling.parseMessageBody("zero one two three");
+ assertText(result, 0, "zero ");
+ assertHighlight(result, 1, "one", config->keywordHighlights[0].action);
+ assertText(result, 2, " two ");
+ assertHighlight(result, 3, "three", config->keywordHighlights[0].action);
+}
+
+TEST_F(ChatMessageParserTest, testMultipleCaseInsensitiveKeywordHighlights) {
+ auto config = mergeHighlightConfig(highlightConfigFromKeyword("one", false), highlightConfigFromKeyword("three", false));
+ auto testling = ChatMessageParser(emoticons_, config);
+ auto result = testling.parseMessageBody("zero oNe two tHrEe");
+ assertText(result, 0, "zero ");
+ assertHighlight(result, 1, "oNe", config->keywordHighlights[0].action);
+ assertText(result, 2, " two ");
+ assertHighlight(result, 3, "tHrEe", config->keywordHighlights[0].action);
+}
+
+TEST_F(ChatMessageParserTest, testMultipleCaseSensitiveKeywordHighlights) {
+ auto config = mergeHighlightConfig(highlightConfigFromKeyword("one", false), highlightConfigFromKeyword("three", true));
+ auto testling = ChatMessageParser(emoticons_, config);
+ auto result = testling.parseMessageBody("zero oNe two tHrEe");
+ assertText(result, 0, "zero ");
+ assertHighlight(result, 1, "oNe", config->keywordHighlights[0].action);
+ assertText(result, 2, " two tHrEe");
+
+ config = mergeHighlightConfig(highlightConfigFromKeyword("one", true), highlightConfigFromKeyword("three", false));
+ testling = ChatMessageParser(emoticons_, config);
+ result = testling.parseMessageBody("zero oNe two tHrEe");
+ assertText(result, 0, "zero oNe two ");
+ assertHighlight(result, 1, "tHrEe", config->keywordHighlights[0].action);
+}
+
+TEST_F(ChatMessageParserTest, testOneEmoticon) {
+ auto testling = ChatMessageParser(emoticons_, std::make_shared<HighlightConfiguration>());
+ auto result = testling.parseMessageBody(" :) ");
+ assertText(result, 0, " ");
+ assertEmoticon(result, 1, smile1_, smile1Path_);
+ assertText(result, 2, " ");
+}
+
+TEST_F(ChatMessageParserTest, testBareEmoticon) {
+ auto testling = ChatMessageParser(emoticons_, std::make_shared<HighlightConfiguration>());
+ auto result = testling.parseMessageBody(":)");
+ assertEmoticon(result, 0, smile1_, smile1Path_);
+}
+
+TEST_F(ChatMessageParserTest, testHiddenEmoticon) {
+ auto testling = ChatMessageParser(emoticons_, std::make_shared<HighlightConfiguration>());
+ auto result = testling.parseMessageBody("b:)a");
+ assertText(result, 0, "b:)a");
+}
+
+TEST_F(ChatMessageParserTest, testEndlineEmoticon) {
+ auto testling = ChatMessageParser(emoticons_, std::make_shared<HighlightConfiguration>());
+ auto result = testling.parseMessageBody("Lazy:)");
+ assertText(result, 0, "Lazy");
+ assertEmoticon(result, 1, smile1_, smile1Path_);
+}
+
+TEST_F(ChatMessageParserTest, testBoundedEmoticons) {
+ auto testling = ChatMessageParser(emoticons_, std::make_shared<HighlightConfiguration>());
+ auto result = testling.parseMessageBody(":)Lazy:(");
+ assertEmoticon(result, 0, smile1_, smile1Path_);
+ assertText(result, 1, "Lazy");
+ assertEmoticon(result, 2, smile2_, smile2Path_);
+}
+
+TEST_F(ChatMessageParserTest, testEmoticonParenthesis) {
+ auto testling = ChatMessageParser(emoticons_, std::make_shared<HighlightConfiguration>());
+ auto result = testling.parseMessageBody("(Like this :))");
+ assertText(result, 0, "(Like this ");
+ assertEmoticon(result, 1, smile1_, smile1Path_);
+ assertText(result, 2, ")");
+}
+
+TEST_F(ChatMessageParserTest, testSenderAndKeywordHighlighting) {
+ auto config = std::make_shared<HighlightConfiguration>();
+ auto contactHighlight = HighlightConfiguration::ContactHighlight();
+ contactHighlight.action.setFrontColor(std::string("#f0f0f0"));
+ contactHighlight.action.setBackColor(std::string("#0f0f0f"));
+ contactHighlight.name = "Romeo";
+ config->contactHighlights.push_back(contactHighlight);
+ auto keywordHighlight = HighlightConfiguration::KeywordHightlight();
+ keywordHighlight.action.setFrontColor(std::string("#abcdef"));
+ keywordHighlight.action.setBackColor(std::string("#fedcba"));
+ keywordHighlight.keyword = "XMPP";
+ config->keywordHighlights.push_back(keywordHighlight);
+ auto testling = ChatMessageParser(emoticons_, config);
+ auto result = testling.parseMessageBody("Heard any news about xmpp recently?", "Romeo");
+ assertText(result, 0, "Heard any news about ");
+ assertHighlight(result, 1, "xmpp", keywordHighlight.action);
+ assertText(result, 2, " recently?");
+ ASSERT_EQ(contactHighlight.action, result.getHighlightActionSender());
+ ASSERT_EQ(HighlightAction(), result.getHighlightActionOwnMention());
+}
+
+TEST_F(ChatMessageParserTest, testKeywordWithEmptyActionIsIgnored) {
+ auto config = std::make_shared<HighlightConfiguration>();
+ auto keywordHighlight = HighlightConfiguration::KeywordHightlight();
+ keywordHighlight.keyword = "XMPP";
+ config->keywordHighlights.push_back(keywordHighlight);
+ auto testling = ChatMessageParser(emoticons_, config);
+ auto result = testling.parseMessageBody("Heard any news about xmpp recently?", "Romeo");
+ assertText(result, 0, "Heard any news about xmpp recently?");
+ ASSERT_EQ(HighlightAction(), result.getHighlightActionOwnMention());
+}
+
+TEST_F(ChatMessageParserTest, testMeMessageAndOwnMention) {
+ auto config = std::make_shared<HighlightConfiguration>();
+ config->ownMentionAction.setFrontColor(std::string("#f0f0f0"));
+ config->ownMentionAction.setBackColor(std::string("#0f0f0f"));
+ config->ownMentionAction.setSoundFilePath(std::string("someSoundFile.wav"));
+ auto ownMentionActionForPart = config->ownMentionAction;
+ ownMentionActionForPart.setSoundFilePath(boost::optional<std::string>());
+ auto testling = ChatMessageParser(emoticons_, config);
+ testling.setNick("Juliet");
+ auto result = testling.parseMessageBody("/me wonders when Juliet is coming?", "Romeo");
+ assertText(result, 0, "wonders when ");
+ assertHighlight(result, 1, "Juliet", ownMentionActionForPart);
+ assertText(result, 2, " is coming?");
+ ASSERT_EQ(true, result.isMeCommand());
+ ASSERT_EQ(config->ownMentionAction, result.getHighlightActionOwnMention());
+}
+
+TEST_F(ChatMessageParserTest, testSoundAndNotificationOnDirectMessage) {
+ auto defaultConfiguration = std::make_shared<HighlightConfiguration>();
+ defaultConfiguration->playSoundOnIncomingDirectMessages = true;
+ defaultConfiguration->showNotificationOnIncomingDirectMessages = true;
+ defaultConfiguration->ownMentionAction.setFrontColor(std::string("black"));
+ defaultConfiguration->ownMentionAction.setBackColor(std::string("yellow"));
+ defaultConfiguration->ownMentionAction.setSoundFilePath(std::string(""));
+ defaultConfiguration->ownMentionAction.setSystemNotificationEnabled(true);
+
+ auto testling = ChatMessageParser(emoticons_, defaultConfiguration, ChatMessageParser::Mode::Chat);
+ auto result = testling.parseMessageBody("I wonder when Juliet is coming?", "Romeo");
+
+ ASSERT_EQ(std::string(""), result.getHighlightActionDirectMessage().getSoundFilePath().get_value_or(std::string("somethingElse")));
+ ASSERT_EQ(true, result.getHighlightActionDirectMessage().isSystemNotificationEnabled());
+ ASSERT_EQ(HighlightAction(), result.getHighlightActionOwnMention());
+}
+
+TEST_F(ChatMessageParserTest, testWithDefaultConfiguration) {
+ DummySettingsProvider settings;
+ HighlightManager manager(&settings);
+ manager.resetToDefaultConfiguration();
+ auto testling = ChatMessageParser(emoticons_, manager.getConfiguration(), ChatMessageParser::Mode::GroupChat);
+ testling.setNick("Juliet");
+ auto result = testling.parseMessageBody("Hello, how is it going?", "Romeo");
+ assertText(result, 0, "Hello, how is it going?");
+ ASSERT_EQ(HighlightAction(), result.getHighlightActionOwnMention());
+ ASSERT_EQ(HighlightAction(), result.getHighlightActionDirectMessage());
+ ASSERT_EQ(HighlightAction(), result.getHighlightActionGroupMessage());
+ ASSERT_EQ(HighlightAction(), result.getHighlightActionSender());
+
+ result = testling.parseMessageBody("Juliet, seen the new interface design?", "Romeo");
+ auto mentionKeywordAction = manager.getConfiguration()->ownMentionAction;
+ mentionKeywordAction.setSoundFilePath(boost::optional<std::string>());
+ mentionKeywordAction.setSystemNotificationEnabled(false);
+ assertHighlight(result, 0, "Juliet", mentionKeywordAction);
+ assertText(result, 1, ", seen the new interface design?");
+ ASSERT_EQ(manager.getConfiguration()->ownMentionAction, result.getHighlightActionOwnMention());
+ ASSERT_EQ(HighlightAction(), result.getHighlightActionDirectMessage());
+ ASSERT_EQ(HighlightAction(), result.getHighlightActionGroupMessage());
+ ASSERT_EQ(HighlightAction(), result.getHighlightActionSender());
+}
diff --git a/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp b/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp
index cff54f8..80f8346 100644
--- a/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp
+++ b/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2016 Isode Limited.
+ * Copyright (c) 2010-2017 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -131,7 +131,7 @@ public:
wbSessionManager_ = new WhiteboardSessionManager(iqRouter_, stanzaChannel_, presenceOracle_, entityCapsProvider_);
wbManager_ = new WhiteboardManager(whiteboardWindowFactory_, uiEventStream_, nickResolver_, wbSessionManager_);
highlightManager_ = new HighlightManager(settings_);
- highlightManager_->resetToDefaultRulesList();
+ highlightManager_->resetToDefaultConfiguration();
handledHighlightActions_ = 0;
soundsPlayed_.clear();
highlightManager_->onHighlight.connect(boost::bind(&ChatsManagerTest::handleHighlightAction, this, _1));
@@ -786,24 +786,17 @@ public:
}
void testChatControllerHighlightingNotificationTesting() {
- HighlightRule keywordRuleA;
- keywordRuleA.setMatchChat(true);
- std::vector<std::string> keywordsA;
- keywordsA.push_back("Romeo");
- keywordRuleA.setKeywords(keywordsA);
- keywordRuleA.getAction().setTextColor("yellow");
- keywordRuleA.getAction().setPlaySound(true);
- highlightManager_->insertRule(0, keywordRuleA);
-
- HighlightRule keywordRuleB;
- keywordRuleB.setMatchChat(true);
- std::vector<std::string> keywordsB;
- keywordsB.push_back("Juliet");
- keywordRuleB.setKeywords(keywordsB);
- keywordRuleB.getAction().setTextColor("green");
- keywordRuleB.getAction().setPlaySound(true);
- keywordRuleB.getAction().setSoundFile("/tmp/someotherfile.wav");
- highlightManager_->insertRule(0, keywordRuleB);
+ HighlightConfiguration::KeywordHightlight keywordRuleA;
+ keywordRuleA.keyword = "Romeo";
+ keywordRuleA.action.setFrontColor(boost::optional<std::string>("yellow"));
+ keywordRuleA.action.setSoundFilePath(boost::optional<std::string>(""));
+ highlightManager_->getConfiguration()->keywordHighlights.push_back(keywordRuleA);
+
+ HighlightConfiguration::KeywordHightlight keywordRuleB;
+ keywordRuleB.keyword = "Juliet";
+ keywordRuleB.action.setFrontColor(boost::optional<std::string>("green"));
+ keywordRuleB.action.setSoundFilePath(boost::optional<std::string>("/tmp/someotherfile.wav"));
+ highlightManager_->getConfiguration()->keywordHighlights.push_back(keywordRuleB);
JID messageJID = JID("testling@test.com");
@@ -817,28 +810,22 @@ public:
manager_->handleIncomingMessage(message);
CPPUNIT_ASSERT_EQUAL(2, handledHighlightActions_);
- CPPUNIT_ASSERT(soundsPlayed_.find(keywordRuleA.getAction().getSoundFile()) != soundsPlayed_.end());
- CPPUNIT_ASSERT(soundsPlayed_.find(keywordRuleB.getAction().getSoundFile()) != soundsPlayed_.end());
+ CPPUNIT_ASSERT(soundsPlayed_.find(keywordRuleA.action.getSoundFilePath().get_value_or("")) != soundsPlayed_.end());
+ CPPUNIT_ASSERT(soundsPlayed_.find(keywordRuleB.action.getSoundFilePath().get_value_or("")) != soundsPlayed_.end());
}
void testChatControllerHighlightingNotificationDeduplicateSounds() {
- HighlightRule keywordRuleA;
- keywordRuleA.setMatchChat(true);
- std::vector<std::string> keywordsA;
- keywordsA.push_back("Romeo");
- keywordRuleA.setKeywords(keywordsA);
- keywordRuleA.getAction().setTextColor("yellow");
- keywordRuleA.getAction().setPlaySound(true);
- highlightManager_->insertRule(0, keywordRuleA);
-
- HighlightRule keywordRuleB;
- keywordRuleB.setMatchChat(true);
- std::vector<std::string> keywordsB;
- keywordsB.push_back("Juliet");
- keywordRuleB.setKeywords(keywordsB);
- keywordRuleB.getAction().setTextColor("green");
- keywordRuleB.getAction().setPlaySound(true);
- highlightManager_->insertRule(0, keywordRuleB);
+ auto keywordRuleA = HighlightConfiguration::KeywordHightlight();
+ keywordRuleA.keyword = "Romeo";
+ keywordRuleA.action.setFrontColor(boost::optional<std::string>("yellow"));
+ keywordRuleA.action.setSoundFilePath(boost::optional<std::string>(""));
+ highlightManager_->getConfiguration()->keywordHighlights.push_back(keywordRuleA);
+
+ auto keywordRuleB = HighlightConfiguration::KeywordHightlight();
+ keywordRuleB.keyword = "Juliet";
+ keywordRuleB.action.setFrontColor(boost::optional<std::string>("green"));
+ keywordRuleB.action.setSoundFilePath(boost::optional<std::string>(""));
+ highlightManager_->getConfiguration()->keywordHighlights.push_back(keywordRuleB);
JID messageJID = JID("testling@test.com");
@@ -852,8 +839,8 @@ public:
manager_->handleIncomingMessage(message);
CPPUNIT_ASSERT_EQUAL(1, handledHighlightActions_);
- CPPUNIT_ASSERT(soundsPlayed_.find(keywordRuleA.getAction().getSoundFile()) != soundsPlayed_.end());
- CPPUNIT_ASSERT(soundsPlayed_.find(keywordRuleB.getAction().getSoundFile()) != soundsPlayed_.end());
+ CPPUNIT_ASSERT(soundsPlayed_.find(keywordRuleA.action.getSoundFilePath().get_value_or("")) != soundsPlayed_.end());
+ CPPUNIT_ASSERT(soundsPlayed_.find(keywordRuleB.action.getSoundFilePath().get_value_or("")) != soundsPlayed_.end());
}
void testChatControllerMeMessageHandling() {
@@ -922,12 +909,13 @@ public:
JID mucJID("mucroom@rooms.test.com");
std::string nickname = "toodles";
+ //highlightManager_->resetToDefaultConfiguration();
+
// add highlight rule for 'foo'
- HighlightRule fooHighlight;
- fooHighlight.setKeywords({"foo"});
- fooHighlight.setMatchMUC(true);
- fooHighlight.getAction().setTextBackground("green");
- highlightManager_->insertRule(0, fooHighlight);
+ HighlightConfiguration::KeywordHightlight keywordHighlight;
+ keywordHighlight.keyword = "foo";
+ keywordHighlight.action.setBackColor(boost::optional<std::string>("green"));
+ highlightManager_->getConfiguration()->keywordHighlights.push_back(keywordHighlight);
MockChatWindow* window = new MockChatWindow();
mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(mucJID, uiEventStream_).Return(window);
@@ -1141,8 +1129,8 @@ private:
void handleHighlightAction(const HighlightAction& action) {
handledHighlightActions_++;
- if (action.playSound()) {
- soundsPlayed_.insert(action.getSoundFile());
+ if (action.getSoundFilePath()) {
+ soundsPlayed_.insert(action.getSoundFilePath().get_value_or(""));
}
}
diff --git a/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp b/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp
index dad021f..eabf4c5 100644
--- a/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp
+++ b/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2016 Isode Limited.
+ * Copyright (c) 2010-2017 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -94,18 +94,20 @@ public:
highlightManager_ = new HighlightManager(settings_);
muc_ = std::make_shared<MockMUC>(mucJID_);
mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(muc_->getJID(), uiEventStream_).Return(window_);
- chatMessageParser_ = std::make_shared<ChatMessageParser>(std::map<std::string, std::string>(), highlightManager_->getRules(), true);
+ chatMessageParser_ = std::make_shared<ChatMessageParser>(std::map<std::string, std::string>(), highlightManager_->getConfiguration(), ChatMessageParser::Mode::GroupChat);
vcardStorage_ = new VCardMemoryStorage(crypto_.get());
vcardManager_ = new VCardManager(self_, iqRouter_, vcardStorage_);
+ nickResolver_ = new NickResolver(self_, xmppRoster_, vcardManager_, mucRegistry_);
clientBlockListManager_ = new ClientBlockListManager(iqRouter_);
mucBookmarkManager_ = new MUCBookmarkManager(iqRouter_);
- controller_ = new MUCController (self_, muc_, boost::optional<std::string>(), nick_, stanzaChannel_, iqRouter_, chatWindowFactory_, presenceOracle_, avatarManager_, uiEventStream_, false, timerFactory, eventController_, entityCapsProvider_, nullptr, nullptr, mucRegistry_, highlightManager_, clientBlockListManager_, chatMessageParser_, false, nullptr, vcardManager_, mucBookmarkManager_);
+ controller_ = new MUCController (self_, muc_, boost::optional<std::string>(), nick_, stanzaChannel_, iqRouter_, chatWindowFactory_, nickResolver_, presenceOracle_, avatarManager_, uiEventStream_, false, timerFactory, eventController_, entityCapsProvider_, nullptr, nullptr, mucRegistry_, highlightManager_, clientBlockListManager_, chatMessageParser_, false, nullptr, vcardManager_, mucBookmarkManager_);
}
void tearDown() {
delete controller_;
delete mucBookmarkManager_;
delete clientBlockListManager_;
+ delete nickResolver_;
delete vcardManager_;
delete vcardStorage_;
delete highlightManager_;
@@ -592,7 +594,7 @@ private:
ChatWindowFactory* chatWindowFactory_;
UserSearchWindowFactory* userSearchWindowFactory_;
MUCController* controller_;
-// NickResolver* nickResolver_;
+ NickResolver* nickResolver_;
PresenceOracle* presenceOracle_;
AvatarManager* avatarManager_;
StanzaChannelPresenceSender* presenceSender_;