summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'Swift/Controllers/Highlighting')
-rw-r--r--Swift/Controllers/Highlighting/HighlightAction.cpp75
-rw-r--r--Swift/Controllers/Highlighting/HighlightAction.h68
-rw-r--r--Swift/Controllers/Highlighting/HighlightConfiguration.cpp36
-rw-r--r--Swift/Controllers/Highlighting/HighlightConfiguration.h81
-rw-r--r--Swift/Controllers/Highlighting/HighlightEditorController.cpp57
-rw-r--r--Swift/Controllers/Highlighting/HighlightEditorController.h49
-rw-r--r--Swift/Controllers/Highlighting/HighlightManager.cpp102
-rw-r--r--Swift/Controllers/Highlighting/HighlightManager.h64
-rw-r--r--Swift/Controllers/Highlighting/Highlighter.cpp113
-rw-r--r--Swift/Controllers/Highlighting/Highlighter.h38
10 files changed, 683 insertions, 0 deletions
diff --git a/Swift/Controllers/Highlighting/HighlightAction.cpp b/Swift/Controllers/Highlighting/HighlightAction.cpp
new file mode 100644
index 0000000..e9f14df
--- /dev/null
+++ b/Swift/Controllers/Highlighting/HighlightAction.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2012 Maciej Niedzielski
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+/*
+ * Copyright (c) 2015-2017 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#include <Swift/Controllers/Highlighting/HighlightAction.h>
+
+namespace Swift {
+
+
+
+bool operator ==(const HighlightAction& a, const HighlightAction& b) {
+ if (a.getFrontColor() != b.getFrontColor()) {
+ return false;
+ }
+ if (a.getBackColor() != b.getBackColor()) {
+ return false;
+ }
+ if (a.getSoundFilePath() != b.getSoundFilePath()) {
+ return false;
+ }
+ if (a.isSystemNotificationEnabled() != b.isSystemNotificationEnabled()) {
+ return false;
+ }
+ return true;
+}
+
+bool operator !=(const HighlightAction& a, const HighlightAction& b) {
+ return !(a == b);
+}
+
+void HighlightAction::setFrontColor(const boost::optional<std::string>& frontColor) {
+ frontColor_ = frontColor;
+}
+
+boost::optional<std::string> HighlightAction::getFrontColor() const {
+ return frontColor_;
+}
+
+void HighlightAction::setBackColor(const boost::optional<std::string>& backColor) {
+ backColor_ = backColor;
+}
+
+boost::optional<std::string> HighlightAction::getBackColor() const {
+ return backColor_;
+}
+
+void HighlightAction::setSoundFilePath(const boost::optional<std::string>& soundFilePath) {
+ soundFilePath_ = soundFilePath;
+}
+
+boost::optional<std::string> HighlightAction::getSoundFilePath() const {
+ return soundFilePath_;
+}
+
+void HighlightAction::setSystemNotificationEnabled(bool systemNotificationEnabled) {
+ systemNotificaitonEnabled_ = systemNotificationEnabled;
+}
+
+bool HighlightAction::isSystemNotificationEnabled() const {
+ return systemNotificaitonEnabled_;
+}
+
+bool HighlightAction::isEmpty() const {
+ return !frontColor_.is_initialized() && !backColor_.is_initialized() && !soundFilePath_.is_initialized() && !systemNotificaitonEnabled_;
+}
+
+}
diff --git a/Swift/Controllers/Highlighting/HighlightAction.h b/Swift/Controllers/Highlighting/HighlightAction.h
new file mode 100644
index 0000000..da92901
--- /dev/null
+++ b/Swift/Controllers/Highlighting/HighlightAction.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2012 Maciej Niedzielski
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+/*
+ * Copyright (c) 2014-2017 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <string>
+
+#include <boost/archive/text_iarchive.hpp>
+#include <boost/archive/text_oarchive.hpp>
+#include <boost/optional.hpp>
+#include <boost/serialization/optional.hpp>
+
+namespace Swift {
+ class HighlightAction {
+ public:
+ void setFrontColor(const boost::optional<std::string>& frontColor);
+ boost::optional<std::string> getFrontColor() const;
+
+ void setBackColor(const boost::optional<std::string>& backColor);
+ boost::optional<std::string> getBackColor() const;
+
+ void setSoundFilePath(const boost::optional<std::string>& soundFilePath);
+ boost::optional<std::string> getSoundFilePath() const;
+
+ void setSystemNotificationEnabled(bool systemNotificationEnabled);
+ bool isSystemNotificationEnabled() const;
+
+ // @return returns true if the HighlightAction would result in no
+ // noticable action to the user.
+ bool isEmpty() const;
+
+ private:
+ friend class boost::serialization::access;
+ template<class Archive> void serialize(Archive & ar, const unsigned int version);
+
+ private:
+ // Highlight color.
+ boost::optional<std::string> frontColor_;
+ boost::optional<std::string> backColor_;
+
+ // Audio notification.
+ boost::optional<std::string> soundFilePath_;
+
+ // macOS Notification Center or similar.
+ bool systemNotificaitonEnabled_ = false;
+ };
+
+ bool operator ==(const HighlightAction& a, const HighlightAction& b);
+ bool operator !=(const HighlightAction& a, const HighlightAction& b);
+
+ template<class Archive>
+ void HighlightAction::serialize(Archive& ar, const unsigned int /*version*/) {
+ ar & frontColor_;
+ ar & backColor_;
+ ar & soundFilePath_;
+ ar & systemNotificaitonEnabled_;
+ }
+
+}
diff --git a/Swift/Controllers/Highlighting/HighlightConfiguration.cpp b/Swift/Controllers/Highlighting/HighlightConfiguration.cpp
new file mode 100644
index 0000000..e82adb8
--- /dev/null
+++ b/Swift/Controllers/Highlighting/HighlightConfiguration.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2016-2017 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#include <Swift/Controllers/Highlighting/HighlightConfiguration.h>
+
+namespace Swift {
+
+bool operator ==(const HighlightConfiguration& a, const HighlightConfiguration& b) {
+ if (a.keywordHighlights != b.keywordHighlights) {
+ return false;
+ }
+ if (a.contactHighlights != b.contactHighlights) {
+ return false;
+ }
+ if (a.ownMentionAction != b.ownMentionAction) {
+ return false;
+ }
+ if (a.playSoundOnIncomingDirectMessages != b.playSoundOnIncomingDirectMessages) {
+ return false;
+ }
+ if (a.showNotificationOnIncomingDirectMessages != b.showNotificationOnIncomingDirectMessages) {
+ return false;
+ }
+ if (a.playSoundOnIncomingGroupchatMessages != b.playSoundOnIncomingGroupchatMessages) {
+ return false;
+ }
+ if (a.showNotificationOnIncomingGroupchatMessages != b.showNotificationOnIncomingGroupchatMessages) {
+ return false;
+ }
+ return true;
+}
+
+}
diff --git a/Swift/Controllers/Highlighting/HighlightConfiguration.h b/Swift/Controllers/Highlighting/HighlightConfiguration.h
new file mode 100644
index 0000000..d262dba
--- /dev/null
+++ b/Swift/Controllers/Highlighting/HighlightConfiguration.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2016-2017 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include <boost/archive/text_iarchive.hpp>
+#include <boost/archive/text_oarchive.hpp>
+
+#include <Swift/Controllers/Highlighting/HighlightAction.h>
+
+namespace Swift {
+
+class HighlightConfiguration {
+public:
+ class ContactHighlight {
+ public:
+ friend class boost::serialization::access;
+ template<class Archive> void serialize(Archive & ar, const unsigned int version);
+
+ public:
+ std::string name;
+ HighlightAction action;
+ };
+
+ class KeywordHightlight {
+ public:
+ friend class boost::serialization::access;
+ template<class Archive> void serialize(Archive & ar, const unsigned int version);
+
+ public:
+ std::string keyword;
+ bool matchCaseSensitive = false;
+ HighlightAction action;
+ };
+
+ friend class boost::serialization::access;
+ template<class Archive> void serialize(Archive & ar, const unsigned int version);
+
+public:
+ std::vector<KeywordHightlight> keywordHighlights;
+ std::vector<ContactHighlight> contactHighlights;
+ HighlightAction ownMentionAction;
+ bool playSoundOnIncomingDirectMessages = false;
+ bool showNotificationOnIncomingDirectMessages = false;
+ bool playSoundOnIncomingGroupchatMessages = false;
+ bool showNotificationOnIncomingGroupchatMessages = false;
+};
+
+bool operator ==(HighlightConfiguration const& a, HighlightConfiguration const& b);
+
+template<class Archive>
+void HighlightConfiguration::ContactHighlight::serialize(Archive& ar, const unsigned int /*version*/) {
+ ar & name;
+ ar & action;
+}
+
+template<class Archive>
+void HighlightConfiguration::KeywordHightlight::serialize(Archive& ar, const unsigned int /*version*/) {
+ ar & keyword;
+ ar & matchCaseSensitive;
+ ar & action;
+}
+
+template<class Archive>
+void HighlightConfiguration::serialize(Archive& ar, const unsigned int /*version*/) {
+ ar & keywordHighlights;
+ ar & contactHighlights;
+ ar & ownMentionAction;
+ ar & playSoundOnIncomingDirectMessages;
+ ar & showNotificationOnIncomingDirectMessages;
+ ar & playSoundOnIncomingGroupchatMessages;
+ ar & showNotificationOnIncomingGroupchatMessages;
+}
+
+}
diff --git a/Swift/Controllers/Highlighting/HighlightEditorController.cpp b/Swift/Controllers/Highlighting/HighlightEditorController.cpp
new file mode 100644
index 0000000..50da3dc
--- /dev/null
+++ b/Swift/Controllers/Highlighting/HighlightEditorController.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2012 Maciej Niedzielski
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+/*
+ * Copyright (c) 2014-2017 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#include <Swift/Controllers/Highlighting/HighlightEditorController.h>
+
+#include <boost/bind.hpp>
+
+#include <Swift/Controllers/ContactSuggester.h>
+#include <Swift/Controllers/UIEvents/RequestHighlightEditorUIEvent.h>
+#include <Swift/Controllers/UIEvents/UIEventStream.h>
+#include <Swift/Controllers/UIInterfaces/HighlightEditorWindow.h>
+#include <Swift/Controllers/UIInterfaces/HighlightEditorWindowFactory.h>
+
+namespace Swift {
+
+HighlightEditorController::HighlightEditorController(UIEventStream* uiEventStream, HighlightEditorWindowFactory* highlightEditorWindowFactory, HighlightManager* highlightManager)
+: highlightEditorWindowFactory_(highlightEditorWindowFactory), highlightEditorWindow_(nullptr), highlightManager_(highlightManager), contactSuggester_(nullptr)
+{
+ uiEventStream->onUIEvent.connect(boost::bind(&HighlightEditorController::handleUIEvent, this, _1));
+}
+
+HighlightEditorController::~HighlightEditorController()
+{
+ delete highlightEditorWindow_;
+ highlightEditorWindow_ = nullptr;
+}
+
+void HighlightEditorController::handleUIEvent(std::shared_ptr<UIEvent> rawEvent)
+{
+ std::shared_ptr<RequestHighlightEditorUIEvent> event = std::dynamic_pointer_cast<RequestHighlightEditorUIEvent>(rawEvent);
+ if (event) {
+ if (!highlightEditorWindow_) {
+ highlightEditorWindow_ = highlightEditorWindowFactory_->createHighlightEditorWindow();
+ highlightEditorWindow_->setHighlightManager(highlightManager_);
+ highlightEditorWindow_->onContactSuggestionsRequested.connect(boost::bind(&HighlightEditorController::handleContactSuggestionsRequested, this, _1));
+ }
+ highlightEditorWindow_->show();
+ }
+}
+
+void HighlightEditorController::handleContactSuggestionsRequested(const std::string& text)
+{
+ if (contactSuggester_) {
+ highlightEditorWindow_->setContactSuggestions(contactSuggester_->getSuggestions(text, true));
+ }
+}
+
+}
diff --git a/Swift/Controllers/Highlighting/HighlightEditorController.h b/Swift/Controllers/Highlighting/HighlightEditorController.h
new file mode 100644
index 0000000..d7608a5
--- /dev/null
+++ b/Swift/Controllers/Highlighting/HighlightEditorController.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2012 Maciej Niedzielski
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+/*
+ * Copyright (c) 2014-2017 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <memory>
+#include <string>
+
+#include <Swift/Controllers/UIEvents/UIEvent.h>
+
+namespace Swift {
+
+ class UIEventStream;
+
+ class HighlightEditorWindowFactory;
+ class HighlightEditorWindow;
+
+ class HighlightManager;
+ class ContactSuggester;
+
+ class HighlightEditorController {
+ public:
+ HighlightEditorController(UIEventStream* uiEventStream, HighlightEditorWindowFactory* highlightEditorWindowFactory, HighlightManager* highlightManager);
+ ~HighlightEditorController();
+
+ HighlightManager* getHighlightManager() const { return highlightManager_; }
+ void setContactSuggester(ContactSuggester *suggester) { contactSuggester_ = suggester; }
+
+ private:
+ void handleUIEvent(std::shared_ptr<UIEvent> event);
+ void handleContactSuggestionsRequested(const std::string& text);
+
+ private:
+ HighlightEditorWindowFactory* highlightEditorWindowFactory_;
+ HighlightEditorWindow* highlightEditorWindow_;
+ HighlightManager* highlightManager_;
+ ContactSuggester* contactSuggester_;
+ };
+
+}
diff --git a/Swift/Controllers/Highlighting/HighlightManager.cpp b/Swift/Controllers/Highlighting/HighlightManager.cpp
new file mode 100644
index 0000000..89261af
--- /dev/null
+++ b/Swift/Controllers/Highlighting/HighlightManager.cpp
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2012 Maciej Niedzielski
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+/*
+ * Copyright (c) 2014-2017 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#include <Swift/Controllers/Highlighting/HighlightManager.h>
+
+#include <cassert>
+#include <sstream>
+
+#include <boost/algorithm/string.hpp>
+#include <boost/archive/text_iarchive.hpp>
+#include <boost/archive/text_oarchive.hpp>
+#include <boost/bind.hpp>
+#include <boost/numeric/conversion/cast.hpp>
+#include <boost/regex.hpp>
+#include <boost/serialization/vector.hpp>
+
+#include <Swiften/Base/Log.h>
+
+#include <Swift/Controllers/Highlighting/HighlightConfiguration.h>
+#include <Swift/Controllers/Highlighting/Highlighter.h>
+#include <Swift/Controllers/SettingConstants.h>
+#include <Swift/Controllers/Settings/SettingsProvider.h>
+
+namespace Swift {
+
+HighlightManager::HighlightManager(SettingsProvider* settings)
+ : settings_(settings)
+ , storingSettings_(false) {
+ highlightConfiguration_ = std::make_shared<HighlightConfiguration>();
+ loadSettings();
+ handleSettingChangedConnection_ = settings_->onSettingChanged.connect(boost::bind(&HighlightManager::handleSettingChanged, this, _1));
+}
+
+void HighlightManager::handleSettingChanged(const std::string& settingPath) {
+ if (!storingSettings_ && SettingConstants::HIGHLIGHT_RULES.getKey() == settingPath) {
+ loadSettings();
+ }
+}
+
+HighlightConfiguration HighlightManager::getDefaultConfig() {
+ HighlightConfiguration defaultConfiguration;
+ defaultConfiguration.playSoundOnIncomingDirectMessages = true;
+ defaultConfiguration.showNotificationOnIncomingDirectMessages = true;
+ defaultConfiguration.ownMentionAction.setFrontColor(std::string("black"));
+ defaultConfiguration.ownMentionAction.setBackColor(std::string("yellow"));
+ defaultConfiguration.ownMentionAction.setSoundFilePath(std::string("/sounds/message-received.wav"));
+ defaultConfiguration.ownMentionAction.setSystemNotificationEnabled(true);
+ return defaultConfiguration;
+}
+
+void HighlightManager::storeSettings() {
+ storingSettings_ = true; // don't reload settings while saving
+ settings_->storeSetting(SettingConstants::HIGHLIGHT_RULES_V2, highlightConfigurationToString(*highlightConfiguration_));
+ storingSettings_ = false;
+}
+
+void HighlightManager::loadSettings() {
+ std::string configString = settings_->getSetting(SettingConstants::HIGHLIGHT_RULES_V2);
+ *highlightConfiguration_ = highlightConfigurationFromString(configString);
+}
+
+Highlighter* HighlightManager::createHighlighter(NickResolver* nickResolver) {
+ return new Highlighter(this, nickResolver);
+}
+
+void HighlightManager::resetToDefaultConfiguration() {
+ *highlightConfiguration_ = getDefaultConfig();
+}
+
+HighlightConfiguration HighlightManager::highlightConfigurationFromString(const std::string& dataString) {
+ std::stringstream stream;
+ stream << dataString;
+
+ HighlightConfiguration configuration;
+ try {
+ boost::archive::text_iarchive archive(stream);
+ archive >> configuration;
+ }
+ catch (boost::archive::archive_exception&) {
+ configuration = getDefaultConfig();
+ SWIFT_LOG(warning) << "Failed to load highlight configuration. Will use default configuration instead." << std::endl;
+ }
+ return configuration;
+}
+
+std::string HighlightManager::highlightConfigurationToString(const HighlightConfiguration& configuration) {
+ std::stringstream stream;
+ boost::archive::text_oarchive archive(stream);
+ archive & configuration;
+ return stream.str();
+}
+
+}
diff --git a/Swift/Controllers/Highlighting/HighlightManager.h b/Swift/Controllers/Highlighting/HighlightManager.h
new file mode 100644
index 0000000..13f59fa
--- /dev/null
+++ b/Swift/Controllers/Highlighting/HighlightManager.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2012 Maciej Niedzielski
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+/*
+ * Copyright (c) 2014-2017 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <memory>
+#include <string>
+
+#include <boost/signals2.hpp>
+
+#include <Swift/Controllers/Highlighting/HighlightConfiguration.h>
+
+namespace Swift {
+
+ class NickResolver;
+ class SettingsProvider;
+ class Highlighter;
+
+ class HighlightManager {
+ public:
+ HighlightManager(SettingsProvider* settings);
+
+ Highlighter* createHighlighter(NickResolver* nickResolver);
+
+ std::shared_ptr<HighlightConfiguration> getConfiguration() const {
+ return highlightConfiguration_;
+ }
+
+ void setConfiguration(const HighlightConfiguration& config) {
+ *highlightConfiguration_ = config;
+ storeSettings();
+ }
+
+ void resetToDefaultConfiguration();
+
+ void storeSettings();
+ void loadSettings();
+
+ boost::signals2::signal<void (const HighlightAction&)> onHighlight;
+
+ private:
+ void handleSettingChanged(const std::string& settingPath);
+
+ static HighlightConfiguration getDefaultConfig();
+
+ static HighlightConfiguration highlightConfigurationFromString(const std::string& dataString);
+ static std::string highlightConfigurationToString(const HighlightConfiguration& configuration);
+
+ private:
+ SettingsProvider* settings_;
+ bool storingSettings_;
+ std::shared_ptr<HighlightConfiguration> highlightConfiguration_;
+ boost::signals2::scoped_connection handleSettingChangedConnection_;
+ };
+}
diff --git a/Swift/Controllers/Highlighting/Highlighter.cpp b/Swift/Controllers/Highlighting/Highlighter.cpp
new file mode 100644
index 0000000..b05de2d
--- /dev/null
+++ b/Swift/Controllers/Highlighting/Highlighter.cpp
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2012 Maciej Niedzielski
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+/*
+ * Copyright (c) 2014-2017 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#include <Swift/Controllers/Highlighting/Highlighter.h>
+
+#include <set>
+#include <string>
+
+#include <Swiften/Base/String.h>
+#include <Swiften/Base/format.h>
+#include <Swiften/Client/NickResolver.h>
+
+#include <Swift/Controllers/Highlighting/HighlightManager.h>
+#include <Swift/Controllers/Intl.h>
+#include <Swift/Controllers/XMPPEvents/MessageEvent.h>
+
+namespace Swift {
+
+Highlighter::Highlighter(HighlightManager* manager, NickResolver* nickResolver)
+ : manager_(manager), nickResolver_(nickResolver) {
+}
+
+void Highlighter::handleSystemNotifications(const ChatWindow::ChatMessage& message, std::shared_ptr<MessageEvent> event) {
+ if (std::shared_ptr<MessageEvent> messageEvent = std::dynamic_pointer_cast<MessageEvent>(event)) {
+ JID jid = messageEvent->getStanza()->getFrom();
+ std::string nickname = nickResolver_->jidToNick(jid);
+
+ std::string messageText = messageEvent->getStanza()->getBody().get_value_or("");
+ if (boost::starts_with(messageText, "/me ")) {
+ messageText = "*" + String::getSplittedAtFirst(messageText, ' ').second + "*";
+ }
+
+ if (message.getHighlightActionDirectMessage().isSystemNotificationEnabled()) {
+ // title: Romeo says
+ // message: message
+ std::string title = str(format(QT_TRANSLATE_NOOP("", "%1% says")) % nickname);
+ event->addNotification(title, messageText);
+ }
+ if (message.getHighlightActionGroupMessage().isSystemNotificationEnabled()) {
+ // title: Romeo in $roomJID says
+ // message: message
+ std::string roomName = jid.getNode();
+ std::string title = str(format(QT_TRANSLATE_NOOP("", "%1% in %2% says")) % nickname % roomName);
+ event->addNotification(title, messageText);
+ }
+ if (message.getHighlightActionOwnMention().isSystemNotificationEnabled()) {
+ // title: Romeo mentioned you in $roomJID
+ // message: message
+ std::string roomName = jid.getNode();
+ std::string title = str(format(QT_TRANSLATE_NOOP("", "%1% mentioned you in %2%")) % nickname % roomName);
+ event->addNotification(title, messageText);
+ }
+ if (message.getHighlightActionSender().isSystemNotificationEnabled()) {
+ // title: Romeo says
+ // message: message
+ auto title = str(format(QT_TRANSLATE_NOOP("", "%1% says")) % nickname);
+ event->addNotification(title, messageText);
+ }
+ for (auto&& part : message.getParts()) {
+ auto highlightPart = std::dynamic_pointer_cast<ChatWindow::ChatHighlightingMessagePart>(part);
+ if (highlightPart && highlightPart->action.isSystemNotificationEnabled()) {
+ // title: Romeo mentioned '$keyword'
+ // message: message
+ auto title = str(format(QT_TRANSLATE_NOOP("", "%1% mentioned '%2%'")) % nickname % highlightPart->text);
+ event->addNotification(title, messageText);
+ }
+ }
+ }
+}
+
+void Highlighter::handleSoundNotifications(const ChatWindow::ChatMessage& chatMessage) {
+ std::set<std::string> playedSoundPaths;
+ std::vector<HighlightAction> actionsToPlay;
+
+ // collect unique sounds to play
+ auto checkSoundActionAndQueueUnique = [&](const HighlightAction& action) {
+ if (action.getSoundFilePath()) {
+ auto soundFilePath = action.getSoundFilePath().get_value_or("");
+ if (playedSoundPaths.find(soundFilePath) == playedSoundPaths.end()) {
+ playedSoundPaths.insert(soundFilePath);
+ actionsToPlay.push_back(action);
+ }
+ }
+ };
+
+ for (auto&& part : chatMessage.getParts()) {
+ auto highlightMessage = std::dynamic_pointer_cast<ChatWindow::ChatHighlightingMessagePart>(part);
+ if (highlightMessage) {
+ checkSoundActionAndQueueUnique(highlightMessage->action);
+ }
+ }
+
+ checkSoundActionAndQueueUnique(chatMessage.getHighlightActionSender());
+ checkSoundActionAndQueueUnique(chatMessage.getHighlightActionOwnMention());
+ checkSoundActionAndQueueUnique(chatMessage.getHighlightActionDirectMessage());
+ checkSoundActionAndQueueUnique(chatMessage.getHighlightActionGroupMessage());
+
+ // play sounds
+ for (const auto& action : actionsToPlay) {
+ manager_->onHighlight(action);
+ }
+}
+
+}
diff --git a/Swift/Controllers/Highlighting/Highlighter.h b/Swift/Controllers/Highlighting/Highlighter.h
new file mode 100644
index 0000000..51308a1
--- /dev/null
+++ b/Swift/Controllers/Highlighting/Highlighter.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2012 Maciej Niedzielski
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+/*
+ * Copyright (c) 2016-2017 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <string>
+
+#include <Swift/Controllers/Highlighting/HighlightConfiguration.h>
+#include <Swift/Controllers/UIInterfaces/ChatWindow.h>
+#include <Swift/Controllers/XMPPEvents/MessageEvent.h>
+
+namespace Swift {
+
+ class HighlightManager;
+ class NickResolver;
+
+ class Highlighter {
+ public:
+ Highlighter(HighlightManager* manager, NickResolver* nickResolver);
+
+ void handleSystemNotifications(const ChatWindow::ChatMessage& message, std::shared_ptr<MessageEvent> event);
+ void handleSoundNotifications(const ChatWindow::ChatMessage& chatMessage);
+
+ private:
+ HighlightManager* manager_;
+ NickResolver* nickResolver_;
+ };
+
+}