diff options
Diffstat (limited to 'Swift/Controllers/Chat')
| -rw-r--r-- | Swift/Controllers/Chat/ChatController.cpp | 4 | ||||
| -rw-r--r-- | Swift/Controllers/Chat/ChatController.h | 4 | ||||
| -rw-r--r-- | Swift/Controllers/Chat/ChatControllerBase.cpp | 12 | ||||
| -rw-r--r-- | Swift/Controllers/Chat/ChatControllerBase.h | 8 | ||||
| -rw-r--r-- | Swift/Controllers/Chat/ChatMessageParser.cpp | 75 | ||||
| -rw-r--r-- | Swift/Controllers/Chat/ChatMessageParser.h | 11 | ||||
| -rw-r--r-- | Swift/Controllers/Chat/ChatsManager.cpp | 9 | ||||
| -rw-r--r-- | Swift/Controllers/Chat/ChatsManager.h | 2 | ||||
| -rw-r--r-- | Swift/Controllers/Chat/MUCController.cpp | 2 | ||||
| -rw-r--r-- | Swift/Controllers/Chat/MUCController.h | 2 | ||||
| -rw-r--r-- | Swift/Controllers/Chat/UnitTest/ChatMessageParserTest.cpp | 134 | ||||
| -rw-r--r-- | Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp | 7 | 
12 files changed, 223 insertions, 47 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 @@ -51,3 +51,3 @@ namespace Swift {   */ -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) { @@ -320,3 +320,3 @@ void ChatController::postSendMessage(const std::string& body, boost::shared_ptr<  		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 { 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,3 +1,3 @@  /* - * Copyright (c) 2010-2013 Kevin Smith + * Copyright (c) 2010-2014 Kevin Smith   * Licensed under the GNU General Public License v3. @@ -30,3 +30,3 @@ namespace Swift {  		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(); 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,3 +1,3 @@  /* - * Copyright (c) 2010-2013 Kevin Smith + * Copyright (c) 2010-2014 Kevin Smith   * Licensed under the GNU General Public License v3. @@ -44,3 +44,3 @@ 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); @@ -203,3 +203,3 @@ std::string ChatControllerBase::addMessage(const std::string& message, const std  	} 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);  	} @@ -207,3 +207,3 @@ std::string ChatControllerBase::addMessage(const std::string& message, const std -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 ")) { @@ -211,3 +211,3 @@ void ChatControllerBase::replaceMessage(const std::string& message, const std::s  	} else { -		chatWindow_->replaceMessage(chatMessageParser_->parseMessageBody(message), id, time, highlight); +		chatWindow_->replaceMessage(chatMessageParser_->parseMessageBody(message,senderIsSelf), id, time, highlight);  	} @@ -282,3 +282,3 @@ void ChatControllerBase::handleIncomingMessage(boost::shared_ptr<MessageEvent> m  			if (lastMessage != lastMessagesUIID_.end()) { -				replaceMessage(body, lastMessagesUIID_[from], timeStamp, highlight); +				replaceMessage(body, lastMessagesUIID_[from], isIncomingMessageFromMe(message), timeStamp, highlight);  			} 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,3 +1,3 @@  /* - * Copyright (c) 2010-2013 Kevin Smith + * Copyright (c) 2010-2014 Kevin Smith   * Licensed under the GNU General Public License v3. @@ -57,3 +57,3 @@ namespace Swift {  			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); @@ -72,3 +72,3 @@ namespace Swift {  		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); @@ -129,3 +129,3 @@ namespace Swift {  			Highlighter* highlighter_; -			ChatMessageParser* chatMessageParser_; +			boost::shared_ptr<ChatMessageParser> chatMessageParser_;  			AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider_; 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 @@ -22,4 +22,4 @@ 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) {  	} @@ -28,3 +28,3 @@ namespace Swift { -	ChatWindow::ChatMessage ChatMessageParser::parseMessageBody(const std::string& body) { +	ChatWindow::ChatMessage ChatMessageParser::parseMessageBody(const std::string& body, bool senderIsSelf) {  		ChatWindow::ChatMessage parsedMessage; @@ -53,4 +53,17 @@ namespace Swift {  		} -		 +		/* 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; @@ -126,2 +139,56 @@ namespace Swift {  	} + +	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 ®ex, 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,3 +1,3 @@  /* - * Copyright (c) 2013 Kevin Smith + * Copyright (c) 2013-2014 Kevin Smith   * Licensed under the GNU General Public License v3. @@ -16,7 +16,10 @@ namespace Swift {  		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 @@ -147,2 +147,3 @@ ChatsManager::ChatsManager(  			highlightManager_(highlightManager), +			emoticons_(emoticons),  			clientBlockListManager_(clientBlockListManager), @@ -163,3 +164,2 @@ ChatsManager::ChatsManager(  	profileSettings_ = profileSettings; -	chatMessageParser_ = new ChatMessageParser(emoticons);  	presenceOracle_->onPresenceChange.connect(boost::bind(&ChatsManager::handlePresenceChange, this, _1)); @@ -210,3 +210,2 @@ ChatsManager::~ChatsManager() {  	delete mucSearchController_; -	delete chatMessageParser_;  	delete autoAcceptMUCInviteDecider_; @@ -699,3 +698,4 @@ 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; @@ -783,3 +783,4 @@ MUC::ref ChatsManager::handleJoinMUCRequest(const JID &mucJID, const boost::opti  		} -		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) { 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 @@ -176,4 +176,4 @@ namespace Swift {  			HighlightManager* highlightManager_; +			std::map<std::string, std::string> emoticons_;  			ClientBlockListManager* clientBlockListManager_; -			ChatMessageParser* chatMessageParser_;  			JID localMUCServiceJID_; 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 @@ -73,3 +73,3 @@ MUCController::MUCController (  		HighlightManager* highlightManager, -		ChatMessageParser* chatMessageParser, +		boost::shared_ptr<ChatMessageParser> chatMessageParser,  		bool isImpromptu, 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 @@ -52,3 +52,3 @@ namespace Swift {  		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(); 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 @@ -50,2 +50,7 @@ public: +	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) { @@ -55,5 +60,37 @@ public: +	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_); @@ -62,8 +99,79 @@ public:  		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");  	} @@ -71,3 +179,3 @@ public:  	void testOneEmoticon() { -		ChatMessageParser testling(emoticons_); +		ChatMessageParser testling(emoticons_, boost::make_shared<HighlightManager::HighlightRulesList>());  		ChatWindow::ChatMessage result = testling.parseMessageBody(" :) "); @@ -80,3 +188,3 @@ public:  	void testBareEmoticon() { -		ChatMessageParser testling(emoticons_); +		ChatMessageParser testling(emoticons_, boost::make_shared<HighlightManager::HighlightRulesList>());  		ChatWindow::ChatMessage result = testling.parseMessageBody(":)"); @@ -86,3 +194,3 @@ public:  	void testHiddenEmoticon() { -		ChatMessageParser testling(emoticons_); +		ChatMessageParser testling(emoticons_, boost::make_shared<HighlightManager::HighlightRulesList>());  		ChatWindow::ChatMessage result = testling.parseMessageBody("b:)a"); @@ -92,3 +200,3 @@ public:  	void testEndlineEmoticon() { -		ChatMessageParser testling(emoticons_); +		ChatMessageParser testling(emoticons_, boost::make_shared<HighlightManager::HighlightRulesList>());  		ChatWindow::ChatMessage result = testling.parseMessageBody("Lazy:)"); @@ -99,3 +207,3 @@ public:  	void testBoundedEmoticons() { -		ChatMessageParser testling(emoticons_); +		ChatMessageParser testling(emoticons_, boost::make_shared<HighlightManager::HighlightRulesList>());  		ChatWindow::ChatMessage result = testling.parseMessageBody(":)Lazy:("); @@ -107,3 +215,3 @@ public:  	void testEmoticonParenthesis() { -		ChatMessageParser testling(emoticons_); +		ChatMessageParser testling(emoticons_, boost::make_shared<HighlightManager::HighlightRulesList>());  		ChatWindow::ChatMessage result = testling.parseMessageBody("(Like this :))"); @@ -114,3 +222,2 @@ public: -  private: @@ -124,2 +231 @@ private:  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,3 +1,3 @@  /* - * Copyright (c) 2010-2013 Kevin Smith + * Copyright (c) 2010-2014 Kevin Smith   * Licensed under the GNU General Public License v3. @@ -83,3 +83,3 @@ public:  		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()); @@ -107,3 +107,2 @@ public:  		delete avatarManager_; -		delete chatMessageParser_;  	} @@ -431,3 +430,3 @@ private:  	HighlightManager* highlightManager_; -	ChatMessageParser* chatMessageParser_; +	boost::shared_ptr<ChatMessageParser> chatMessageParser_;  	boost::shared_ptr<CryptoProvider> crypto_; | 
 Swift
 Swift