From 96be62f4a700e3bd50f4b6f177f02e5820a09106 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Remko=20Tron=C3=A7on?= <git@el-tramo.be>
Date: Sat, 23 Oct 2010 10:22:10 +0200
Subject: Don't lose notification enabledness when the user changes status.

Resolves: #651
Release-Notes: The notification toggle on Linux will now be respected.

diff --git a/SwifTools/Notifier/GrowlNotifier.cpp b/SwifTools/Notifier/GrowlNotifier.cpp
index 066c4d0..3eb580a 100644
--- a/SwifTools/Notifier/GrowlNotifier.cpp
+++ b/SwifTools/Notifier/GrowlNotifier.cpp
@@ -70,7 +70,7 @@ GrowlNotifier::GrowlNotifier(const String& name) {
 	Growl_SetDelegate(&delegate_);
 }
 
-void GrowlNotifier::doShowMessage(Type type, const String& subject, const String& description, const boost::filesystem::path& picturePath, boost::function<void()> callback) {
+void GrowlNotifier::showMessage(Type type, const String& subject, const String& description, const boost::filesystem::path& picturePath, boost::function<void()> callback) {
 	ByteArray picture;
 	picture.readFromFile(picturePath.string());
 
diff --git a/SwifTools/Notifier/GrowlNotifier.h b/SwifTools/Notifier/GrowlNotifier.h
index 379181d..5d618e6 100644
--- a/SwifTools/Notifier/GrowlNotifier.h
+++ b/SwifTools/Notifier/GrowlNotifier.h
@@ -24,7 +24,7 @@ namespace Swift {
 		public:
 			GrowlNotifier(const String& name);
 
-			virtual void doShowMessage(Type type, const String& subject, const String& description, const boost::filesystem::path& picture, boost::function<void()> callback);
+			virtual void showMessage(Type type, const String& subject, const String& description, const boost::filesystem::path& picture, boost::function<void()> callback);
 		
 		private:
 			Growl_Delegate delegate_;
diff --git a/SwifTools/Notifier/LoggingNotifier.h b/SwifTools/Notifier/LoggingNotifier.h
index 138d1c5..eea07ef 100644
--- a/SwifTools/Notifier/LoggingNotifier.h
+++ b/SwifTools/Notifier/LoggingNotifier.h
@@ -12,7 +12,7 @@
 namespace Swift {
 	class LoggingNotifier : public Notifier {
 		public:
-			virtual void doShowMessage(Type type, const String& subject, const String& description, const boost::filesystem::path& picture, boost::function<void()> callback) {
+			virtual void showMessage(Type type, const String& subject, const String& description, const boost::filesystem::path& picture, boost::function<void()> callback) {
 				notifications.push_back(Notification(type, subject, description, picture, callback));
 			}
 
diff --git a/SwifTools/Notifier/Notifier.cpp b/SwifTools/Notifier/Notifier.cpp
index c03970b..2c2660e 100644
--- a/SwifTools/Notifier/Notifier.cpp
+++ b/SwifTools/Notifier/Notifier.cpp
@@ -11,18 +11,9 @@ namespace Swift {
 const int Notifier::DEFAULT_STATUS_NOTIFICATION_TIMEOUT_SECONDS = 3;
 const int Notifier::DEFAULT_MESSAGE_NOTIFICATION_TIMEOUT_SECONDS = 5;
 
-Notifier::Notifier() : enabled(true) {
-}
-
 Notifier::~Notifier() {
 }
 
-void Notifier::showMessage(Type type, const String& subject, const String& description, const boost::filesystem::path& picture, boost::function<void()> callback) {
-	if (enabled) {
-		doShowMessage(type, subject, description, picture, callback);
-	}
-}
-
 String Notifier::typeToString(Type type) {
 	switch (type) {
 		case ContactAvailable: return "Contact Becomes Available";
diff --git a/SwifTools/Notifier/Notifier.h b/SwifTools/Notifier/Notifier.h
index e609867..b7c705e 100644
--- a/SwifTools/Notifier/Notifier.h
+++ b/SwifTools/Notifier/Notifier.h
@@ -14,7 +14,6 @@
 namespace Swift {
 	class Notifier {
 		public:
-			Notifier();
 			virtual ~Notifier();
 
 			enum Type { ContactAvailable, ContactUnavailable, ContactStatusChange, IncomingMessage, SystemMessage };
@@ -27,20 +26,6 @@ namespace Swift {
 				const String& subject, 
 				const String& description, 
 				const boost::filesystem::path& picture,
-				boost::function<void()> callback);
-
-			void setEnabled(bool b) {
-				enabled = b;
-			}
-
-			bool getEnabled() const {return enabled;}
-
-		private:
-			virtual void doShowMessage(
-				Type type,
-				const String& subject, 
-				const String& description, 
-				const boost::filesystem::path& picture,
 				boost::function<void()> callback) = 0;
 
 		protected:
@@ -50,8 +35,5 @@ namespace Swift {
 
 			static const int DEFAULT_STATUS_NOTIFICATION_TIMEOUT_SECONDS;
 			static const int DEFAULT_MESSAGE_NOTIFICATION_TIMEOUT_SECONDS;
-
-		private:
-			bool enabled;
 	};
 }
diff --git a/SwifTools/Notifier/NullNotifier.h b/SwifTools/Notifier/NullNotifier.h
index 0b0b3df..e97329b 100644
--- a/SwifTools/Notifier/NullNotifier.h
+++ b/SwifTools/Notifier/NullNotifier.h
@@ -11,7 +11,7 @@
 namespace Swift {
 	class NullNotifier : public Notifier {
 		public:
-			virtual void doShowMessage(Type, const String&, const String&, const boost::filesystem::path&, boost::function<void()>) {
+			virtual void showMessage(Type, const String&, const String&, const boost::filesystem::path&, boost::function<void()>) {
 			}
 	};
 }
diff --git a/SwifTools/Notifier/SnarlNotifier.h b/SwifTools/Notifier/SnarlNotifier.h
index 83d4715..2350e29 100644
--- a/SwifTools/Notifier/SnarlNotifier.h
+++ b/SwifTools/Notifier/SnarlNotifier.h
@@ -19,7 +19,7 @@ namespace Swift {
 			SnarlNotifier(const String& name, Win32NotifierWindow* window, const boost::filesystem::path& icon);
 			~SnarlNotifier();
 
-			virtual void doShowMessage(Type type, const String& subject, const String& description, const boost::filesystem::path& picture, boost::function<void()> callback);
+			virtual void showMessage(Type type, const String& subject, const String& description, const boost::filesystem::path& picture, boost::function<void()> callback);
 		
 		private:
 			void handleMessageReceived(MSG* message);
diff --git a/SwifTools/Notifier/TogglableNotifier.h b/SwifTools/Notifier/TogglableNotifier.h
new file mode 100644
index 0000000..1e87807
--- /dev/null
+++ b/SwifTools/Notifier/TogglableNotifier.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include "SwifTools/Notifier/Notifier.h"
+
+namespace Swift {
+	class TogglableNotifier : public Notifier {
+		public:
+			TogglableNotifier(Notifier* notifier) : notifier(notifier), persistentEnabled(true), temporarilyDisabled(false) {
+			}
+
+			/**
+			 * Set a long-term (usually user-set) enabled.
+			 * This may be temporarily overriden by the application, e.g. if the 
+			 * user is marked DND.
+			 */
+			void setPersistentEnabled(bool b) {
+				persistentEnabled = b;
+			}
+
+			/**
+			 * Set a temporary override to stop notifications without changing the 
+			 * long-term state. e.g. if the user goes DND, but the persistent 
+			 * enabled shouldn't be lost when they become available again.
+			 */
+			void setTemporarilyDisabled(bool b) {
+				temporarilyDisabled = b;
+			}
+
+			/**
+			 * Get the result of applying the temporary override to the persistent 
+			 * enabledness.
+			 */
+			bool getCurrentlyEnabled() const {
+				return persistentEnabled && !temporarilyDisabled;
+			}
+ 
+			virtual void showMessage(Type type, const String& subject, const String& description, const boost::filesystem::path& picture, boost::function<void()> callback) {
+				if (getCurrentlyEnabled()) {
+					notifier->showMessage(type, subject, description, picture, callback);
+				}
+			}
+
+		private:
+			Notifier* notifier;
+			bool persistentEnabled;
+			bool temporarilyDisabled;
+	};
+}
diff --git a/Swift/Controllers/MainController.cpp b/Swift/Controllers/MainController.cpp
index 7cf68a1..fcd161b 100644
--- a/Swift/Controllers/MainController.cpp
+++ b/Swift/Controllers/MainController.cpp
@@ -39,6 +39,7 @@
 #include "Swift/Controllers/PresenceNotifier.h"
 #include "Swift/Controllers/EventNotifier.h"
 #include "SwifTools/Dock/Dock.h"
+#include "SwifTools/Notifier/TogglableNotifier.h"
 #include "Swiften/Base/foreach.h"
 #include "Swiften/Base/String.h"
 #include "Swiften/Client/Client.h"
@@ -69,6 +70,7 @@ static const String CLIENT_NAME = "Swift";
 static const String CLIENT_VERSION = "1.0-devel";
 static const String CLIENT_NODE = "http://swift.im";
 
+static const String SHOW_NOTIFICATIONS = "showNotifications";
 
 MainController::MainController(
 		ChatWindowFactory* chatWindowFactory,
@@ -119,12 +121,12 @@ MainController::MainController(
 	mucSearchWindowFactory_ = mucSearchWindowFactory;
 	eventWindowFactory_ = eventWindowFactory;
 	dock_ = dock;
-	notifier_ = notifier;
 	chatListWindowFactory_ = chatListWindowFactory;
 	uiEventStream_ = new UIEventStream();
 
 	avatarStorage_ = avatarStorage;
 	capsStorage_ = capsStorage;
+	notifier_ = new TogglableNotifier(notifier);
 	eventController_ = new EventController();
 	eventController_->onEventQueueLengthChange.connect(boost::bind(&MainController::handleEventQueueLengthChange, this, _1));
 
@@ -158,10 +160,10 @@ MainController::MainController(
 
 	xmlConsoleController_ = new XMLConsoleController(uiEventStream_, xmlConsoleWidgetFactory);
 
-	bool enabled = settings_->getBoolSetting("showNotifications", true);
-	notifier_->setEnabled(enabled);
-	uiEventStream_->send(boost::shared_ptr<ToggleNotificationsUIEvent>(new ToggleNotificationsUIEvent(enabled)));
 	uiEventStream_->onUIEvent.connect(boost::bind(&MainController::handleUIEvent, this, _1));
+	bool enabled = settings_->getBoolSetting(SHOW_NOTIFICATIONS, true);
+	uiEventStream_->send(boost::shared_ptr<ToggleNotificationsUIEvent>(new ToggleNotificationsUIEvent(enabled)));
+	
 
 	if (loginAutomatically) {
 		profileSettings_ = new ProfileSettingsProvider(selectedLoginJID, settings_);
@@ -179,6 +181,7 @@ MainController::~MainController() {
 	delete uiEventStream_;
 	resetClient();
 	delete eventController_;
+	delete notifier_;
 	for(VCardStorageMap::iterator i = vcardStorages_.begin(); i != vcardStorages_.end(); ++i) {
 		delete i->second;
 	}
@@ -230,10 +233,8 @@ void MainController::handleUIEvent(boost::shared_ptr<UIEvent> event) {
 	boost::shared_ptr<ToggleNotificationsUIEvent> notificationsEvent = boost::dynamic_pointer_cast<ToggleNotificationsUIEvent>(event);
 	if (notificationsEvent) {
 		bool enabled = notificationsEvent->getEnabled();
-		if (enabled != notifier_->getEnabled()) {
-			notifier_->setEnabled(enabled);
-			settings_->storeBool("showNotifications", enabled);
-		}
+		notifier_->setPersistentEnabled(enabled);
+		settings_->storeBool(SHOW_NOTIFICATIONS, enabled);
 	}
 }
 
@@ -339,7 +340,7 @@ void MainController::sendPresence(boost::shared_ptr<Presence> presence) {
 	rosterController_->getWindow()->setMyStatusType(presence->getShow());
 	rosterController_->getWindow()->setMyStatusText(presence->getStatus());
 	systemTrayController_->setMyStatusType(presence->getShow());
-	notifier_->setEnabled(presence->getShow() != StatusShow::DND);
+	notifier_->setTemporarilyDisabled(presence->getShow() == StatusShow::DND);
 
 	// Add information and send
 	if (!vCardPhotoHash_.isEmpty()) {
diff --git a/Swift/Controllers/MainController.h b/Swift/Controllers/MainController.h
index e7b4bfd..2f01fd2 100644
--- a/Swift/Controllers/MainController.h
+++ b/Swift/Controllers/MainController.h
@@ -53,6 +53,7 @@ namespace Swift {
 	class LoginWindowFactory;
 	class MUCController;
 	class Notifier;
+	class TogglableNotifier;
 	class PresenceNotifier;
 	class EventNotifier;
 	class SystemTray;
@@ -137,7 +138,7 @@ namespace Swift {
 			VCardStorageFactory* vcardStorageFactory_;
 			VCardManager* vcardManager_;
 			Dock* dock_;
-			Notifier* notifier_;
+			TogglableNotifier* notifier_;
 			PresenceNotifier* presenceNotifier_;
 			EventNotifier* eventNotifier_;
 			RosterController* rosterController_;
-- 
cgit v0.10.2-6-g49f6