From ff6103b78e16383cd4d0191ae39097496be6a65c Mon Sep 17 00:00:00 2001 From: Richard Maudsley Date: Wed, 22 Jan 2014 14:43:25 +0000 Subject: Testing highlight keywords. Change-Id: I808a4cf454198c41095adf294cb1d19860ed5df5 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 = sentStanza->getPayload(); if (replace) { eraseIf(unackedStanzas_, PairSecondEquals, 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(), 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 m std::map::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 info); void handleIncomingMessage(boost::shared_ptr message); std::string addMessage(const std::string& message, const std::string& senderName, bool senderIsSelf, boost::shared_ptr 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 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 part, parsedMessage.getParts()) { - boost::shared_ptr textPart; - if ((textPart = boost::dynamic_pointer_cast(part))) { - try { - boost::match_results 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(std::string(start, matchStart))); - } - boost::shared_ptr emoticonPart = boost::make_shared(); - std::map::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(std::string(start, text.end()))); - } + if (regexString.empty()) { + return message; + } + + regexString += ")"; + boost::regex emoticonRegex(regexString); + + ChatWindow::ChatMessage newMessage; + foreach (boost::shared_ptr part, message.getParts()) { + boost::shared_ptr textPart; + if ((textPart = boost::dynamic_pointer_cast(part))) { + try { + boost::match_results 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(std::string(start, matchStart))); + } + boost::shared_ptr emoticonPart = boost::make_shared(); + std::map::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(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 part, parsedMessage.getParts()) { + boost::shared_ptr textPart; + if ((textPart = boost::dynamic_pointer_cast(part))) { + try { + boost::match_results 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(std::string(start, matchStart))); + } + boost::shared_ptr highlightPart = boost::make_shared(); + 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(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& emoticons, const std::vector& 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 emoticons_; std::vector 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& getSenders() const { return senders_; } void setSenders(const std::vector&); + const std::vector& getSenderRegex() const { return senderRegex_; } const std::vector& getKeywords() const { return keywords_; } void setKeywords(const std::vector&); + const std::vector& 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(); } } diff --git a/Swift/QtUI/QtWebKitChatView.cpp b/Swift/QtUI/QtWebKitChatView.cpp index d1e250c..5d85913 100644 --- a/Swift/QtUI/QtWebKitChatView.cpp +++ b/Swift/QtUI/QtWebKitChatView.cpp @@ -557,7 +557,16 @@ QString QtWebKitChatView::chatMessageToHTML(const ChatWindow::ChatMessage& messa continue; } if ((highlightPart = boost::dynamic_pointer_cast(part))) { - //FIXME: Maybe do something here. Anything, really. + + //class ChatHighlightingMessagePart : public ChatMessagePart { + //public: + //std::string foregroundColor; + //std::string backgroundColor; + //std::string text; + //}; + + /* TODO: this is just temporary for testing. it should take the color into account... */ + result += "!" + QtUtilities::htmlEscape(P2QSTRING(highlightPart->text)) + "!"; continue; } @@ -565,7 +574,6 @@ QString QtWebKitChatView::chatMessageToHTML(const ChatWindow::ChatMessage& messa return result; } - QString QtWebKitChatView::getHighlightSpanStart(const HighlightAction& highlight) { QString color = QtUtilities::htmlEscape(P2QSTRING(highlight.getTextColor())); QString background = QtUtilities::htmlEscape(P2QSTRING(highlight.getTextBackground())); -- cgit v0.10.2-6-g49f6