diff options
Diffstat (limited to 'Swift/Controllers')
-rw-r--r-- | Swift/Controllers/Chat/ChatController.cpp | 2 | ||||
-rw-r--r-- | Swift/Controllers/Chat/ChatControllerBase.cpp | 8 | ||||
-rw-r--r-- | Swift/Controllers/Chat/ChatControllerBase.h | 2 | ||||
-rw-r--r-- | Swift/Controllers/Chat/ChatMessageParser.cpp | 137 | ||||
-rw-r--r-- | Swift/Controllers/Chat/ChatMessageParser.h | 4 | ||||
-rw-r--r-- | Swift/Controllers/HighlightRule.h | 3 |
6 files changed, 110 insertions, 46 deletions
diff --git a/Swift/Controllers/Chat/ChatController.cpp b/Swift/Controllers/Chat/ChatController.cpp index 13fd22b..af35984 100644 --- a/Swift/Controllers/Chat/ChatController.cpp +++ b/Swift/Controllers/Chat/ChatController.cpp @@ -303,7 +303,7 @@ void ChatController::postSendMessage(const std::string& body, boost::shared_ptr< boost::shared_ptr<Replace> replace = sentStanza->getPayload<Replace>(); if (replace) { eraseIf(unackedStanzas_, PairSecondEquals<boost::shared_ptr<Stanza>, std::string>(myLastMessageUIID_)); - replaceMessage(body, myLastMessageUIID_, boost::posix_time::microsec_clock::universal_time(), 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()); } diff --git a/Swift/Controllers/Chat/ChatControllerBase.cpp b/Swift/Controllers/Chat/ChatControllerBase.cpp index 23137dc..272a0fb 100644 --- a/Swift/Controllers/Chat/ChatControllerBase.cpp +++ b/Swift/Controllers/Chat/ChatControllerBase.cpp @@ -201,15 +201,15 @@ std::string ChatControllerBase::addMessage(const std::string& message, const std 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); } } @@ -280,7 +280,7 @@ void ChatControllerBase::handleIncomingMessage(boost::shared_ptr<MessageEvent> m std::map<JID, std::string>::iterator lastMessage; lastMessage = lastMessagesUIID_.find(from); if (lastMessage != lastMessagesUIID_.end()) { - replaceMessage(body, lastMessagesUIID_[from], timeStamp, highlight); + replaceMessage(body, lastMessagesUIID_[from], isIncomingMessageFromMe(message), timeStamp, highlight); } } else { diff --git a/Swift/Controllers/Chat/ChatControllerBase.h b/Swift/Controllers/Chat/ChatControllerBase.h index 7db94a4..0a955e6 100644 --- a/Swift/Controllers/Chat/ChatControllerBase.h +++ b/Swift/Controllers/Chat/ChatControllerBase.h @@ -55,7 +55,7 @@ namespace Swift { 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;} diff --git a/Swift/Controllers/Chat/ChatMessageParser.cpp b/Swift/Controllers/Chat/ChatMessageParser.cpp index 8449901..de4abb1 100644 --- a/Swift/Controllers/Chat/ChatMessageParser.cpp +++ b/Swift/Controllers/Chat/ChatMessageParser.cpp @@ -27,7 +27,7 @@ namespace Swift { 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 */ @@ -52,9 +52,20 @@ 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) + { std::string regexString; /* Parse two, emoticons */ foreach (StringPair emoticon, emoticons_) { @@ -62,52 +73,100 @@ namespace Swift { regexString += regexString.empty() ? "(" : "|"; regexString += Regex::escape(emoticon.first); } - if (!regexString.empty()) { - regexString += ")"; - boost::regex emoticonRegex(regexString); - - 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, emoticonRegex)) { - 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::ChatEmoticonMessagePart> emoticonPart = boost::make_shared<ChatWindow::ChatEmoticonMessagePart>(); - std::map<std::string, std::string>::const_iterator emoticonIterator = emoticons_.find(match.str()); - assert (emoticonIterator != emoticons_.end()); - const StringPair& emoticon = *emoticonIterator; - emoticonPart->imagePath = emoticon.second; - emoticonPart->alternativeText = emoticon.first; - newMessage.append(emoticonPart); - 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()))); - } + if (regexString.empty()) { + return message; + } + + regexString += ")"; + boost::regex emoticonRegex(regexString); + + ChatWindow::ChatMessage newMessage; + foreach (boost::shared_ptr<ChatWindow::ChatMessagePart> part, message.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, emoticonRegex)) { + 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::ChatEmoticonMessagePart> emoticonPart = boost::make_shared<ChatWindow::ChatEmoticonMessagePart>(); + std::map<std::string, std::string>::const_iterator emoticonIterator = emoticons_.find(match.str()); + assert (emoticonIterator != emoticons_.end()); + const StringPair& emoticon = *emoticonIterator; + emoticonPart->imagePath = emoticon.second; + emoticonPart->alternativeText = emoticon.first; + newMessage.append(emoticonPart); + start = matchEnd; } - catch (std::runtime_error) { - /* Basically too expensive to compute the regex results and it gave up, so pass through as text */ - newMessage.append(part); + if (start != text.end()) { + /* If there's plain text after the last emoticon, record it */ + newMessage.append(boost::make_shared<ChatWindow::ChatTextMessagePart>(std::string(start, text.end()))); } } - else { + 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 newMessage; + } + ChatWindow::ChatMessage ChatMessageParser::splitHighlight(const ChatWindow::ChatMessage& message) + { + ChatWindow::ChatMessage parsedMessage = message; + + foreach(const HighlightRule &rule, highlightRules_) { + 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 dd0d1bd..e899246 100644 --- a/Swift/Controllers/Chat/ChatMessageParser.h +++ b/Swift/Controllers/Chat/ChatMessageParser.h @@ -15,8 +15,10 @@ namespace Swift { class ChatMessageParser { public: ChatMessageParser(const std::map<std::string, std::string>& emoticons, const std::vector<HighlightRule>& highlightRules); - ChatWindow::ChatMessage parseMessageBody(const std::string& body); + 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_; std::vector<HighlightRule> highlightRules_; diff --git a/Swift/Controllers/HighlightRule.h b/Swift/Controllers/HighlightRule.h index 523be47..ac1b6be 100644 --- a/Swift/Controllers/HighlightRule.h +++ b/Swift/Controllers/HighlightRule.h @@ -30,9 +30,11 @@ namespace Swift { 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); @@ -87,6 +89,7 @@ namespace Swift { ar & matchCase_; ar & matchWholeWords_; ar & action_; + updateRegex(); } } |