summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'Swift/Controllers')
-rw-r--r--Swift/Controllers/Chat/ChatController.cpp4
-rw-r--r--Swift/Controllers/Chat/ChatController.h4
-rw-r--r--Swift/Controllers/Chat/ChatControllerBase.cpp12
-rw-r--r--Swift/Controllers/Chat/ChatControllerBase.h8
-rw-r--r--Swift/Controllers/Chat/ChatMessageParser.cpp75
-rw-r--r--Swift/Controllers/Chat/ChatMessageParser.h11
-rw-r--r--Swift/Controllers/Chat/ChatsManager.cpp9
-rw-r--r--Swift/Controllers/Chat/ChatsManager.h2
-rw-r--r--Swift/Controllers/Chat/MUCController.cpp2
-rw-r--r--Swift/Controllers/Chat/MUCController.h2
-rw-r--r--Swift/Controllers/Chat/UnitTest/ChatMessageParserTest.cpp134
-rw-r--r--Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp7
-rw-r--r--Swift/Controllers/HighlightAction.h31
-rw-r--r--Swift/Controllers/HighlightEditorController.cpp34
-rw-r--r--Swift/Controllers/HighlightEditorController.h20
-rw-r--r--Swift/Controllers/HighlightManager.cpp92
-rw-r--r--Swift/Controllers/HighlightManager.h32
-rw-r--r--Swift/Controllers/HighlightRule.cpp64
-rw-r--r--Swift/Controllers/HighlightRule.h30
-rw-r--r--Swift/Controllers/Highlighter.cpp14
-rw-r--r--Swift/Controllers/MainController.cpp9
-rw-r--r--Swift/Controllers/SConscript1
-rw-r--r--Swift/Controllers/UIInterfaces/HighlightEditorWindow.cpp19
-rw-r--r--Swift/Controllers/UIInterfaces/HighlightEditorWindow.h27
-rw-r--r--Swift/Controllers/UIInterfaces/HighlightEditorWindowFactory.h24
-rw-r--r--Swift/Controllers/UIInterfaces/UIFactory.h6
-rw-r--r--Swift/Controllers/UnitTest/HighlightRuleTest.cpp38
27 files changed, 505 insertions, 206 deletions
diff --git a/Swift/Controllers/Chat/ChatController.cpp b/Swift/Controllers/Chat/ChatController.cpp
index 2367761..9df7708 100644
--- a/Swift/Controllers/Chat/ChatController.cpp
+++ b/Swift/Controllers/Chat/ChatController.cpp
@@ -43,19 +43,19 @@
#include <Swift/Controllers/SettingConstants.h>
#include <Swift/Controllers/Highlighter.h>
#include <Swift/Controllers/Chat/ChatMessageParser.h>
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, ChatMessageParser* chatMessageParser, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider)
+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, boost::shared_ptr<ChatMessageParser> chatMessageParser, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider)
: ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, contact, presenceOracle, avatarManager, useDelayForLatency, eventStream, eventController, timerFactory, entityCapsProvider, historyController, mucRegistry, highlightManager, chatMessageParser, autoAcceptMUCInviteDecider), eventStream_(eventStream), userWantsReceipts_(userWantsReceipts), settings_(settings), clientBlockListManager_(clientBlockListManager) {
isInMUC_ = isInMUC;
lastWasPresence_ = false;
chatStateNotifier_ = new ChatStateNotifier(stanzaChannel, contact, entityCapsProvider);
chatStateTracker_ = new ChatStateTracker();
nickResolver_ = nickResolver;
presenceOracle_->onPresenceChange.connect(boost::bind(&ChatController::handlePresenceChange, this, _1));
chatStateTracker_->onChatStateChange.connect(boost::bind(&ChatWindow::setContactChatState, chatWindow_, _1));
stanzaChannel_->onStanzaAcked.connect(boost::bind(&ChatController::handleStanzaAcked, this, _1));
@@ -312,19 +312,19 @@ void ChatController::handleUIEvent(boost::shared_ptr<UIEvent> event) {
onConvertToMUC(detachChatWindow(), inviteEvent->getInvites(), inviteEvent->getReason());
}
}
void ChatController::postSendMessage(const std::string& body, boost::shared_ptr<Stanza> sentStanza) {
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(), HighlightAction());
+ replaceMessage(body, myLastMessageUIID_, true, 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>(), avatarManager_->getAvatarPath(selfJID_), boost::posix_time::microsec_clock::universal_time(), HighlightAction());
}
if (stanzaChannel_->getStreamManagementEnabled() && !myLastMessageUIID_.empty() ) {
chatWindow_->setAckState(myLastMessageUIID_, ChatWindow::Pending);
unackedStanzas_[sentStanza] = myLastMessageUIID_;
}
diff --git a/Swift/Controllers/Chat/ChatController.h b/Swift/Controllers/Chat/ChatController.h
index f8b6d8b..8b1bb9a 100644
--- a/Swift/Controllers/Chat/ChatController.h
+++ b/Swift/Controllers/Chat/ChatController.h
@@ -1,11 +1,11 @@
/*
- * Copyright (c) 2010-2013 Kevin Smith
+ * Copyright (c) 2010-2014 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
#pragma once
#include <Swift/Controllers/Chat/ChatControllerBase.h>
#include <map>
@@ -22,19 +22,19 @@ namespace Swift {
class FileTransferController;
class SettingsProvider;
class HistoryController;
class HighlightManager;
class ClientBlockListManager;
class UIEvent;
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, HighlightManager* highlightManager, ClientBlockListManager* clientBlockListManager, ChatMessageParser* chatMessageParser, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider);
+ 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, boost::shared_ptr<ChatMessageParser> chatMessageParser, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider);
virtual ~ChatController();
virtual void setToJID(const JID& jid);
virtual void setAvailableServerFeatures(boost::shared_ptr<DiscoInfo> info);
virtual void setOnline(bool online);
virtual void handleNewFileTransferController(FileTransferController* ftc);
virtual void handleWhiteboardSessionRequest(bool senderIsSelf);
virtual void handleWhiteboardStateChange(const ChatWindow::WhiteboardSessionState state);
virtual void setContactIsReceivingPresence(bool /*isReceivingPresence*/);
virtual ChatWindow* detachChatWindow();
diff --git a/Swift/Controllers/Chat/ChatControllerBase.cpp b/Swift/Controllers/Chat/ChatControllerBase.cpp
index 23137dc..5363e0c 100644
--- a/Swift/Controllers/Chat/ChatControllerBase.cpp
+++ b/Swift/Controllers/Chat/ChatControllerBase.cpp
@@ -1,11 +1,11 @@
/*
- * Copyright (c) 2010-2013 Kevin Smith
+ * Copyright (c) 2010-2014 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
#include <Swift/Controllers/Chat/ChatControllerBase.h>
#include <sstream>
#include <map>
@@ -36,19 +36,19 @@
#include <Swift/Controllers/UIInterfaces/ChatWindowFactory.h>
#include <Swift/Controllers/XMPPEvents/MUCInviteEvent.h>
#include <Swift/Controllers/HighlightManager.h>
#include <Swift/Controllers/Highlighter.h>
#include <Swift/Controllers/Chat/AutoAcceptMUCInviteDecider.h>
#include <Swift/Controllers/Chat/ChatMessageParser.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, HighlightManager* highlightManager, 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, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController, TimerFactory* timerFactory, EntityCapsProvider* entityCapsProvider, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager, boost::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();
setOnline(stanzaChannel->isAvailable() && iqRouter->isAvailable());
createDayChangeTimer();
}
@@ -195,27 +195,27 @@ void ChatControllerBase::showChatWindow() {
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 boost::filesystem::path& avatarPath, const boost::posix_time::ptime& time, const HighlightAction& highlight) {
if (boost::starts_with(message, "/me ")) {
return chatWindow_->addAction(chatMessageParser_->parseMessageBody(String::getSplittedAtFirst(message, ' ').second), senderName, senderIsSelf, label, pathToString(avatarPath), time, highlight);
} else {
- return chatWindow_->addMessage(chatMessageParser_->parseMessageBody(message), senderName, senderIsSelf, label, pathToString(avatarPath), time, highlight);
+ return chatWindow_->addMessage(chatMessageParser_->parseMessageBody(message,senderIsSelf), senderName, senderIsSelf, label, pathToString(avatarPath), time, highlight);
}
}
-void ChatControllerBase::replaceMessage(const std::string& message, const std::string& id, const boost::posix_time::ptime& time, const HighlightAction& highlight) {
+void ChatControllerBase::replaceMessage(const std::string& message, const std::string& id, bool senderIsSelf, const boost::posix_time::ptime& time, const HighlightAction& highlight) {
if (boost::starts_with(message, "/me ")) {
chatWindow_->replaceWithAction(chatMessageParser_->parseMessageBody(String::getSplittedAtFirst(message, ' ').second), id, time, highlight);
} else {
- chatWindow_->replaceMessage(chatMessageParser_->parseMessageBody(message), id, time, highlight);
+ chatWindow_->replaceMessage(chatMessageParser_->parseMessageBody(message,senderIsSelf), id, time, highlight);
}
}
bool ChatControllerBase::isFromContact(const JID& from) {
return from.toBare() == toJID_.toBare();
}
void ChatControllerBase::handleIncomingMessage(boost::shared_ptr<MessageEvent> messageEvent) {
preHandleIncomingMessage(messageEvent);
@@ -274,19 +274,19 @@ void ChatControllerBase::handleIncomingMessage(boost::shared_ptr<MessageEvent> m
}
boost::shared_ptr<Replace> replace = message->getPayload<Replace>();
if (replace) {
std::string body = message->getBody();
// Should check if the user has a previous message
std::map<JID, std::string>::iterator lastMessage;
lastMessage = lastMessagesUIID_.find(from);
if (lastMessage != lastMessagesUIID_.end()) {
- replaceMessage(body, lastMessagesUIID_[from], timeStamp, highlight);
+ replaceMessage(body, lastMessagesUIID_[from], isIncomingMessageFromMe(message), timeStamp, highlight);
}
}
else {
lastMessagesUIID_[from] = addMessage(body, senderDisplayNameFromMessage(from), isIncomingMessageFromMe(message), label, avatarManager_->getAvatarPath(from), timeStamp, highlight);
}
logMessage(body, from, selfJID_, timeStamp, true);
}
chatWindow_->show();
diff --git a/Swift/Controllers/Chat/ChatControllerBase.h b/Swift/Controllers/Chat/ChatControllerBase.h
index 7db94a4..cf0a4d2 100644
--- a/Swift/Controllers/Chat/ChatControllerBase.h
+++ b/Swift/Controllers/Chat/ChatControllerBase.h
@@ -1,11 +1,11 @@
/*
- * Copyright (c) 2010-2013 Kevin Smith
+ * Copyright (c) 2010-2014 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
#pragma once
#include <map>
#include <vector>
#include <string>
@@ -49,34 +49,34 @@ namespace Swift {
class ChatControllerBase : public boost::bsignals::trackable {
public:
virtual ~ChatControllerBase();
void showChatWindow();
void activateChatWindow();
virtual 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 boost::filesystem::path& 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);
+ void replaceMessage(const std::string& message, const std::string& id, bool senderIsSelf, 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;}
/** Used for determining when something is recent.*/
boost::signal<void (const std::string& /*activity*/)> onActivity;
boost::signal<void ()> onUnreadCountChanged;
int getUnreadCount();
const JID& getToJID() {return toJID_;}
void handleCapsChanged(const JID& jid);
void setCanStartImpromptuChats(bool supportsImpromptu);
virtual ChatWindow* detachChatWindow();
boost::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, ChatMessageParser* chatMessageParser, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider);
+ 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, boost::shared_ptr<ChatMessageParser> chatMessageParser, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider);
/**
* Pass the Message appended, and the stanza used to send it.
*/
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>, const HighlightAction&) {}
@@ -121,14 +121,14 @@ namespace Swift {
bool useDelayForLatency_;
EventController* eventController_;
boost::shared_ptr<Timer> dateChangeTimer_;
TimerFactory* timerFactory_;
EntityCapsProvider* entityCapsProvider_;
SecurityLabelsCatalog::Item lastLabel_;
HistoryController* historyController_;
MUCRegistry* mucRegistry_;
Highlighter* highlighter_;
- ChatMessageParser* chatMessageParser_;
+ boost::shared_ptr<ChatMessageParser> chatMessageParser_;
AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider_;
UIEventStream* eventStream_;
};
}
diff --git a/Swift/Controllers/Chat/ChatMessageParser.cpp b/Swift/Controllers/Chat/ChatMessageParser.cpp
index 698b766..09d93ac 100644
--- a/Swift/Controllers/Chat/ChatMessageParser.cpp
+++ b/Swift/Controllers/Chat/ChatMessageParser.cpp
@@ -14,25 +14,25 @@
#include <Swiften/Base/Regex.h>
#include <Swiften/Base/foreach.h>
#include <SwifTools/Linkify.h>
namespace Swift {
- ChatMessageParser::ChatMessageParser(const std::map<std::string, std::string>& emoticons) : emoticons_(emoticons) {
-
+ ChatMessageParser::ChatMessageParser(const std::map<std::string, std::string>& emoticons, HighlightRulesListPtr highlightRules, bool mucMode)
+ : emoticons_(emoticons), highlightRules_(highlightRules), mucMode_(mucMode) {
}
typedef std::pair<std::string, std::string> StringPair;
- ChatWindow::ChatMessage ChatMessageParser::parseMessageBody(const std::string& body) {
+ ChatWindow::ChatMessage ChatMessageParser::parseMessageBody(const std::string& body, bool senderIsSelf) {
ChatWindow::ChatMessage parsedMessage;
std::string remaining = body;
/* Parse one, URLs */
while (!remaining.empty()) {
bool found = false;
std::pair<std::vector<std::string>, size_t> links = Linkify::splitLink(remaining);
remaining = "";
for (size_t i = 0; i < links.first.size(); i++) {
const std::string& part = links.first[i];
@@ -45,20 +45,33 @@ namespace Swift {
found = true;
parsedMessage.append(boost::make_shared<ChatWindow::ChatURIMessagePart>(part));
}
else {
parsedMessage.append(boost::make_shared<ChatWindow::ChatTextMessagePart>(part));
}
}
}
}
-
+ /* do emoticon substitution */
+ parsedMessage = emoticonHighlight(parsedMessage);
+
+ if (!senderIsSelf) { /* do not highlight our own messsages */
+ /* do word-based color highlighting */
+ parsedMessage = splitHighlight(parsedMessage);
+ }
+
+ return parsedMessage;
+ }
+
+ ChatWindow::ChatMessage ChatMessageParser::emoticonHighlight(const ChatWindow::ChatMessage& message)
+ {
+ ChatWindow::ChatMessage parsedMessage = message;
std::string regexString;
/* Parse two, emoticons */
foreach (StringPair emoticon, emoticons_) {
/* Construct a regexp that finds an instance of any of the emoticons inside a group
* at the start or end of the line, or beside whitespace.
*/
regexString += regexString.empty() ? "" : "|";
std::string escaped = "(" + Regex::escape(emoticon.first) + ")";
@@ -118,10 +131,64 @@ namespace Swift {
else {
newMessage.append(part);
}
}
parsedMessage = newMessage;
}
return parsedMessage;
}
+
+ ChatWindow::ChatMessage ChatMessageParser::splitHighlight(const ChatWindow::ChatMessage& message)
+ {
+ 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 */
+ }
+ foreach(const boost::regex &regex, rule.getKeywordRegex()) {
+ ChatWindow::ChatMessage newMessage;
+ foreach (boost::shared_ptr<ChatWindow::ChatMessagePart> part, parsedMessage.getParts()) {
+ boost::shared_ptr<ChatWindow::ChatTextMessagePart> textPart;
+ if ((textPart = boost::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(boost::make_shared<ChatWindow::ChatTextMessagePart>(std::string(start, matchStart)));
+ }
+ boost::shared_ptr<ChatWindow::ChatHighlightingMessagePart> highlightPart = boost::make_shared<ChatWindow::ChatHighlightingMessagePart>();
+ highlightPart->text = match.str();
+ highlightPart->foregroundColor = rule.getAction().getTextColor();
+ highlightPart->backgroundColor = rule.getAction().getTextBackground();
+ newMessage.append(highlightPart);
+ start = matchEnd;
+ }
+ if (start != text.end()) {
+ /* If there's plain text after the last emoticon, record it */
+ newMessage.append(boost::make_shared<ChatWindow::ChatTextMessagePart>(std::string(start, text.end())));
+ }
+ }
+ catch (std::runtime_error) {
+ /* Basically too expensive to compute the regex results and it gave up, so pass through as text */
+ newMessage.append(part);
+ }
+ } else {
+ newMessage.append(part);
+ }
+ }
+ parsedMessage = newMessage;
+ }
+ }
+
+ return parsedMessage;
+ }
}
diff --git a/Swift/Controllers/Chat/ChatMessageParser.h b/Swift/Controllers/Chat/ChatMessageParser.h
index c9b9456..cff4ffa 100644
--- a/Swift/Controllers/Chat/ChatMessageParser.h
+++ b/Swift/Controllers/Chat/ChatMessageParser.h
@@ -1,23 +1,26 @@
/*
- * Copyright (c) 2013 Kevin Smith
+ * Copyright (c) 2013-2014 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
#pragma once
#include <string>
#include <Swift/Controllers/UIInterfaces/ChatWindow.h>
namespace Swift {
class ChatMessageParser {
public:
- ChatMessageParser(const std::map<std::string, std::string>& emoticons);
- ChatWindow::ChatMessage parseMessageBody(const std::string& body);
+ ChatMessageParser(const std::map<std::string, std::string>& emoticons, HighlightRulesListPtr highlightRules, bool mucMode = false);
+ ChatWindow::ChatMessage parseMessageBody(const std::string& body, bool senderIsSelf = false);
private:
+ ChatWindow::ChatMessage emoticonHighlight(const ChatWindow::ChatMessage& parsedMessage);
+ ChatWindow::ChatMessage splitHighlight(const ChatWindow::ChatMessage& parsedMessage);
std::map<std::string, std::string> emoticons_;
-
+ HighlightRulesListPtr highlightRules_;
+ bool mucMode_;
};
}
diff --git a/Swift/Controllers/Chat/ChatsManager.cpp b/Swift/Controllers/Chat/ChatsManager.cpp
index 1698b4a..8a077d1 100644
--- a/Swift/Controllers/Chat/ChatsManager.cpp
+++ b/Swift/Controllers/Chat/ChatsManager.cpp
@@ -139,35 +139,35 @@ ChatsManager::ChatsManager(
entityCapsProvider_(entityCapsProvider),
mucManager(mucManager),
ftOverview_(ftOverview),
roster_(roster),
eagleMode_(eagleMode),
settings_(settings),
historyController_(historyController),
whiteboardManager_(whiteboardManager),
highlightManager_(highlightManager),
+ emoticons_(emoticons),
clientBlockListManager_(clientBlockListManager),
inviteUserSearchController_(inviteUserSearchController),
vcardManager_(vcardManager) {
timerFactory_ = timerFactory;
eventController_ = eventController;
stanzaChannel_ = stanzaChannel;
iqRouter_ = iqRouter;
chatWindowFactory_ = chatWindowFactory;
nickResolver_ = nickResolver;
presenceOracle_ = presenceOracle;
avatarManager_ = NULL;
serverDiscoInfo_ = boost::make_shared<DiscoInfo>();
presenceSender_ = presenceSender;
uiEventStream_ = uiEventStream;
mucBookmarkManager_ = NULL;
profileSettings_ = profileSettings;
- chatMessageParser_ = new ChatMessageParser(emoticons);
presenceOracle_->onPresenceChange.connect(boost::bind(&ChatsManager::handlePresenceChange, this, _1));
uiEventConnection_ = uiEventStream_->onUIEvent.connect(boost::bind(&ChatsManager::handleUIEvent, this, _1));
chatListWindow_ = chatListWindowFactory->createChatListWindow(uiEventStream_);
chatListWindow_->onMUCBookmarkActivated.connect(boost::bind(&ChatsManager::handleMUCBookmarkActivated, this, _1));
chatListWindow_->onRecentActivated.connect(boost::bind(&ChatsManager::handleRecentActivated, this, _1));
chatListWindow_->onClearRecentsRequested.connect(boost::bind(&ChatsManager::handleClearRecentsRequested, this));
joinMUCWindow_ = NULL;
@@ -202,19 +202,18 @@ ChatsManager::~ChatsManager() {
delete joinMUCWindow_;
foreach (JIDChatControllerPair controllerPair, chatControllers_) {
delete controllerPair.second;
}
foreach (JIDMUCControllerPair controllerPair, mucControllers_) {
delete controllerPair.second;
}
delete mucBookmarkManager_;
delete mucSearchController_;
- delete chatMessageParser_;
delete autoAcceptMUCInviteDecider_;
}
void ChatsManager::saveRecents() {
std::stringstream serializeStream;
boost::archive::text_oarchive oa(serializeStream);
std::vector<ChatListWindow::Chat> recentsLimited = std::vector<ChatListWindow::Chat>(recentChats_.begin(), recentChats_.end());
if (recentsLimited.size() > 25) {
recentsLimited.erase(recentsLimited.begin() + 25, recentsLimited.end());
@@ -691,19 +690,20 @@ ChatController* ChatsManager::getChatControllerOrFindAnother(const JID &contact)
break;
}
}
}
return controller ? controller : createNewChatController(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_, highlightManager_, clientBlockListManager_, chatMessageParser_, autoAcceptMUCInviteDecider_);
+ boost::shared_ptr<ChatMessageParser> chatMessageParser = boost::make_shared<ChatMessageParser>(emoticons_, highlightManager_->getRules(), false); /* 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_);
controller->onActivity.connect(boost::bind(&ChatsManager::handleChatActivity, this, contact, _1, false));
controller->onUnreadCountChanged.connect(boost::bind(&ChatsManager::handleUnreadCountChanged, this, controller));
controller->onConvertToMUC.connect(boost::bind(&ChatsManager::handleTransformChatToMUC, this, controller, _1, _2, _3));
updatePresenceReceivingStateOnChatController(contact);
controller->setCanStartImpromptuChats(!localMUCServiceJID_.toString().empty());
return controller;
}
@@ -775,19 +775,20 @@ MUC::ref ChatsManager::handleJoinMUCRequest(const JID &mucJID, const boost::opti
if (isImpromptu) {
muc->setCreateAsReservedIfNew();
}
MUCController* controller = NULL;
SingleChatWindowFactoryAdapter* chatWindowFactoryAdapter = NULL;
if (reuseChatwindow) {
chatWindowFactoryAdapter = new SingleChatWindowFactoryAdapter(reuseChatwindow);
}
- controller = new MUCController(jid_, muc, password, nick, stanzaChannel_, iqRouter_, reuseChatwindow ? chatWindowFactoryAdapter : chatWindowFactory_, presenceOracle_, avatarManager_, uiEventStream_, false, timerFactory_, eventController_, entityCapsProvider_, roster_, historyController_, mucRegistry_, highlightManager_, chatMessageParser_, isImpromptu, autoAcceptMUCInviteDecider_, vcardManager_);
+ boost::shared_ptr<ChatMessageParser> chatMessageParser = boost::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_, chatMessageParser, isImpromptu, autoAcceptMUCInviteDecider_, vcardManager_);
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
* are also deleted there.*/
chatWindowFactoryAdapters_[controller] = chatWindowFactoryAdapter;
}
mucControllers_[mucJID] = controller;
controller->setAvailableServerFeatures(serverDiscoInfo_);
diff --git a/Swift/Controllers/Chat/ChatsManager.h b/Swift/Controllers/Chat/ChatsManager.h
index 88a0986..41435d9 100644
--- a/Swift/Controllers/Chat/ChatsManager.h
+++ b/Swift/Controllers/Chat/ChatsManager.h
@@ -168,19 +168,19 @@ namespace Swift {
ProfileSettingsProvider* profileSettings_;
FileTransferOverview* ftOverview_;
XMPPRoster* roster_;
bool eagleMode_;
bool userWantsReceipts_;
SettingsProvider* settings_;
HistoryController* historyController_;
WhiteboardManager* whiteboardManager_;
HighlightManager* highlightManager_;
+ std::map<std::string, std::string> emoticons_;
ClientBlockListManager* clientBlockListManager_;
- ChatMessageParser* chatMessageParser_;
JID localMUCServiceJID_;
boost::shared_ptr<DiscoServiceWalker> localMUCServiceFinderWalker_;
AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider_;
UserSearchController* inviteUserSearchController_;
IDGenerator idGenerator_;
VCardManager* vcardManager_;
};
}
diff --git a/Swift/Controllers/Chat/MUCController.cpp b/Swift/Controllers/Chat/MUCController.cpp
index d09bc3d..b467227 100644
--- a/Swift/Controllers/Chat/MUCController.cpp
+++ b/Swift/Controllers/Chat/MUCController.cpp
@@ -65,19 +65,19 @@ MUCController::MUCController (
UIEventStream* uiEventStream,
bool useDelayForLatency,
TimerFactory* timerFactory,
EventController* eventController,
EntityCapsProvider* entityCapsProvider,
XMPPRoster* roster,
HistoryController* historyController,
MUCRegistry* mucRegistry,
HighlightManager* highlightManager,
- ChatMessageParser* chatMessageParser,
+ boost::shared_ptr<ChatMessageParser> chatMessageParser,
bool isImpromptu,
AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider,
VCardManager* vcardManager) :
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) {
parting_ = true;
joined_ = false;
lastWasPresence_ = false;
shouldJoinOnReconnect_ = true;
doneGettingHistory_ = false;
diff --git a/Swift/Controllers/Chat/MUCController.h b/Swift/Controllers/Chat/MUCController.h
index feffaba..b5b5837 100644
--- a/Swift/Controllers/Chat/MUCController.h
+++ b/Swift/Controllers/Chat/MUCController.h
@@ -44,19 +44,19 @@ namespace Swift {
struct NickJoinPart {
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, HighlightManager* highlightManager, ChatMessageParser* chatMessageParser, bool isImpromptu, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider, VCardManager* vcardManager);
+ 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, boost::shared_ptr<ChatMessageParser> chatMessageParser, bool isImpromptu, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider, VCardManager* vcardManager);
virtual ~MUCController();
boost::signal<void ()> onUserLeft;
boost::signal<void ()> onUserJoined;
boost::signal<void ()> onImpromptuConfigCompleted;
virtual void setOnline(bool online);
void rejoin();
static void appendToJoinParts(std::vector<NickJoinPart>& joinParts, const NickJoinPart& newEvent);
static std::string generateJoinPartString(const std::vector<NickJoinPart>& joinParts, bool isImpromptu);
static std::string concatenateListOfNames(const std::vector<NickJoinPart>& joinParts);
diff --git a/Swift/Controllers/Chat/UnitTest/ChatMessageParserTest.cpp b/Swift/Controllers/Chat/UnitTest/ChatMessageParserTest.cpp
index 0a14303..5dca63a 100644
--- a/Swift/Controllers/Chat/UnitTest/ChatMessageParserTest.cpp
+++ b/Swift/Controllers/Chat/UnitTest/ChatMessageParserTest.cpp
@@ -42,84 +42,190 @@ public:
}
void assertEmoticon(const ChatWindow::ChatMessage& result, size_t index, const std::string& text, const std::string& path) {
boost::shared_ptr<ChatWindow::ChatEmoticonMessagePart> part = boost::dynamic_pointer_cast<ChatWindow::ChatEmoticonMessagePart>(result.getParts()[index]);
CPPUNIT_ASSERT(!!part);
CPPUNIT_ASSERT_EQUAL(text, part->alternativeText);
CPPUNIT_ASSERT_EQUAL(path, part->imagePath);
}
+ void assertHighlight(const ChatWindow::ChatMessage& result, size_t index, const std::string& text) {
+ boost::shared_ptr<ChatWindow::ChatHighlightingMessagePart> part = boost::dynamic_pointer_cast<ChatWindow::ChatHighlightingMessagePart>(result.getParts()[index]);
+ CPPUNIT_ASSERT_EQUAL(text, part->text);
+ }
+
void assertURL(const ChatWindow::ChatMessage& result, size_t index, const std::string& text) {
boost::shared_ptr<ChatWindow::ChatURIMessagePart> part = boost::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);
+ return rule;
+ }
+
+ static const HighlightRulesListPtr ruleListFromKeyword(const std::string& keyword, bool matchCase, bool matchWholeWord)
+ {
+ boost::shared_ptr<HighlightManager::HighlightRulesList> list = boost::make_shared<HighlightManager::HighlightRulesList>();
+ list->addRule(ruleFromKeyword(keyword, matchCase, matchWholeWord));
+ return list;
+ }
+
+ static const HighlightRulesListPtr ruleListFromKeywords(const HighlightRule &rule1, const HighlightRule &rule2)
+ {
+ boost::shared_ptr<HighlightManager::HighlightRulesList> list = boost::make_shared<HighlightManager::HighlightRulesList>();
+ list->addRule(rule1);
+ list->addRule(rule2);
+ return list;
+ }
+
void testFullBody() {
- ChatMessageParser testling(emoticons_);
- ChatWindow::ChatMessage result = testling.parseMessageBody(":) shiny :( :) http://wonderland.lit/blah http://denmark.lit boom boom");
+ const std::string no_special_message = "a message with no special content";
+ ChatMessageParser testling(emoticons_, boost::make_shared<HighlightManager::HighlightRulesList>());
+ ChatWindow::ChatMessage result = testling.parseMessageBody(no_special_message);
+ assertText(result, 0, no_special_message);
+
+ testling = ChatMessageParser(emoticons_, ruleListFromKeyword("trigger", false, false));
+ 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, " ");
- assertEmoticon(result, 4, smile1_, smile1Path_);
+ assertHighlight(result, 4, "trigger");
assertText(result, 5, " ");
- assertURL(result, 6, "http://wonderland.lit/blah");
+ assertEmoticon(result, 6, smile1_, smile1Path_);
assertText(result, 7, " ");
- assertURL(result, 8, "http://denmark.lit");
- assertText(result, 9, " boom boom");
+ 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");
+ 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");
+
+ testling = ChatMessageParser(emoticons_, ruleListFromKeyword("trigger", false, false));
+ result = testling.parseMessageBody("partialTrIgGeRmatch");
+ assertText(result, 0, "partial");
+ assertHighlight(result, 1, "TrIgGeR");
+ 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");
+ assertText(result, 2, " two ");
+ assertHighlight(result, 3, "three");
+
+ 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");
+ assertText(result, 2, " two ");
+ assertHighlight(result, 3, "tHrEe");
+
+ 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");
+ 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");
+ assertText(result, 2, "two");
+ assertHighlight(result, 3, "three");
+
+ testling = ChatMessageParser(emoticons_, ruleListFromKeywords(ruleFromKeyword("one", true, false), ruleFromKeyword("three", false, false)));
+ result = testling.parseMessageBody("zeroOnEtwoThReE");
+ assertText(result, 0, "zeroOnEtwo");
+ assertHighlight(result, 1, "ThReE");
+
+ testling = ChatMessageParser(emoticons_, ruleListFromKeywords(ruleFromKeyword("one", false, true), ruleFromKeyword("three", false, false)));
+ result = testling.parseMessageBody("zeroonetwothree");
+ assertText(result, 0, "zeroonetwo");
+ assertHighlight(result, 1, "three");
+
+ testling = ChatMessageParser(emoticons_, ruleListFromKeywords(ruleFromKeyword("one", false, true), ruleFromKeyword("three", false, true)));
+ result = testling.parseMessageBody("zeroonetwothree");
+ assertText(result, 0, "zeroonetwothree");
}
void testOneEmoticon() {
- ChatMessageParser testling(emoticons_);
+ ChatMessageParser testling(emoticons_, boost::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_);
+ ChatMessageParser testling(emoticons_, boost::make_shared<HighlightManager::HighlightRulesList>());
ChatWindow::ChatMessage result = testling.parseMessageBody(":)");
assertEmoticon(result, 0, smile1_, smile1Path_);
}
void testHiddenEmoticon() {
- ChatMessageParser testling(emoticons_);
+ ChatMessageParser testling(emoticons_, boost::make_shared<HighlightManager::HighlightRulesList>());
ChatWindow::ChatMessage result = testling.parseMessageBody("b:)a");
assertText(result, 0, "b:)a");
}
void testEndlineEmoticon() {
- ChatMessageParser testling(emoticons_);
+ ChatMessageParser testling(emoticons_, boost::make_shared<HighlightManager::HighlightRulesList>());
ChatWindow::ChatMessage result = testling.parseMessageBody("Lazy:)");
assertText(result, 0, "Lazy");
assertEmoticon(result, 1, smile1_, smile1Path_);
}
void testBoundedEmoticons() {
- ChatMessageParser testling(emoticons_);
+ ChatMessageParser testling(emoticons_, boost::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 testEmoticonParenthesis() {
- ChatMessageParser testling(emoticons_);
+ ChatMessageParser testling(emoticons_, boost::make_shared<HighlightManager::HighlightRulesList>());
ChatWindow::ChatMessage result = testling.parseMessageBody("(Like this :))");
assertText(result, 0, "(Like this ");
assertEmoticon(result, 1, smile1_, smile1Path_);
assertText(result, 2, ")");
}
-
private:
std::map<std::string, std::string> emoticons_;
std::string smile1_;
std::string smile1Path_;
std::string smile2_;
std::string smile2Path_;
};
CPPUNIT_TEST_SUITE_REGISTRATION(ChatMessageParserTest);
-
diff --git a/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp b/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp
index 7268878..bb22e43 100644
--- a/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp
+++ b/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp
@@ -1,11 +1,11 @@
/*
- * Copyright (c) 2010-2013 Kevin Smith
+ * Copyright (c) 2010-2014 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <boost/algorithm/string.hpp>
#include <hippomocks.h>
@@ -75,19 +75,19 @@ public:
avatarManager_ = new NullAvatarManager();
TimerFactory* timerFactory = NULL;
window_ = new MockChatWindow();
mucRegistry_ = new MUCRegistry();
entityCapsProvider_ = new DummyEntityCapsProvider();
settings_ = new DummySettingsProvider();
highlightManager_ = new HighlightManager(settings_);
muc_ = boost::make_shared<MockMUC>(mucJID_);
mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(muc_->getJID(), uiEventStream_).Return(window_);
- chatMessageParser_ = new ChatMessageParser(std::map<std::string, std::string>());
+ chatMessageParser_ = boost::make_shared<ChatMessageParser>(std::map<std::string, std::string>(), highlightManager_->getRules(), true);
vcardStorage_ = new VCardMemoryStorage(crypto_.get());
vcardManager_ = new VCardManager(self_, iqRouter_, vcardStorage_);
controller_ = new MUCController (self_, muc_, boost::optional<std::string>(), nick_, stanzaChannel_, iqRouter_, chatWindowFactory_, presenceOracle_, avatarManager_, uiEventStream_, false, timerFactory, eventController_, entityCapsProvider_, NULL, NULL, mucRegistry_, highlightManager_, chatMessageParser_, false, NULL, vcardManager_);
}
void tearDown() {
delete controller_;
delete vcardManager_;
delete vcardStorage_;
@@ -99,19 +99,18 @@ public:
delete mocks_;
delete uiEventStream_;
delete stanzaChannel_;
delete presenceSender_;
delete directedPresenceSender_;
delete iqRouter_;
delete iqChannel_;
delete mucRegistry_;
delete avatarManager_;
- delete chatMessageParser_;
}
void finishJoin() {
Presence::ref presence(new Presence());
presence->setFrom(JID(muc_->getJID().toString() + "/" + nick_));
MUCUserPayload::ref status(new MUCUserPayload());
MUCUserPayload::StatusCode code;
code.code = 110;
status->addStatusCode(code);
@@ -423,17 +422,17 @@ private:
StanzaChannelPresenceSender* presenceSender_;
DirectedPresenceSender* directedPresenceSender_;
MockRepository* mocks_;
UIEventStream* uiEventStream_;
MockChatWindow* window_;
MUCRegistry* mucRegistry_;
DummyEntityCapsProvider* entityCapsProvider_;
DummySettingsProvider* settings_;
HighlightManager* highlightManager_;
- ChatMessageParser* chatMessageParser_;
+ boost::shared_ptr<ChatMessageParser> chatMessageParser_;
boost::shared_ptr<CryptoProvider> crypto_;
VCardManager* vcardManager_;
VCardMemoryStorage* vcardStorage_;
};
CPPUNIT_TEST_SUITE_REGISTRATION(MUCControllerTest);
diff --git a/Swift/Controllers/HighlightAction.h b/Swift/Controllers/HighlightAction.h
index bfbed74..de1f201 100644
--- a/Swift/Controllers/HighlightAction.h
+++ b/Swift/Controllers/HighlightAction.h
@@ -1,45 +1,76 @@
/*
* Copyright (c) 2012 Maciej Niedzielski
* Licensed under the simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
+/*
+ * Copyright (c) 2014 Kevin Smith and Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
#pragma once
#include <string>
+#include <boost/archive/text_oarchive.hpp>
+#include <boost/archive/text_iarchive.hpp>
+
namespace Swift {
class HighlightRule;
class HighlightAction {
public:
HighlightAction() : highlightText_(false), playSound_(false) {}
bool highlightText() const { return highlightText_; }
void setHighlightText(bool highlightText);
+ /**
+ * Gets the foreground highlight color. If the string is empty, assume a default color.
+ */
const std::string& getTextColor() const { return textColor_; }
void setTextColor(const std::string& textColor) { textColor_ = textColor; }
+ /**
+ * Gets the background highlight color. If the string is empty, assume a default color.
+ */
const std::string& getTextBackground() const { return textBackground_; }
void setTextBackground(const std::string& textBackground) { textBackground_ = textBackground; }
bool playSound() const { return playSound_; }
void setPlaySound(bool playSound);
+ /**
+ * Gets the sound filename. If the string is empty, assume a default sound file.
+ */
const std::string& getSoundFile() const { return soundFile_; }
void setSoundFile(const std::string& soundFile) { soundFile_ = soundFile; }
bool isEmpty() const { return !highlightText_ && !playSound_; }
private:
+ friend class boost::serialization::access;
+ template<class Archive> void serialize(Archive & ar, const unsigned int version);
+
bool highlightText_;
std::string textColor_;
std::string textBackground_;
bool playSound_;
std::string soundFile_;
};
+ template<class Archive>
+ void HighlightAction::serialize(Archive& ar, const unsigned int /*version*/)
+ {
+ ar & highlightText_;
+ ar & textColor_;
+ ar & textBackground_;
+ ar & playSound_;
+ ar & soundFile_;
+ }
+
}
diff --git a/Swift/Controllers/HighlightEditorController.cpp b/Swift/Controllers/HighlightEditorController.cpp
index 899e4bb..38007f0 100644
--- a/Swift/Controllers/HighlightEditorController.cpp
+++ b/Swift/Controllers/HighlightEditorController.cpp
@@ -1,40 +1,56 @@
/*
* Copyright (c) 2012 Maciej Niedzielski
* Licensed under the simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
+/*
+ * Copyright (c) 2014 Kevin Smith and Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
#include <boost/bind.hpp>
#include <Swift/Controllers/HighlightEditorController.h>
-#include <Swift/Controllers/UIInterfaces/HighlightEditorWidget.h>
-#include <Swift/Controllers/UIInterfaces/HighlightEditorWidgetFactory.h>
#include <Swift/Controllers/UIEvents/RequestHighlightEditorUIEvent.h>
#include <Swift/Controllers/UIEvents/UIEventStream.h>
+#include <Swift/Controllers/UIInterfaces/HighlightEditorWindowFactory.h>
+#include <Swift/Controllers/UIInterfaces/HighlightEditorWindow.h>
+#include <Swift/Controllers/ContactSuggester.h>
namespace Swift {
-HighlightEditorController::HighlightEditorController(UIEventStream* uiEventStream, HighlightEditorWidgetFactory* highlightEditorWidgetFactory, HighlightManager* highlightManager) : highlightEditorWidgetFactory_(highlightEditorWidgetFactory), highlightEditorWidget_(NULL), highlightManager_(highlightManager)
+HighlightEditorController::HighlightEditorController(UIEventStream* uiEventStream, HighlightEditorWindowFactory* highlightEditorWindowFactory, HighlightManager* highlightManager)
+: highlightEditorWindowFactory_(highlightEditorWindowFactory), highlightEditorWindow_(NULL), highlightManager_(highlightManager), contactSuggester_(0)
{
uiEventStream->onUIEvent.connect(boost::bind(&HighlightEditorController::handleUIEvent, this, _1));
}
HighlightEditorController::~HighlightEditorController()
{
- delete highlightEditorWidget_;
- highlightEditorWidget_ = NULL;
+ delete highlightEditorWindow_;
+ highlightEditorWindow_ = NULL;
}
void HighlightEditorController::handleUIEvent(boost::shared_ptr<UIEvent> rawEvent)
{
boost::shared_ptr<RequestHighlightEditorUIEvent> event = boost::dynamic_pointer_cast<RequestHighlightEditorUIEvent>(rawEvent);
if (event) {
- if (!highlightEditorWidget_) {
- highlightEditorWidget_ = highlightEditorWidgetFactory_->createHighlightEditorWidget();
- highlightEditorWidget_->setHighlightManager(highlightManager_);
+ if (!highlightEditorWindow_) {
+ highlightEditorWindow_ = highlightEditorWindowFactory_->createHighlightEditorWindow();
+ highlightEditorWindow_->setHighlightManager(highlightManager_);
+ highlightEditorWindow_->onContactSuggestionsRequested.connect(boost::bind(&HighlightEditorController::handleContactSuggestionsRequested, this, _1));
}
- highlightEditorWidget_->show();
+ highlightEditorWindow_->show();
+ }
+}
+
+void HighlightEditorController::handleContactSuggestionsRequested(const std::string& text)
+{
+ if (contactSuggester_) {
+ highlightEditorWindow_->setContactSuggestions(contactSuggester_->getSuggestions(text));
}
}
}
diff --git a/Swift/Controllers/HighlightEditorController.h b/Swift/Controllers/HighlightEditorController.h
index 3868251..54322e2 100644
--- a/Swift/Controllers/HighlightEditorController.h
+++ b/Swift/Controllers/HighlightEditorController.h
@@ -1,38 +1,48 @@
/*
* Copyright (c) 2012 Maciej Niedzielski
* Licensed under the simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
+/*
+ * Copyright (c) 2014 Kevin Smith and Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
#pragma once
#include <boost/shared_ptr.hpp>
#include <Swift/Controllers/UIEvents/UIEvent.h>
namespace Swift {
class UIEventStream;
- class HighlightEditorWidgetFactory;
- class HighlightEditorWidget;
+ class HighlightEditorWindowFactory;
+ class HighlightEditorWindow;
class HighlightManager;
+ class ContactSuggester;
class HighlightEditorController {
public:
- HighlightEditorController(UIEventStream* uiEventStream, HighlightEditorWidgetFactory* highlightEditorWidgetFactory, HighlightManager* highlightManager);
+ HighlightEditorController(UIEventStream* uiEventStream, HighlightEditorWindowFactory* highlightEditorWindowFactory, HighlightManager* highlightManager);
~HighlightEditorController();
HighlightManager* getHighlightManager() const { return highlightManager_; }
+ void setContactSuggester(ContactSuggester *suggester) { contactSuggester_ = suggester; }
private:
void handleUIEvent(boost::shared_ptr<UIEvent> event);
+ void handleContactSuggestionsRequested(const std::string& text);
private:
- HighlightEditorWidgetFactory* highlightEditorWidgetFactory_;
- HighlightEditorWidget* highlightEditorWidget_;
+ HighlightEditorWindowFactory* highlightEditorWindowFactory_;
+ HighlightEditorWindow* highlightEditorWindow_;
HighlightManager* highlightManager_;
+ ContactSuggester* contactSuggester_;
};
}
diff --git a/Swift/Controllers/HighlightManager.cpp b/Swift/Controllers/HighlightManager.cpp
index 7ab578e..eac562f 100644
--- a/Swift/Controllers/HighlightManager.cpp
+++ b/Swift/Controllers/HighlightManager.cpp
@@ -1,21 +1,30 @@
/*
* Copyright (c) 2012 Maciej Niedzielski
* Licensed under the simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
+/*
+ * Copyright (c) 2014 Kevin Smith and Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
#include <cassert>
#include <boost/algorithm/string.hpp>
#include <boost/regex.hpp>
#include <boost/bind.hpp>
#include <boost/numeric/conversion/cast.hpp>
+#include <boost/serialization/vector.hpp>
+#include <boost/archive/text_oarchive.hpp>
+#include <boost/archive/text_iarchive.hpp>
#include <Swiften/Base/foreach.h>
#include <Swift/Controllers/HighlightManager.h>
#include <Swift/Controllers/Highlighter.h>
#include <Swift/Controllers/Settings/SettingsProvider.h>
#include <Swift/Controllers/SettingConstants.h>
/* How does highlighting work?
*
@@ -34,106 +43,89 @@
* which is handled by SoundController to play sound notification
*/
namespace Swift {
HighlightManager::HighlightManager(SettingsProvider* settings)
: settings_(settings)
, storingSettings_(false)
{
+ rules_ = boost::make_shared<HighlightRulesList>();
loadSettings();
settings_->onSettingChanged.connect(boost::bind(&HighlightManager::handleSettingChanged, this, _1));
}
void HighlightManager::handleSettingChanged(const std::string& settingPath)
{
if (!storingSettings_ && SettingConstants::HIGHLIGHT_RULES.getKey() == settingPath) {
loadSettings();
}
}
-void HighlightManager::loadSettings()
-{
- std::string highlightRules = settings_->getSetting(SettingConstants::HIGHLIGHT_RULES);
- if (highlightRules == "@") {
- rules_ = getDefaultRules();
- } else {
- rules_ = rulesFromString(highlightRules);
- }
-}
-
std::string HighlightManager::rulesToString() const
{
- std::string s;
- foreach (HighlightRule r, rules_) {
- s += r.toString() + '\f';
- }
- if (s.size()) {
- s.erase(s.end() - 1);
- }
- return s;
-}
-
-std::vector<HighlightRule> HighlightManager::rulesFromString(const std::string& rulesString)
-{
- std::vector<HighlightRule> rules;
- std::string s(rulesString);
- typedef boost::split_iterator<std::string::iterator> split_iterator;
- for (split_iterator it = boost::make_split_iterator(s, boost::first_finder("\f")); it != split_iterator(); ++it) {
- HighlightRule r = HighlightRule::fromString(boost::copy_range<std::string>(*it));
- if (!r.isEmpty()) {
- rules.push_back(r);
- }
- }
- return rules;
+ std::stringstream stream;
+ boost::archive::text_oarchive archive(stream);
+ archive << rules_->list_;
+ return stream.str();
}
std::vector<HighlightRule> HighlightManager::getDefaultRules()
{
std::vector<HighlightRule> rules;
HighlightRule r;
r.setMatchChat(true);
r.getAction().setPlaySound(true);
rules.push_back(r);
return rules;
}
-void HighlightManager::storeSettings()
-{
- storingSettings_ = true; // don't reload settings while saving
- settings_->storeSetting(SettingConstants::HIGHLIGHT_RULES, rulesToString());
- storingSettings_ = false;
-}
-
HighlightRule HighlightManager::getRule(int index) const
{
- assert(index >= 0 && static_cast<size_t>(index) < rules_.size());
- return rules_[static_cast<size_t>(index)];
+ assert(index >= 0 && static_cast<size_t>(index) < rules_->getSize());
+ return rules_->getRule(static_cast<size_t>(index));
}
void HighlightManager::setRule(int index, const HighlightRule& rule)
{
- assert(index >= 0 && static_cast<size_t>(index) < rules_.size());
- rules_[static_cast<size_t>(index)] = rule;
- storeSettings();
+ assert(index >= 0 && static_cast<size_t>(index) < rules_->getSize());
+ rules_->list_[static_cast<size_t>(index)] = rule;
}
void HighlightManager::insertRule(int index, const HighlightRule& rule)
{
- assert(index >= 0 && boost::numeric_cast<std::vector<std::string>::size_type>(index) <= rules_.size());
- rules_.insert(rules_.begin() + index, rule);
- storeSettings();
+ assert(index >= 0 && boost::numeric_cast<std::vector<std::string>::size_type>(index) <= rules_->getSize());
+ rules_->list_.insert(rules_->list_.begin() + index, rule);
}
void HighlightManager::removeRule(int index)
{
- assert(index >= 0 && boost::numeric_cast<std::vector<std::string>::size_type>(index) < rules_.size());
- rules_.erase(rules_.begin() + index);
- storeSettings();
+ assert(index >= 0 && boost::numeric_cast<std::vector<std::string>::size_type>(index) < rules_->getSize());
+ rules_->list_.erase(rules_->list_.begin() + index);
+}
+
+void HighlightManager::storeSettings()
+{
+ storingSettings_ = true; // don't reload settings while saving
+ settings_->storeSetting(SettingConstants::HIGHLIGHT_RULES, rulesToString());
+ storingSettings_ = false;
+}
+
+void HighlightManager::loadSettings()
+{
+ std::string rulesString = settings_->getSetting(SettingConstants::HIGHLIGHT_RULES);
+ std::stringstream stream;
+ stream << rulesString;
+ try {
+ boost::archive::text_iarchive archive(stream);
+ archive >> rules_->list_;
+ } catch (boost::archive::archive_exception&) {
+ rules_->list_ = getDefaultRules();
+ }
}
Highlighter* HighlightManager::createHighlighter()
{
return new Highlighter(this);
}
}
diff --git a/Swift/Controllers/HighlightManager.h b/Swift/Controllers/HighlightManager.h
index d195d05..3da72eb 100644
--- a/Swift/Controllers/HighlightManager.h
+++ b/Swift/Controllers/HighlightManager.h
@@ -1,49 +1,71 @@
/*
* Copyright (c) 2012 Maciej Niedzielski
* Licensed under the simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
+/*
+ * Copyright (c) 2014 Kevin Smith and Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
#pragma once
#include <vector>
#include <string>
#include <Swiften/Base/boost_bsignals.h>
#include <Swift/Controllers/HighlightRule.h>
namespace Swift {
class SettingsProvider;
class Highlighter;
class HighlightManager {
public:
+
+ class HighlightRulesList {
+ public:
+ friend class HighlightManager;
+ size_t getSize() const { return list_.size(); }
+ const HighlightRule& getRule(const size_t index) const { return list_[index]; }
+ void addRule(const HighlightRule &rule) { list_.push_back(rule); }
+ void combineRules(const HighlightRulesList &rhs) {
+ list_.insert(list_.end(), rhs.list_.begin(), rhs.list_.end());
+ }
+ private:
+ std::vector<HighlightRule> list_;
+ };
+
HighlightManager(SettingsProvider* settings);
Highlighter* createHighlighter();
- const std::vector<HighlightRule>& getRules() const { return rules_; }
+ boost::shared_ptr<const HighlightManager::HighlightRulesList> getRules() const { return rules_; }
+
HighlightRule getRule(int index) const;
void setRule(int index, const HighlightRule& rule);
void insertRule(int index, const HighlightRule& rule);
void removeRule(int index);
+ void storeSettings();
+ void loadSettings();
boost::signal<void (const HighlightAction&)> onHighlight;
private:
void handleSettingChanged(const std::string& settingPath);
std::string rulesToString() const;
- static std::vector<HighlightRule> rulesFromString(const std::string&);
static std::vector<HighlightRule> getDefaultRules();
SettingsProvider* settings_;
bool storingSettings_;
- void storeSettings();
- void loadSettings();
- std::vector<HighlightRule> rules_;
+ boost::shared_ptr<HighlightManager::HighlightRulesList> rules_;
};
+ typedef boost::shared_ptr<const HighlightManager::HighlightRulesList> HighlightRulesListPtr;
+
}
diff --git a/Swift/Controllers/HighlightRule.cpp b/Swift/Controllers/HighlightRule.cpp
index 9ca7d86..f1a5235 100644
--- a/Swift/Controllers/HighlightRule.cpp
+++ b/Swift/Controllers/HighlightRule.cpp
@@ -1,15 +1,21 @@
/*
* Copyright (c) 2012 Maciej Niedzielski
* Licensed under the simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
+/*
+ * Copyright (c) 2014 Kevin Smith and Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
#include <algorithm>
#include <boost/algorithm/string.hpp>
#include <boost/lambda/lambda.hpp>
#include <Swiften/Base/foreach.h>
#include <Swiften/Base/Regex.h>
#include <Swift/Controllers/HighlightRule.h>
namespace Swift {
@@ -50,83 +56,25 @@ std::string HighlightRule::boolToString(bool b)
{
return b ? "1" : "0";
}
bool HighlightRule::boolFromString(const std::string& s)
{
return s == "1";
}
-std::string HighlightRule::toString() const
-{
- std::vector<std::string> v;
- v.push_back(boost::join(senders_, "\t"));
- v.push_back(boost::join(keywords_, "\t"));
- v.push_back(boolToString(nickIsKeyword_));
- v.push_back(boolToString(matchChat_));
- v.push_back(boolToString(matchMUC_));
- v.push_back(boolToString(matchCase_));
- v.push_back(boolToString(matchWholeWords_));
- v.push_back(boolToString(action_.highlightText()));
- v.push_back(action_.getTextColor());
- v.push_back(action_.getTextBackground());
- v.push_back(boolToString(action_.playSound()));
- v.push_back(action_.getSoundFile());
- return boost::join(v, "\n");
-}
-
-HighlightRule HighlightRule::fromString(const std::string& s)
-{
- std::vector<std::string> v;
- boost::split(v, s, boost::is_any_of("\n"));
-
- HighlightRule r;
- size_t i = 0;
- try {
- boost::split(r.senders_, v.at(i++), boost::is_any_of("\t"));
- r.senders_.erase(std::remove_if(r.senders_.begin(), r.senders_.end(), boost::lambda::_1 == ""), r.senders_.end());
- boost::split(r.keywords_, v.at(i++), boost::is_any_of("\t"));
- r.keywords_.erase(std::remove_if(r.keywords_.begin(), r.keywords_.end(), boost::lambda::_1 == ""), r.keywords_.end());
- r.nickIsKeyword_ = boolFromString(v.at(i++));
- r.matchChat_ = boolFromString(v.at(i++));
- r.matchMUC_ = boolFromString(v.at(i++));
- r.matchCase_ = boolFromString(v.at(i++));
- r.matchWholeWords_ = boolFromString(v.at(i++));
- r.action_.setHighlightText(boolFromString(v.at(i++)));
- r.action_.setTextColor(v.at(i++));
- r.action_.setTextBackground(v.at(i++));
- r.action_.setPlaySound(boolFromString(v.at(i++)));
- r.action_.setSoundFile(v.at(i++));
- }
- catch (std::out_of_range) {
- // this may happen if more properties are added to HighlightRule object, etc...
- // in such case, default values (set by default constructor) will be used
- }
-
- r.updateRegex();
-
- return r;
-}
-
bool HighlightRule::isMatch(const std::string& body, const std::string& sender, const std::string& nick, MessageType messageType) const
{
if ((messageType == HighlightRule::ChatMessage && matchChat_) || (messageType == HighlightRule::MUCMessage && matchMUC_)) {
bool matchesKeyword = keywords_.empty() && (nick.empty() || !nickIsKeyword_);
bool matchesSender = senders_.empty();
- foreach (const boost::regex & rx, keywordRegex_) {
- if (boost::regex_search(body, rx)) {
- matchesKeyword = true;
- break;
- }
- }
-
if (!matchesKeyword && nickIsKeyword_ && !nick.empty()) {
if (boost::regex_search(body, regexFromString(nick))) {
matchesKeyword = true;
}
}
foreach (const boost::regex & rx, senderRegex_) {
if (boost::regex_search(sender, rx)) {
matchesSender = true;
diff --git a/Swift/Controllers/HighlightRule.h b/Swift/Controllers/HighlightRule.h
index 1abfa5a..ae1a3d3 100644
--- a/Swift/Controllers/HighlightRule.h
+++ b/Swift/Controllers/HighlightRule.h
@@ -1,45 +1,52 @@
/*
* Copyright (c) 2012 Maciej Niedzielski
* Licensed under the simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
+/*
+ * Copyright (c) 2014 Kevin Smith and Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
#pragma once
#include <vector>
#include <string>
#include <boost/regex.hpp>
+#include <boost/archive/text_oarchive.hpp>
+#include <boost/archive/text_iarchive.hpp>
#include <Swift/Controllers/HighlightAction.h>
namespace Swift {
class HighlightRule {
public:
HighlightRule();
enum MessageType { ChatMessage, MUCMessage };
bool isMatch(const std::string& body, const std::string& sender, const std::string& nick, MessageType) const;
const HighlightAction& getAction() const { return action_; }
HighlightAction& getAction() { return action_; }
- static HighlightRule fromString(const std::string&);
- std::string toString() const;
-
const std::vector<std::string>& getSenders() const { return senders_; }
void setSenders(const std::vector<std::string>&);
+ const std::vector<boost::regex>& getSenderRegex() const { return senderRegex_; }
const std::vector<std::string>& getKeywords() const { return keywords_; }
void setKeywords(const std::vector<std::string>&);
+ const std::vector<boost::regex>& getKeywordRegex() const { return keywordRegex_; }
bool getNickIsKeyword() const { return nickIsKeyword_; }
void setNickIsKeyword(bool);
bool getMatchCase() const { return matchCase_; }
void setMatchCase(bool);
bool getMatchWholeWords() const { return matchWholeWords_; }
void setMatchWholeWords(bool);
@@ -47,18 +54,21 @@ namespace Swift {
bool getMatchChat() const { return matchChat_; }
void setMatchChat(bool);
bool getMatchMUC() const { return matchMUC_; }
void setMatchMUC(bool);
bool isEmpty() const;
private:
+ friend class boost::serialization::access;
+ template<class Archive> void serialize(Archive & ar, const unsigned int version);
+
static std::string boolToString(bool);
static bool boolFromString(const std::string&);
std::vector<std::string> senders_;
std::vector<std::string> keywords_;
bool nickIsKeyword_;
mutable std::vector<boost::regex> senderRegex_;
mutable std::vector<boost::regex> keywordRegex_;
@@ -68,10 +78,24 @@ namespace Swift {
bool matchCase_;
bool matchWholeWords_;
bool matchChat_;
bool matchMUC_;
HighlightAction action_;
};
+ template<class Archive>
+ void HighlightRule::serialize(Archive& ar, const unsigned int /*version*/)
+ {
+ ar & senders_;
+ ar & keywords_;
+ ar & nickIsKeyword_;
+ ar & matchChat_;
+ ar & matchMUC_;
+ ar & matchCase_;
+ ar & matchWholeWords_;
+ ar & action_;
+ updateRegex();
+ }
+
}
diff --git a/Swift/Controllers/Highlighter.cpp b/Swift/Controllers/Highlighter.cpp
index 754641a..efeeb6b 100644
--- a/Swift/Controllers/Highlighter.cpp
+++ b/Swift/Controllers/Highlighter.cpp
@@ -1,15 +1,21 @@
/*
* Copyright (c) 2012 Maciej Niedzielski
* Licensed under the simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
+/*
+ * Copyright (c) 2014 Kevin Smith and Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
#include <Swiften/Base/foreach.h>
#include <Swift/Controllers/Highlighter.h>
#include <Swift/Controllers/HighlightManager.h>
namespace Swift {
Highlighter::Highlighter(HighlightManager* manager)
: manager_(manager)
{
@@ -18,21 +24,23 @@ Highlighter::Highlighter(HighlightManager* manager)
void Highlighter::setMode(Mode mode)
{
mode_ = mode;
messageType_ = mode_ == ChatMode ? HighlightRule::ChatMessage : HighlightRule::MUCMessage;
}
HighlightAction Highlighter::findAction(const std::string& body, const std::string& sender) const
{
- foreach (const HighlightRule & r, manager_->getRules()) {
- if (r.isMatch(body, sender, nick_, messageType_)) {
- return r.getAction();
+ HighlightRulesListPtr rules = manager_->getRules();
+ for (size_t i = 0; i < rules->getSize(); ++i) {
+ const HighlightRule& rule = rules->getRule(i);
+ if (rule.isMatch(body, sender, nick_, messageType_)) {
+ return rule.getAction();
}
}
return HighlightAction();
}
void Highlighter::handleHighlightAction(const HighlightAction& action)
{
manager_->onHighlight(action);
diff --git a/Swift/Controllers/MainController.cpp b/Swift/Controllers/MainController.cpp
index 79b7502..a16cbe7 100644
--- a/Swift/Controllers/MainController.cpp
+++ b/Swift/Controllers/MainController.cpp
@@ -1,17 +1,11 @@
/*
- * Copyright (c) 2010-2013 Kevin Smith
- * Licensed under the GNU General Public License v3.
- * See Documentation/Licenses/GPLv3.txt for more information.
- */
-
-/*
- * Copyright (c) 2013 Remko Tronçon
+ * Copyright (c) 2010-2014 Kevin Smith and Remko Tronçon
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
#include <Swift/Controllers/MainController.h>
#include <cstdlib>
#include <boost/bind.hpp>
@@ -363,18 +357,19 @@ void MainController::handleConnected() {
historyViewController_ = new HistoryViewController(jid_, uiEventStream_, historyController_, client_->getNickResolver(), client_->getAvatarManager(), client_->getPresenceOracle(), uiFactory_);
chatsManager_ = new ChatsManager(jid_, client_->getStanzaChannel(), client_->getIQRouter(), eventController_, uiFactory_, uiFactory_, client_->getNickResolver(), client_->getPresenceOracle(), client_->getPresenceSender(), uiEventStream_, uiFactory_, useDelayForLatency_, networkFactories_->getTimerFactory(), client_->getMUCRegistry(), client_->getEntityCapsProvider(), client_->getMUCManager(), uiFactory_, profileSettings_, ftOverview_, client_->getRoster(), !settings_->getSetting(SettingConstants::REMEMBER_RECENT_CHATS), settings_, historyController_, whiteboardManager_, highlightManager_, client_->getClientBlockListManager(), emoticons_, userSearchControllerInvite_, client_->getVCardManager());
#else
chatsManager_ = new ChatsManager(jid_, client_->getStanzaChannel(), client_->getIQRouter(), eventController_, uiFactory_, uiFactory_, client_->getNickResolver(), client_->getPresenceOracle(), client_->getPresenceSender(), uiEventStream_, uiFactory_, useDelayForLatency_, networkFactories_->getTimerFactory(), client_->getMUCRegistry(), client_->getEntityCapsProvider(), client_->getMUCManager(), uiFactory_, profileSettings_, ftOverview_, client_->getRoster(), !settings_->getSetting(SettingConstants::REMEMBER_RECENT_CHATS), settings_, NULL, whiteboardManager_, highlightManager_, client_->getClientBlockListManager(), emoticons_, userSearchControllerInvite_, client_->getVCardManager());
#endif
contactsFromRosterProvider_ = new ContactsFromXMPPRoster(client_->getRoster(), client_->getAvatarManager(), client_->getPresenceOracle());
contactSuggesterWithoutRoster_->addContactProvider(chatsManager_);
contactSuggesterWithRoster_->addContactProvider(chatsManager_);
contactSuggesterWithRoster_->addContactProvider(contactsFromRosterProvider_);
+ highlightEditorController_->setContactSuggester(contactSuggesterWithoutRoster_);
client_->onMessageReceived.connect(boost::bind(&ChatsManager::handleIncomingMessage, chatsManager_, _1));
chatsManager_->setAvatarManager(client_->getAvatarManager());
eventWindowController_ = new EventWindowController(eventController_, uiFactory_);
loginWindow_->morphInto(rosterController_->getWindow());
DiscoInfo discoInfo;
diff --git a/Swift/Controllers/SConscript b/Swift/Controllers/SConscript
index 4c71268..5ebbdd3 100644
--- a/Swift/Controllers/SConscript
+++ b/Swift/Controllers/SConscript
@@ -56,18 +56,19 @@ if env["SCONS_STAGE"] == "build" :
"StatusTracker.cpp",
"PresenceNotifier.cpp",
"EventNotifier.cpp",
"AdHocManager.cpp",
"AdHocController.cpp",
"XMPPEvents/EventController.cpp",
"UIEvents/UIEvent.cpp",
"UIInterfaces/XMLConsoleWidget.cpp",
"UIInterfaces/ChatListWindow.cpp",
+ "UIInterfaces/HighlightEditorWindow.cpp",
"PreviousStatusStore.cpp",
"ProfileSettingsProvider.cpp",
"Settings/SettingsProviderHierachy.cpp",
"Settings/XMLSettingsProvider.cpp",
"Storages/CertificateStorageFactory.cpp",
"Storages/CertificateStorage.cpp",
"Storages/CertificateFileStorage.cpp",
"Storages/CertificateMemoryStorage.cpp",
"Storages/AvatarFileStorage.cpp",
diff --git a/Swift/Controllers/UIInterfaces/HighlightEditorWindow.cpp b/Swift/Controllers/UIInterfaces/HighlightEditorWindow.cpp
new file mode 100644
index 0000000..f90903b
--- /dev/null
+++ b/Swift/Controllers/UIInterfaces/HighlightEditorWindow.cpp
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2014 Kevin Smith and Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swift/Controllers/UIInterfaces/HighlightEditorWindow.h>
+
+namespace Swift {
+
+HighlightEditorWindow::HighlightEditorWindow()
+{
+}
+
+HighlightEditorWindow::~HighlightEditorWindow()
+{
+}
+
+}
diff --git a/Swift/Controllers/UIInterfaces/HighlightEditorWindow.h b/Swift/Controllers/UIInterfaces/HighlightEditorWindow.h
new file mode 100644
index 0000000..83ae959
--- /dev/null
+++ b/Swift/Controllers/UIInterfaces/HighlightEditorWindow.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2014 Kevin Smith and Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <vector>
+#include <Swiften/Base/boost_bsignals.h>
+#include <Swift/Controllers/Contact.h>
+
+namespace Swift {
+
+class HighlightManager;
+
+class HighlightEditorWindow {
+public:
+ HighlightEditorWindow();
+ virtual ~HighlightEditorWindow();
+ virtual void show() = 0;
+ virtual void setHighlightManager(HighlightManager *highlightManager) = 0;
+ virtual void setContactSuggestions(const std::vector<Contact::ref>& suggestions) = 0;
+
+public:
+ boost::signal<void (const std::string&)> onContactSuggestionsRequested;
+};
+
+}
diff --git a/Swift/Controllers/UIInterfaces/HighlightEditorWindowFactory.h b/Swift/Controllers/UIInterfaces/HighlightEditorWindowFactory.h
new file mode 100644
index 0000000..e0aaaef
--- /dev/null
+++ b/Swift/Controllers/UIInterfaces/HighlightEditorWindowFactory.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2012 Mateusz Piękos
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+/*
+ * Copyright (c) 2014 Kevin Smith and Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+namespace Swift {
+ class HighlightEditorWindow;
+
+ class HighlightEditorWindowFactory {
+ public :
+ virtual ~HighlightEditorWindowFactory() {}
+
+ virtual HighlightEditorWindow* createHighlightEditorWindow() = 0;
+ };
+}
diff --git a/Swift/Controllers/UIInterfaces/UIFactory.h b/Swift/Controllers/UIInterfaces/UIFactory.h
index 990dc98..54fa7ce 100644
--- a/Swift/Controllers/UIInterfaces/UIFactory.h
+++ b/Swift/Controllers/UIInterfaces/UIFactory.h
@@ -1,11 +1,11 @@
/*
- * Copyright (c) 2010 Remko Tronçon
+ * Copyright (c) 2010-2014 Remko Tronçon
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
#pragma once
#include <Swift/Controllers/UIInterfaces/ChatListWindowFactory.h>
#include <Swift/Controllers/UIInterfaces/ChatWindowFactory.h>
#include <Swift/Controllers/UIInterfaces/HistoryWindowFactory.h>
@@ -15,19 +15,19 @@
#include <Swift/Controllers/UIInterfaces/MUCSearchWindowFactory.h>
#include <Swift/Controllers/UIInterfaces/JoinMUCWindowFactory.h>
#include <Swift/Controllers/UIInterfaces/UserSearchWindowFactory.h>
#include <Swift/Controllers/UIInterfaces/XMLConsoleWidgetFactory.h>
#include <Swift/Controllers/UIInterfaces/ProfileWindowFactory.h>
#include <Swift/Controllers/UIInterfaces/ContactEditWindowFactory.h>
#include <Swift/Controllers/UIInterfaces/AdHocCommandWindowFactory.h>
#include <Swift/Controllers/UIInterfaces/FileTransferListWidgetFactory.h>
#include <Swift/Controllers/UIInterfaces/WhiteboardWindowFactory.h>
-#include <Swift/Controllers/UIInterfaces/HighlightEditorWidgetFactory.h>
+#include <Swift/Controllers/UIInterfaces/HighlightEditorWindowFactory.h>
#include <Swift/Controllers/UIInterfaces/BlockListEditorWidgetFactory.h>
namespace Swift {
class UIFactory :
public ChatListWindowFactory,
public ChatWindowFactory,
public HistoryWindowFactory,
public EventWindowFactory,
public LoginWindowFactory,
@@ -35,15 +35,15 @@ namespace Swift {
public MUCSearchWindowFactory,
public XMLConsoleWidgetFactory,
public UserSearchWindowFactory,
public JoinMUCWindowFactory,
public ProfileWindowFactory,
public ContactEditWindowFactory,
public AdHocCommandWindowFactory,
public FileTransferListWidgetFactory,
public WhiteboardWindowFactory,
- public HighlightEditorWidgetFactory,
+ public HighlightEditorWindowFactory,
public BlockListEditorWidgetFactory {
public:
virtual ~UIFactory() {}
};
}
diff --git a/Swift/Controllers/UnitTest/HighlightRuleTest.cpp b/Swift/Controllers/UnitTest/HighlightRuleTest.cpp
index ec81227..c988b8d 100644
--- a/Swift/Controllers/UnitTest/HighlightRuleTest.cpp
+++ b/Swift/Controllers/UnitTest/HighlightRuleTest.cpp
@@ -1,15 +1,21 @@
/*
* Copyright (c) 2012 Maciej Niedzielski
* Licensed under the simplified BSD license.
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
+/*
+ * Copyright (c) 2014 Kevin Smith and Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
#include <vector>
#include <string>
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <Swift/Controllers/HighlightRule.h>
using namespace Swift;
@@ -28,19 +34,19 @@ class HighlightRuleTest : public CppUnit::TestFixture {
CPPUNIT_TEST(testMUC);
CPPUNIT_TEST_SUITE_END();
public:
void setUp() {
std::vector<std::string> keywords;
keywords.push_back("keyword1");
keywords.push_back("KEYWORD2");
- std::vector<std::string>senders;
+ std::vector<std::string> senders;
senders.push_back("sender1");
senders.push_back("SENDER2");
emptyRule = new HighlightRule();
keywordRule = new HighlightRule();
keywordRule->setKeywords(keywords);
keywordChatRule = new HighlightRule();
@@ -151,40 +157,40 @@ class HighlightRuleTest : public CppUnit::TestFixture {
CPPUNIT_ASSERT_EQUAL(emptyRule->isMatch("", "", "", HighlightRule::ChatMessage), false);
CPPUNIT_ASSERT_EQUAL(emptyRule->isMatch("", "", "", HighlightRule::MUCMessage), false);
}
void testKeyword() {
CPPUNIT_ASSERT_EQUAL(keywordChatRule->isMatch("body", "from", "nick", HighlightRule::ChatMessage), false);
CPPUNIT_ASSERT_EQUAL(keywordChatRule->isMatch("body", "from", "nick", HighlightRule::MUCMessage), false);
- CPPUNIT_ASSERT_EQUAL(keywordChatRule->isMatch("keyword1", "from", "nick", HighlightRule::ChatMessage), true);
+ CPPUNIT_ASSERT_EQUAL(keywordChatRule->isMatch("keyword1", "from", "nick", HighlightRule::ChatMessage), false);
CPPUNIT_ASSERT_EQUAL(keywordChatRule->isMatch("keyword1", "from", "nick", HighlightRule::MUCMessage), false);
CPPUNIT_ASSERT_EQUAL(keywordRule->isMatch("keyword1", "from", "nick", HighlightRule::ChatMessage), false);
CPPUNIT_ASSERT_EQUAL(keywordChatRule->isMatch("body", "sender contains keyword1", "nick", HighlightRule::ChatMessage), false);
- CPPUNIT_ASSERT_EQUAL(keywordChatRule->isMatch("abc keyword1 xyz", "from", "nick", HighlightRule::ChatMessage), true);
- CPPUNIT_ASSERT_EQUAL(keywordChatRule->isMatch("abckeyword1xyz", "from", "nick", HighlightRule::ChatMessage), true);
+ CPPUNIT_ASSERT_EQUAL(keywordChatRule->isMatch("abc keyword1 xyz", "from", "nick", HighlightRule::ChatMessage), false);
+ CPPUNIT_ASSERT_EQUAL(keywordChatRule->isMatch("abckeyword1xyz", "from", "nick", HighlightRule::ChatMessage), false);
- CPPUNIT_ASSERT_EQUAL(keywordChatRule->isMatch("KEYword1", "from", "nick", HighlightRule::ChatMessage), true);
- CPPUNIT_ASSERT_EQUAL(keywordChatRule->isMatch("abc KEYword1 xyz", "from", "nick", HighlightRule::ChatMessage), true);
- CPPUNIT_ASSERT_EQUAL(keywordChatRule->isMatch("abcKEYword1xyz", "from", "nick", HighlightRule::ChatMessage), true);
+ CPPUNIT_ASSERT_EQUAL(keywordChatRule->isMatch("KEYword1", "from", "nick", HighlightRule::ChatMessage), false);
+ CPPUNIT_ASSERT_EQUAL(keywordChatRule->isMatch("abc KEYword1 xyz", "from", "nick", HighlightRule::ChatMessage), false);
+ CPPUNIT_ASSERT_EQUAL(keywordChatRule->isMatch("abcKEYword1xyz", "from", "nick", HighlightRule::ChatMessage), false);
- CPPUNIT_ASSERT_EQUAL(keywordChatRule->isMatch("keyword2", "from", "nick", HighlightRule::ChatMessage), true);
+ CPPUNIT_ASSERT_EQUAL(keywordChatRule->isMatch("keyword2", "from", "nick", HighlightRule::ChatMessage), false);
}
void testNickKeyword() {
CPPUNIT_ASSERT_EQUAL(keywordNickChatRule->isMatch("body contains nick", "from", "nick", HighlightRule::ChatMessage), true);
CPPUNIT_ASSERT_EQUAL(keywordNickChatRule->isMatch("body contains nick", "from", "nick", HighlightRule::MUCMessage), false);
CPPUNIT_ASSERT_EQUAL(keywordChatRule->isMatch("body contains nick", "from", "nick", HighlightRule::ChatMessage), false);
- CPPUNIT_ASSERT_EQUAL(keywordNickChatRule->isMatch("keyword1", "from", "nick", HighlightRule::ChatMessage), true);
+ CPPUNIT_ASSERT_EQUAL(keywordNickChatRule->isMatch("keyword1", "from", "nick", HighlightRule::ChatMessage), false);
CPPUNIT_ASSERT_EQUAL(keywordNickChatRule->isMatch("body", "sender contains nick", "nick", HighlightRule::ChatMessage), false);
CPPUNIT_ASSERT_EQUAL(keywordNickChatRule->isMatch("body contains mixed-case NiCk", "sender", "nick", HighlightRule::ChatMessage), true);
CPPUNIT_ASSERT_EQUAL(keywordNickChatRule->isMatch("nickname", "from", "nick", HighlightRule::ChatMessage), true);
CPPUNIT_ASSERT_EQUAL(keywordNickChatRule->isMatch("NIckNAME", "from", "nick", HighlightRule::ChatMessage), true);
CPPUNIT_ASSERT_EQUAL(keywordNickChatRule->isMatch("body", "from", "", HighlightRule::ChatMessage), false);
@@ -226,77 +232,77 @@ class HighlightRuleTest : public CppUnit::TestFixture {
CPPUNIT_ASSERT_EQUAL(senderChatRule->isMatch("body", "abcSENDer1xyz", "nick", HighlightRule::ChatMessage), true);
CPPUNIT_ASSERT_EQUAL(senderChatRule->isMatch("body", "sender2", "nick", HighlightRule::ChatMessage), true);
}
void testSenderAndKeyword() {
CPPUNIT_ASSERT_EQUAL(senderKeywordChatRule->isMatch("body", "from", "nick", HighlightRule::ChatMessage), false);
CPPUNIT_ASSERT_EQUAL(senderKeywordChatRule->isMatch("keyword1", "from", "nick", HighlightRule::ChatMessage), false);
CPPUNIT_ASSERT_EQUAL(senderKeywordChatRule->isMatch("body", "sender1", "nick", HighlightRule::ChatMessage), false);
- CPPUNIT_ASSERT_EQUAL(senderKeywordChatRule->isMatch("keyword1", "sender1", "nick", HighlightRule::ChatMessage), true);
+ CPPUNIT_ASSERT_EQUAL(senderKeywordChatRule->isMatch("keyword1", "sender1", "nick", HighlightRule::ChatMessage), false);
}
void testWholeWords() {
CPPUNIT_ASSERT_EQUAL(senderKeywordNickWordChatRule->isMatch("body", "from", "nick", HighlightRule::ChatMessage), false);
CPPUNIT_ASSERT_EQUAL(senderKeywordNickWordChatRule->isMatch("keyword1", "from", "nick", HighlightRule::ChatMessage), false);
CPPUNIT_ASSERT_EQUAL(senderKeywordNickWordChatRule->isMatch("body", "sender1", "nick", HighlightRule::ChatMessage), false);
- CPPUNIT_ASSERT_EQUAL(senderKeywordNickWordChatRule->isMatch("keyword1", "sender1", "nick", HighlightRule::ChatMessage), true);
+ CPPUNIT_ASSERT_EQUAL(senderKeywordNickWordChatRule->isMatch("keyword1", "sender1", "nick", HighlightRule::ChatMessage), false);
CPPUNIT_ASSERT_EQUAL(senderKeywordNickWordChatRule->isMatch("xkeyword1", "sender1", "nick", HighlightRule::ChatMessage), false);
CPPUNIT_ASSERT_EQUAL(senderKeywordNickWordChatRule->isMatch("keyword1", "xsender1", "nick", HighlightRule::ChatMessage), false);
CPPUNIT_ASSERT_EQUAL(senderKeywordNickWordChatRule->isMatch("body contains nick", "sender1", "nick", HighlightRule::ChatMessage), true);
CPPUNIT_ASSERT_EQUAL(senderKeywordNickWordChatRule->isMatch("body contains xnick", "sender1", "nick", HighlightRule::ChatMessage), false);
- CPPUNIT_ASSERT_EQUAL(senderKeywordNickWordChatRule->isMatch("KEYword1", "SENDer1", "nick", HighlightRule::ChatMessage), true);
+ CPPUNIT_ASSERT_EQUAL(senderKeywordNickWordChatRule->isMatch("KEYword1", "SENDer1", "nick", HighlightRule::ChatMessage), false);
CPPUNIT_ASSERT_EQUAL(senderKeywordNickWordChatRule->isMatch("body contains NiCk", "sender1", "nick", HighlightRule::ChatMessage), true);
}
void testCase() {
CPPUNIT_ASSERT_EQUAL(senderKeywordNickCaseChatRule->isMatch("body", "from", "nick", HighlightRule::ChatMessage), false);
CPPUNIT_ASSERT_EQUAL(senderKeywordNickCaseChatRule->isMatch("keyword1", "from", "nick", HighlightRule::ChatMessage), false);
CPPUNIT_ASSERT_EQUAL(senderKeywordNickCaseChatRule->isMatch("body", "sender1", "nick", HighlightRule::ChatMessage), false);
- CPPUNIT_ASSERT_EQUAL(senderKeywordNickCaseChatRule->isMatch("keyword1", "sender1", "nick", HighlightRule::ChatMessage), true);
- CPPUNIT_ASSERT_EQUAL(senderKeywordNickCaseChatRule->isMatch("xkeyword1", "xsender1", "nick", HighlightRule::ChatMessage), true);
+ CPPUNIT_ASSERT_EQUAL(senderKeywordNickCaseChatRule->isMatch("keyword1", "sender1", "nick", HighlightRule::ChatMessage), false);
+ CPPUNIT_ASSERT_EQUAL(senderKeywordNickCaseChatRule->isMatch("xkeyword1", "xsender1", "nick", HighlightRule::ChatMessage), false);
CPPUNIT_ASSERT_EQUAL(senderKeywordNickCaseChatRule->isMatch("body contains nick", "sender1", "nick", HighlightRule::ChatMessage), true);
CPPUNIT_ASSERT_EQUAL(senderKeywordNickCaseChatRule->isMatch("body contains xnick", "sender1", "nick", HighlightRule::ChatMessage), true);
CPPUNIT_ASSERT_EQUAL(senderKeywordNickCaseChatRule->isMatch("KEYword1", "SENDer1", "nick", HighlightRule::ChatMessage), false);
CPPUNIT_ASSERT_EQUAL(senderKeywordNickCaseChatRule->isMatch("keyword1", "SENDer1", "nick", HighlightRule::ChatMessage), false);
CPPUNIT_ASSERT_EQUAL(senderKeywordNickCaseChatRule->isMatch("KEYword1", "sender1", "nick", HighlightRule::ChatMessage), false);
CPPUNIT_ASSERT_EQUAL(senderKeywordNickCaseChatRule->isMatch("body contains NiCk", "sender1", "nick", HighlightRule::ChatMessage), false);
}
void testWholeWordsAndCase() {
CPPUNIT_ASSERT_EQUAL(senderKeywordNickCaseWordChatRule->isMatch("body", "from", "nick", HighlightRule::ChatMessage), false);
CPPUNIT_ASSERT_EQUAL(senderKeywordNickCaseWordChatRule->isMatch("keyword1", "from", "nick", HighlightRule::ChatMessage), false);
CPPUNIT_ASSERT_EQUAL(senderKeywordNickCaseWordChatRule->isMatch("body", "sender1", "nick", HighlightRule::ChatMessage), false);
- CPPUNIT_ASSERT_EQUAL(senderKeywordNickCaseWordChatRule->isMatch("keyword1", "sender1", "nick", HighlightRule::ChatMessage), true);
+ CPPUNIT_ASSERT_EQUAL(senderKeywordNickCaseWordChatRule->isMatch("keyword1", "sender1", "nick", HighlightRule::ChatMessage), false);
CPPUNIT_ASSERT_EQUAL(senderKeywordNickCaseWordChatRule->isMatch("xkeyword1", "sender1", "nick", HighlightRule::ChatMessage), false);
CPPUNIT_ASSERT_EQUAL(senderKeywordNickCaseWordChatRule->isMatch("keyword1", "xsender1", "nick", HighlightRule::ChatMessage), false);
CPPUNIT_ASSERT_EQUAL(senderKeywordNickCaseWordChatRule->isMatch("body contains nick", "sender1", "nick", HighlightRule::ChatMessage), true);
CPPUNIT_ASSERT_EQUAL(senderKeywordNickCaseWordChatRule->isMatch("body contains xnick", "sender1", "nick", HighlightRule::ChatMessage), false);
CPPUNIT_ASSERT_EQUAL(senderKeywordNickCaseWordChatRule->isMatch("KEYword1", "SENDer1", "nick", HighlightRule::ChatMessage), false);
CPPUNIT_ASSERT_EQUAL(senderKeywordNickCaseWordChatRule->isMatch("keyword1", "SENDer1", "nick", HighlightRule::ChatMessage), false);
CPPUNIT_ASSERT_EQUAL(senderKeywordNickCaseWordChatRule->isMatch("KEYword1", "sender1", "nick", HighlightRule::ChatMessage), false);
CPPUNIT_ASSERT_EQUAL(senderKeywordNickCaseWordChatRule->isMatch("body contains NiCk", "sender1", "nick", HighlightRule::ChatMessage), false);
}
void testMUC() {
CPPUNIT_ASSERT_EQUAL(senderKeywordNickMUCRule->isMatch("body", "from", "nick", HighlightRule::ChatMessage), false);
CPPUNIT_ASSERT_EQUAL(senderKeywordNickMUCRule->isMatch("keyword1", "sender1", "nick", HighlightRule::ChatMessage), false);
- CPPUNIT_ASSERT_EQUAL(senderKeywordNickMUCRule->isMatch("keyword1", "sender1", "nick", HighlightRule::MUCMessage), true);
+ CPPUNIT_ASSERT_EQUAL(senderKeywordNickMUCRule->isMatch("keyword1", "sender1", "nick", HighlightRule::MUCMessage), false);
CPPUNIT_ASSERT_EQUAL(senderKeywordNickMUCRule->isMatch("body contains nick", "sender1", "nick", HighlightRule::MUCMessage), true);
}
private:
HighlightRule* emptyRule;
HighlightRule* keywordRule;
HighlightRule* keywordChatRule;
HighlightRule* keywordNickChatRule;