From 3605b6622bc8b4abb810fac6b53f7f71be0fa7de Mon Sep 17 00:00:00 2001
From: Kevin Smith <git@kismith.co.uk>
Date: Fri, 17 Feb 2012 16:57:01 +0000
Subject: Introduce system settings policies.

Release-Notes: It is now possible for sysadmins to deploy files with policies for configuration options, such as making it impossible for users to save passwords or to force sound notifications off, or to set defaults.

Also allow changing an option so that Swift disconnects on idle timeout, instead of going away.

diff --git a/Swift/Controllers/Chat/ChatController.cpp b/Swift/Controllers/Chat/ChatController.cpp
index 9a56300..ea0e8ea 100644
--- a/Swift/Controllers/Chat/ChatController.cpp
+++ b/Swift/Controllers/Chat/ChatController.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Kevin Smith
+ * Copyright (c) 2010-2012 Kevin Smith
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
@@ -27,7 +27,7 @@
 #include <Swift/Controllers/UIEvents/SendFileUIEvent.h>
 #include <Swiften/Elements/DeliveryReceipt.h>
 #include <Swiften/Elements/DeliveryReceiptRequest.h>
-#include <Swift/Controllers/UIEvents/ToggleRequestDeliveryReceiptsUIEvent.h>
+#include <Swift/Controllers/SettingConstants.h>
 
 #include <Swiften/Base/Log.h>
 
@@ -36,8 +36,8 @@ namespace Swift {
 /**
  * The controller does not gain ownership of the stanzaChannel, nor the factory.
  */
-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)
-	: ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, contact, presenceOracle, avatarManager, useDelayForLatency, eventStream, eventController, timerFactory, entityCapsProvider), eventStream_(eventStream), userWantsReceipts_(userWantsReceipts) {
+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)
+	: ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, contact, presenceOracle, avatarManager, useDelayForLatency, eventStream, eventController, timerFactory, entityCapsProvider), eventStream_(eventStream), userWantsReceipts_(userWantsReceipts), settings_(settings) {
 	isInMUC_ = isInMUC;
 	lastWasPresence_ = false;
 	chatStateNotifier_ = new ChatStateNotifier(stanzaChannel, contact, entityCapsProvider);
@@ -73,7 +73,8 @@ ChatController::ChatController(const JID& self, StanzaChannel* stanzaChannel, IQ
 	chatWindow_->onFileTransferCancel.connect(boost::bind(&ChatController::handleFileTransferCancel, this, _1));
 	chatWindow_->onSendFileRequest.connect(boost::bind(&ChatController::handleSendFileRequest, this, _1));
 	handleBareJIDCapsChanged(toJID_);
-	eventStream_->onUIEvent.connect(boost::bind(&ChatController::handleUIEvent, this, _1));
+
+	settings_->onSettingChanged.connect(boost::bind(&ChatController::handleSettingChanged, this, _1));
 }
 
 void ChatController::handleContactNickChanged(const JID& jid, const std::string& /*oldNick*/) {
@@ -83,7 +84,7 @@ void ChatController::handleContactNickChanged(const JID& jid, const std::string&
 }
 
 ChatController::~ChatController() {
-	eventStream_->onUIEvent.disconnect(boost::bind(&ChatController::handleUIEvent, this, _1));
+	settings_->onSettingChanged.disconnect(boost::bind(&ChatController::handleSettingChanged, this, _1));
 	nickResolver_->onNickChanged.disconnect(boost::bind(&ChatController::handleContactNickChanged, this, _1, _2));
 	delete chatStateNotifier_;
 	delete chatStateTracker_;
@@ -174,9 +175,9 @@ void ChatController::setContactIsReceivingPresence(bool isReceivingPresence) {
 	receivingPresenceFromUs_ = isReceivingPresence;
 }
 
-void ChatController::handleUIEvent(boost::shared_ptr<UIEvent> event) {
-	if (boost::shared_ptr<ToggleRequestDeliveryReceiptsUIEvent> toggleAllowReceipts = boost::dynamic_pointer_cast<ToggleRequestDeliveryReceiptsUIEvent>(event)) {
-		userWantsReceipts_ = toggleAllowReceipts->getEnabled();
+void ChatController::handleSettingChanged(const std::string& settingPath) {
+	if (settingPath == SettingConstants::REQUEST_DELIVERYRECEIPTS.getKey()) {
+		userWantsReceipts_ = settings_->getSetting(SettingConstants::REQUEST_DELIVERYRECEIPTS);
 		checkForDisplayingDisplayReceiptsAlert();
 	}
 }
diff --git a/Swift/Controllers/Chat/ChatController.h b/Swift/Controllers/Chat/ChatController.h
index 9c01923..2a66772 100644
--- a/Swift/Controllers/Chat/ChatController.h
+++ b/Swift/Controllers/Chat/ChatController.h
@@ -1,12 +1,12 @@
 /*
- * Copyright (c) 2010 Kevin Smith
+ * Copyright (c) 2010-2012 Kevin Smith
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
 
 #pragma once
 
-#include "Swift/Controllers/Chat/ChatControllerBase.h"
+#include <Swift/Controllers/Chat/ChatControllerBase.h>
 
 #include <map>
 #include <string>
@@ -20,11 +20,11 @@ namespace Swift {
 	class NickResolver;
 	class EntityCapsProvider;
 	class FileTransferController;
-	class UIEvent;
+	class SettingsProvider;
 
 	class ChatController : public ChatControllerBase {
 		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);
+			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);
 			virtual ~ChatController();
 			virtual void setToJID(const JID& jid);
 			virtual void setOnline(bool online);
@@ -51,7 +51,7 @@ namespace Swift {
 			void handleFileTransferAccept(std::string /* id */, std::string /* filename */);
 			void handleSendFileRequest(std::string filename);
 
-			void handleUIEvent(boost::shared_ptr<UIEvent> event);
+			void handleSettingChanged(const std::string& settingPath);
 			void checkForDisplayingDisplayReceiptsAlert();
 
 		private:
@@ -71,6 +71,7 @@ namespace Swift {
 			bool receivingPresenceFromUs_;
 			bool userWantsReceipts_;
 			std::map<std::string, FileTransferController*> ftControllers;
+			SettingsProvider* settings_;
 	};
 }
 
diff --git a/Swift/Controllers/Chat/ChatsManager.cpp b/Swift/Controllers/Chat/ChatsManager.cpp
index c19c524..a2b286f 100644
--- a/Swift/Controllers/Chat/ChatsManager.cpp
+++ b/Swift/Controllers/Chat/ChatsManager.cpp
@@ -21,7 +21,6 @@
 #include <Swift/Controllers/UIEvents/AddMUCBookmarkUIEvent.h>
 #include <Swift/Controllers/UIEvents/RemoveMUCBookmarkUIEvent.h>
 #include <Swift/Controllers/UIEvents/EditMUCBookmarkUIEvent.h>
-#include <Swift/Controllers/UIEvents/ToggleRequestDeliveryReceiptsUIEvent.h>
 #include <Swift/Controllers/UIInterfaces/ChatListWindowFactory.h>
 #include <Swift/Controllers/UIInterfaces/JoinMUCWindow.h>
 #include <Swift/Controllers/UIInterfaces/JoinMUCWindowFactory.h>
@@ -39,6 +38,8 @@
 #include <Swiften/Avatars/AvatarManager.h>
 #include <Swiften/Elements/MUCInvitationPayload.h>
 #include <Swiften/Roster/XMPPRoster.h>
+#include <Swift/Controllers/Settings/SettingsProvider.h>
+#include <Swift/Controllers/SettingConstants.h>
 
 namespace Swift {
 
@@ -64,10 +65,11 @@ ChatsManager::ChatsManager(
 		EntityCapsProvider* entityCapsProvider, 
 		MUCManager* mucManager,
 		MUCSearchWindowFactory* mucSearchWindowFactory,
-		ProfileSettingsProvider* settings,
+		ProfileSettingsProvider* profileSettings,
 		FileTransferOverview* ftOverview,
 		XMPPRoster* roster,
-		bool eagleMode) :
+		bool eagleMode,
+		SettingsProvider* settings) :
 			jid_(jid), 
 			joinMUCWindowFactory_(joinMUCWindowFactory), 
 			useDelayForLatency_(useDelayForLatency), 
@@ -76,7 +78,8 @@ ChatsManager::ChatsManager(
 			mucManager(mucManager),
 			ftOverview_(ftOverview),
 			roster_(roster),
-			eagleMode_(eagleMode) {
+			eagleMode_(eagleMode),
+			settings_(settings) {
 	timerFactory_ = timerFactory;
 	eventController_ = eventController;
 	stanzaChannel_ = stanzaChannel;
@@ -89,7 +92,7 @@ ChatsManager::ChatsManager(
 	presenceSender_ = presenceSender;
 	uiEventStream_ = uiEventStream;
 	mucBookmarkManager_ = NULL;
-	profileSettings_ = settings;
+	profileSettings_ = profileSettings;
 	presenceOracle_->onPresenceChange.connect(boost::bind(&ChatsManager::handlePresenceChange, this, _1));
 	uiEventConnection_ = uiEventStream_->onUIEvent.connect(boost::bind(&ChatsManager::handleUIEvent, this, _1));
 
@@ -99,18 +102,22 @@ ChatsManager::ChatsManager(
 	chatListWindow_->onClearRecentsRequested.connect(boost::bind(&ChatsManager::handleClearRecentsRequested, this));
 
 	joinMUCWindow_ = NULL;
-	mucSearchController_ = new MUCSearchController(jid_, mucSearchWindowFactory, iqRouter, settings);
+	mucSearchController_ = new MUCSearchController(jid_, mucSearchWindowFactory, iqRouter, profileSettings_);
 	mucSearchController_->onMUCSelected.connect(boost::bind(&ChatsManager::handleMUCSelectedAfterSearch, this, _1));
 	ftOverview_->onNewFileTransferController.connect(boost::bind(&ChatsManager::handleNewFileTransferController, this, _1));
 	roster_->onJIDAdded.connect(boost::bind(&ChatsManager::handleJIDAddedToRoster, this, _1));
 	roster_->onJIDRemoved.connect(boost::bind(&ChatsManager::handleJIDRemovedFromRoster, this, _1));
 	roster_->onJIDUpdated.connect(boost::bind(&ChatsManager::handleJIDUpdatedInRoster, this, _1));
 	roster_->onRosterCleared.connect(boost::bind(&ChatsManager::handleRosterCleared, this));
+
+	settings_->onSettingChanged.connect(boost::bind(&ChatsManager::handleSettingChanged, this, _1));
+
 	setupBookmarks();
 	loadRecents();
 }
 
 ChatsManager::~ChatsManager() {
+	settings_->onSettingChanged.disconnect(boost::bind(&ChatsManager::handleSettingChanged, this, _1));
 	roster_->onJIDAdded.disconnect(boost::bind(&ChatsManager::handleJIDAddedToRoster, this, _1));
 	roster_->onJIDRemoved.disconnect(boost::bind(&ChatsManager::handleJIDRemovedFromRoster, this, _1));
 	roster_->onJIDUpdated.disconnect(boost::bind(&ChatsManager::handleJIDUpdatedInRoster, this, _1));
@@ -348,6 +355,13 @@ void ChatsManager::handleUserLeftMUC(MUCController* mucController) {
 	}
 }
 
+void ChatsManager::handleSettingChanged(const std::string& settingPath) {
+	if (settingPath == SettingConstants::REQUEST_DELIVERYRECEIPTS.getKey()) {
+		userWantsReceipts_ = settings_->getSetting(SettingConstants::REQUEST_DELIVERYRECEIPTS);
+		return;
+	}
+}
+
 void ChatsManager::handleUIEvent(boost::shared_ptr<UIEvent> event) {
 	boost::shared_ptr<RequestChatUIEvent> chatEvent = boost::dynamic_pointer_cast<RequestChatUIEvent>(event);
 	if (chatEvent) {
@@ -364,11 +378,7 @@ void ChatsManager::handleUIEvent(boost::shared_ptr<UIEvent> event) {
 		mucBookmarkManager_->addBookmark(addMUCBookmarkEvent->getBookmark());
 		return;
 	}
-	boost::shared_ptr<ToggleRequestDeliveryReceiptsUIEvent> toggleRequestDeliveryReceiptsEvent = boost::dynamic_pointer_cast<ToggleRequestDeliveryReceiptsUIEvent>(event);
-	if (toggleRequestDeliveryReceiptsEvent) {
-		userWantsReceipts_ = toggleRequestDeliveryReceiptsEvent->getEnabled();
-		return;
-	}
+
 
 	boost::shared_ptr<EditMUCBookmarkUIEvent> editMUCBookmarkEvent = boost::dynamic_pointer_cast<EditMUCBookmarkUIEvent>(event);
 	if (editMUCBookmarkEvent) {
@@ -489,7 +499,7 @@ ChatController* ChatsManager::getChatControllerOrFindAnother(const JID &contact)
 
 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_);
+	ChatController* controller = new ChatController(jid_, stanzaChannel_, iqRouter_, chatWindowFactory_, contact, nickResolver_, presenceOracle_, avatarManager_, mucRegistry_->isMUC(contact.toBare()), useDelayForLatency_, uiEventStream_, eventController_, timerFactory_, entityCapsProvider_, userWantsReceipts_, settings_);
 	chatControllers_[contact] = controller;
 	controller->setAvailableServerFeatures(serverDiscoInfo_);
 	controller->onActivity.connect(boost::bind(&ChatsManager::handleChatActivity, this, contact, _1, false));
diff --git a/Swift/Controllers/Chat/ChatsManager.h b/Swift/Controllers/Chat/ChatsManager.h
index 0c7f492..4d1fc14 100644
--- a/Swift/Controllers/Chat/ChatsManager.h
+++ b/Swift/Controllers/Chat/ChatsManager.h
@@ -46,10 +46,11 @@ namespace Swift {
 	class FileTransferOverview;
 	class FileTransferController;
 	class XMPPRoster;
+	class SettingsProvider;
 	
 	class ChatsManager {
 		public:
-			ChatsManager(JID jid, StanzaChannel* stanzaChannel, IQRouter* iqRouter, EventController* eventController, ChatWindowFactory* chatWindowFactory, JoinMUCWindowFactory* joinMUCWindowFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, PresenceSender* presenceSender, UIEventStream* uiEventStream, ChatListWindowFactory* chatListWindowFactory, bool useDelayForLatency, TimerFactory* timerFactory, MUCRegistry* mucRegistry, EntityCapsProvider* entityCapsProvider, MUCManager* mucManager, MUCSearchWindowFactory* mucSearchWindowFactory, ProfileSettingsProvider* settings, FileTransferOverview* ftOverview, XMPPRoster* roster, bool eagleMode);
+			ChatsManager(JID jid, StanzaChannel* stanzaChannel, IQRouter* iqRouter, EventController* eventController, ChatWindowFactory* chatWindowFactory, JoinMUCWindowFactory* joinMUCWindowFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, PresenceSender* presenceSender, UIEventStream* uiEventStream, ChatListWindowFactory* chatListWindowFactory, bool useDelayForLatency, TimerFactory* timerFactory, MUCRegistry* mucRegistry, EntityCapsProvider* entityCapsProvider, MUCManager* mucManager, MUCSearchWindowFactory* mucSearchWindowFactory, ProfileSettingsProvider* settings, FileTransferOverview* ftOverview, XMPPRoster* roster, bool eagleMode, SettingsProvider* settings);
 			virtual ~ChatsManager();
 			void setAvatarManager(AvatarManager* avatarManager);
 			void setOnline(bool enabled);
@@ -86,6 +87,7 @@ namespace Swift {
 			void handleJIDRemovedFromRoster(const JID&);
 			void handleJIDUpdatedInRoster(const JID&);
 			void handleRosterCleared();
+			void handleSettingChanged(const std::string& settingPath);
 
 			void updatePresenceReceivingStateOnChatController(const JID&);
 
@@ -125,5 +127,6 @@ namespace Swift {
 			XMPPRoster* roster_;
 			bool eagleMode_;
 			bool userWantsReceipts_;
+			SettingsProvider* settings_;
 	};
 }
diff --git a/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp b/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp
index 8162bec..cd868e6 100644
--- a/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp
+++ b/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2011 Kevin Smith
+ * Copyright (c) 2010-2012 Kevin Smith
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
@@ -43,12 +43,12 @@
 #include "Swift/Controllers/UIEvents/RequestChatUIEvent.h"
 #include "Swift/Controllers/UIEvents/JoinMUCUIEvent.h"
 #include "Swift/Controllers/UIEvents/UIEventStream.h"
-#include "Swift/Controllers/UIEvents/ToggleRequestDeliveryReceiptsUIEvent.h"
 #include <Swift/Controllers/ProfileSettingsProvider.h>
 #include "Swift/Controllers/FileTransfer/FileTransferOverview.h"
 #include "Swiften/Elements/DeliveryReceiptRequest.h"
 #include "Swiften/Elements/DeliveryReceipt.h"
 #include <Swiften/Base/Algorithm.h>
+#include <Swift/Controllers/SettingConstants.h>
 
 using namespace Swift;
 
@@ -102,7 +102,7 @@ public:
 		ftOverview_ = new FileTransferOverview(ftManager_);
 
 		mocks_->ExpectCall(chatListWindowFactory_, ChatListWindowFactory::createChatListWindow).With(uiEventStream_).Return(chatListWindow_);
-		manager_ = new ChatsManager(jid_, stanzaChannel_, iqRouter_, eventController_, chatWindowFactory_, joinMUCWindowFactory_, nickResolver_, presenceOracle_, directedPresenceSender_, uiEventStream_, chatListWindowFactory_, true, NULL, mucRegistry_, entityCapsManager_, mucManager_, mucSearchWindowFactory_, profileSettings_, ftOverview_, xmppRoster_, false);
+		manager_ = new ChatsManager(jid_, stanzaChannel_, iqRouter_, eventController_, chatWindowFactory_, joinMUCWindowFactory_, nickResolver_, presenceOracle_, directedPresenceSender_, uiEventStream_, chatListWindowFactory_, true, NULL, mucRegistry_, entityCapsManager_, mucManager_, mucSearchWindowFactory_, profileSettings_, ftOverview_, xmppRoster_, false, settings_);
 
 		avatarManager_ = new NullAvatarManager();
 		manager_->setAvatarManager(avatarManager_);
@@ -110,7 +110,6 @@ public:
 	
 	void tearDown() {
 		//delete chatListWindowFactory
-		delete settings_;
 		delete profileSettings_;
 		delete avatarManager_;
 		delete manager_;
@@ -132,6 +131,7 @@ public:
 		delete capsProvider_;
 		delete chatListWindow_;
 		delete mocks_;
+		delete settings_;
 	}
 
 	void testFirstOpenWindowIncoming() {
@@ -353,7 +353,7 @@ public:
 
 		MockChatWindow* window = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>();
 		mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID, uiEventStream_).Return(window);
-		uiEventStream_->send(boost::shared_ptr<UIEvent>(new ToggleRequestDeliveryReceiptsUIEvent(true)));
+		settings_->storeSetting(SettingConstants::REQUEST_DELIVERYRECEIPTS, true);
 
 		boost::shared_ptr<Message> message = makeDeliveryReceiptTestMessage(messageJID, "1");
 		manager_->handleIncomingMessage(message);
@@ -376,7 +376,7 @@ public:
 
 		MockChatWindow* window = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>();
 		mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID, uiEventStream_).Return(window);
-		uiEventStream_->send(boost::shared_ptr<UIEvent>(new ToggleRequestDeliveryReceiptsUIEvent(true)));
+		settings_->storeSetting(SettingConstants::REQUEST_DELIVERYRECEIPTS, true);
 
 		boost::shared_ptr<Message> message = makeDeliveryReceiptTestMessage(messageJID, "1");
 		manager_->handleIncomingMessage(message);
@@ -412,7 +412,7 @@ public:
 
 		MockChatWindow* window = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>();
 		mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID, uiEventStream_).Return(window);
-		uiEventStream_->send(boost::shared_ptr<UIEvent>(new ToggleRequestDeliveryReceiptsUIEvent(true)));
+		settings_->storeSetting(SettingConstants::REQUEST_DELIVERYRECEIPTS, true);
 
 		boost::shared_ptr<Message> message = makeDeliveryReceiptTestMessage(messageJID, "1");
 		manager_->handleIncomingMessage(message);
diff --git a/Swift/Controllers/MainController.cpp b/Swift/Controllers/MainController.cpp
index 6f93dd3..06f8c3a 100644
--- a/Swift/Controllers/MainController.cpp
+++ b/Swift/Controllers/MainController.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2011 Kevin Smith
+ * Copyright (c) 2010-2012 Kevin Smith
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
@@ -59,8 +59,6 @@
 #include "Swiften/StringCodecs/SHA1.h"
 #include "Swiften/StringCodecs/Hexify.h"
 #include "Swift/Controllers/UIEvents/RequestChatUIEvent.h"
-#include "Swift/Controllers/UIEvents/ToggleNotificationsUIEvent.h"
-#include "Swift/Controllers/UIEvents/ToggleRequestDeliveryReceiptsUIEvent.h"
 #include "Swift/Controllers/UIEvents/JoinMUCUIEvent.h"
 #include "Swift/Controllers/Storages/CertificateStorageFactory.h"
 #include "Swift/Controllers/Storages/CertificateStorageTrustChecker.h"
@@ -73,20 +71,19 @@
 #include <Swift/Controllers/FileTransfer/FileTransferOverview.h>
 #include <Swiften/FileTransfer/FileTransferManager.h>
 #include <Swiften/Client/ClientXMLTracer.h>
+#include <Swift/Controllers/SettingConstants.h>
 
 namespace Swift {
 
 static const std::string CLIENT_NAME = "Swift";
 static const std::string CLIENT_NODE = "http://swift.im";
 
-static const std::string SHOW_NOTIFICATIONS = "showNotifications";
-static const std::string REQUEST_DELIVERYRECEIPTS = "requestDeliveryReceipts";
 
 MainController::MainController(
 		EventLoop* eventLoop,
 		NetworkFactories* networkFactories,
 		UIFactory* uiFactories,
-		SettingsProvider *settings,
+		SettingsProvider* settings,
 		SystemTray* systemTray,
 		SoundPlayer* soundPlayer,
 		StoragesFactory* storagesFactory,
@@ -95,8 +92,7 @@ MainController::MainController(
 		Notifier* notifier,
 		URIHandler* uriHandler,
 		IdleDetector* idleDetector,
-		bool useDelayForLatency,
-		bool eagleMode) :
+		bool useDelayForLatency) :
 			eventLoop_(eventLoop),
 			networkFactories_(networkFactories),
 			uiFactory_(uiFactories),
@@ -107,7 +103,6 @@ MainController::MainController(
 			idleDetector_(idleDetector),
 			loginWindow_(NULL) ,
 			useDelayForLatency_(useDelayForLatency),
-			eagleMode_(eagleMode),
 			ftOverview_(NULL) {
 	storages_ = NULL;
 	certificateStorage_ = NULL;
@@ -137,18 +132,19 @@ MainController::MainController(
 	systemTrayController_ = new SystemTrayController(eventController_, systemTray);
 	loginWindow_ = uiFactory_->createLoginWindow(uiEventStream_);
 	loginWindow_->setShowNotificationToggle(!notifier->isExternallyConfigured());
-	soundEventController_ = new SoundEventController(eventController_, soundPlayer, settings, uiEventStream_);
+	soundEventController_ = new SoundEventController(eventController_, soundPlayer, settings);
 
 	xmppURIController_ = new XMPPURIController(uriHandler_, uiEventStream_);
 
-	std::string selectedLoginJID = settings_->getStringSetting("lastLoginJID");
-	bool loginAutomatically = settings_->getBoolSetting("loginAutomatically", false);
+	std::string selectedLoginJID = settings_->getSetting(SettingConstants::LAST_LOGIN_JID);
+	bool loginAutomatically = settings_->getSetting(SettingConstants::LOGIN_AUTOMATICALLY);
 	std::string cachedPassword;
 	std::string cachedCertificate;
-	if (!eagleMode_) {
+	bool eagle = settings_->getSetting(SettingConstants::FORGET_PASSWORDS);
+	if (!eagle) {
 		foreach (std::string profile, settings->getAvailableProfiles()) {
 			ProfileSettingsProvider profileSettings(profile, settings);
-			std::string password = eagleMode ? "" : profileSettings.getStringSetting("pass");
+			std::string password = profileSettings.getStringSetting("pass");
 			std::string certificate = profileSettings.getStringSetting("certificate");
 			std::string jid = profileSettings.getStringSetting("jid");
 			loginWindow_->addAvailableAccount(jid, password, certificate);
@@ -167,16 +163,14 @@ MainController::MainController(
 	loginWindow_->onCancelLoginRequest.connect(boost::bind(&MainController::handleCancelLoginRequest, this));
 	loginWindow_->onQuitRequest.connect(boost::bind(&MainController::handleQuitRequest, this));
 
-	idleDetector_->setIdleTimeSeconds(600);
+	idleDetector_->setIdleTimeSeconds(settings->getSetting(SettingConstants::IDLE_TIMEOUT));
 	idleDetector_->onIdleChanged.connect(boost::bind(&MainController::handleInputIdleChanged, this, _1));
 
 	xmlConsoleController_ = new XMLConsoleController(uiEventStream_, uiFactory_);
 
 	fileTransferListController_ = new FileTransferListController(uiEventStream_, uiFactory_);
 
-	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)));
+	settings_->onSettingChanged.connect(boost::bind(&MainController::handleSettingChanged, this, _1));
 
 	if (loginAutomatically) {
 		profileSettings_ = new ProfileSettingsProvider(selectedLoginJID, settings_);
@@ -246,18 +240,10 @@ void MainController::resetClient() {
 	clientInitialized_ = false;
 }
 
-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();
-		notifier_->setPersistentEnabled(enabled);
-		settings_->storeBool(SHOW_NOTIFICATIONS, enabled);
+void MainController::handleSettingChanged(const std::string& settingPath) {
+	if (settingPath == SettingConstants::SHOW_NOTIFICATIONS.getKey()) {
+		notifier_->setPersistentEnabled(settings_->getSetting(SettingConstants::SHOW_NOTIFICATIONS));
 	}
-	boost::shared_ptr<ToggleRequestDeliveryReceiptsUIEvent> deliveryReceiptEvent = boost::dynamic_pointer_cast<ToggleRequestDeliveryReceiptsUIEvent>(event);
-	if (deliveryReceiptEvent) {
-		settings_->storeBool(REQUEST_DELIVERYRECEIPTS, deliveryReceiptEvent->getEnabled());
-	}
-
 }
 
 void MainController::resetPendingReconnects() {
@@ -281,7 +267,7 @@ void MainController::handleConnected() {
 	resetCurrentError();
 	resetPendingReconnects();
 
-	if (eagleMode_) {
+	if (settings_->getSetting(SettingConstants::FORGET_PASSWORDS)) {
 		purgeCachedCredentials();
 	}
 
@@ -300,7 +286,7 @@ void MainController::handleConnected() {
 
 		contactEditController_ = new ContactEditController(rosterController_, uiFactory_, uiEventStream_);
 
-		chatsManager_ = new ChatsManager(jid_, client_->getStanzaChannel(), client_->getIQRouter(), eventController_, uiFactory_, uiFactory_, client_->getNickResolver(), client_->getPresenceOracle(), client_->getPresenceSender(), uiEventStream_, uiFactory_, useDelayForLatency_, networkFactories_->getTimerFactory(), client_->getMUCRegistry(), client_->getEntityCapsProvider(), client_->getMUCManager(), uiFactory_, profileSettings_, ftOverview_, client_->getRoster(), eagleMode_);
+		chatsManager_ = new ChatsManager(jid_, client_->getStanzaChannel(), client_->getIQRouter(), eventController_, uiFactory_, uiFactory_, client_->getNickResolver(), client_->getPresenceOracle(), client_->getPresenceSender(), uiEventStream_, uiFactory_, useDelayForLatency_, networkFactories_->getTimerFactory(), client_->getMUCRegistry(), client_->getEntityCapsProvider(), client_->getMUCManager(), uiFactory_, profileSettings_, ftOverview_, client_->getRoster(), !settings_->getSetting(SettingConstants::REMEMBER_RECENT_CHATS), settings_);
 		
 		client_->onMessageReceived.connect(boost::bind(&ChatsManager::handleIncomingMessage, chatsManager_, _1));
 		chatsManager_->setAvatarManager(client_->getAvatarManager());
@@ -346,8 +332,6 @@ void MainController::handleConnected() {
 	/* Enable chats last of all, so rejoining MUCs has the right sent presence */
 	chatsManager_->setOnline(true);
 
-	// notify world about current delivey receipt request setting state.
-	uiEventStream_->send(boost::make_shared<ToggleRequestDeliveryReceiptsUIEvent>(settings_->getBoolSetting(REQUEST_DELIVERYRECEIPTS, false)));
 }
 
 void MainController::handleEventQueueLengthChange(int count) {
@@ -408,16 +392,24 @@ void MainController::handleInputIdleChanged(bool idle) {
 		//Haven't logged in yet.
 		return;
 	}
-	if (idle) {
-		if (statusTracker_->goAutoAway()) {
-			if (client_ && client_->isAvailable()) {
-				sendPresence(statusTracker_->getNextPresence());
-			}
+
+	if (settings_->getSetting(SettingConstants::IDLE_GOES_OFFLINE)) {
+		if (idle) {
+			logout();
 		}
-	} else {
-		if (statusTracker_->goAutoUnAway()) {
-			if (client_ && client_->isAvailable()) {
-				sendPresence(statusTracker_->getNextPresence());
+	}
+	else {
+		if (idle) {
+			if (statusTracker_->goAutoAway()) {
+				if (client_ && client_->isAvailable()) {
+					sendPresence(statusTracker_->getNextPresence());
+				}
+			}
+		} else {
+			if (statusTracker_->goAutoUnAway()) {
+				if (client_ && client_->isAvailable()) {
+					sendPresence(statusTracker_->getNextPresence());
+				}
 			}
 		}
 	}
@@ -432,12 +424,12 @@ void MainController::handleLoginRequest(const std::string &username, const std::
 		loginWindow_->setMessage("");
 		loginWindow_->setIsLoggingIn(true);
 		profileSettings_ = new ProfileSettingsProvider(username, settings_);
-		if (!eagleMode_) {
+		if (!settings_->getSetting(SettingConstants::FORGET_PASSWORDS)) {
 			profileSettings_->storeString("jid", username);
 			profileSettings_->storeString("certificate", certificateFile);
 			profileSettings_->storeString("pass", (remember || loginAutomatically) ? password : "");
-			settings_->storeString("lastLoginJID", username);
-			settings_->storeBool("loginAutomatically", loginAutomatically);
+			settings_->storeSetting(SettingConstants::LAST_LOGIN_JID, username);
+			settings_->storeSetting(SettingConstants::LOGIN_AUTOMATICALLY, loginAutomatically);
 			loginWindow_->addAvailableAccount(profileSettings_->getStringSetting("jid"), profileSettings_->getStringSetting("pass"), profileSettings_->getStringSetting("certificate"));
 		}
 
@@ -453,7 +445,7 @@ void MainController::handlePurgeSavedLoginRequest(const std::string& username) {
 }
 
 void MainController::performLoginFromCachedCredentials() {
-	if (eagleMode_ && password_.empty()) {
+	if (settings_->getSetting(SettingConstants::FORGET_PASSWORDS) && password_.empty()) {
 		/* Then we can't try to login again. */
 		return;
 	}
@@ -503,8 +495,9 @@ void MainController::performLoginFromCachedCredentials() {
 		rosterController_->getWindow()->setConnecting();
 	}
 	ClientOptions clientOptions;
-	clientOptions.forgetPassword = eagleMode_;
-	clientOptions.useTLS = eagleMode_ ? ClientOptions::RequireTLS : ClientOptions::UseTLSWhenAvailable;
+	bool eagle = settings_->getSetting(SettingConstants::FORGET_PASSWORDS);
+	clientOptions.forgetPassword = eagle;
+	clientOptions.useTLS = eagle ? ClientOptions::RequireTLS : ClientOptions::UseTLSWhenAvailable;
 	/*if (clientJID.getDomain() == "doomsong.co.uk") {
 		clientOptions.boshURL = URL("https", "channels.doomsong.co.uk", 11443, "http-bind/");
 		clientOptions.boshHTTPConnectProxyURL = URL("http", "squidproxy.doomsong.co.uk", 8123, "");
@@ -513,7 +506,7 @@ void MainController::performLoginFromCachedCredentials() {
 }
 
 void MainController::handleDisconnected(const boost::optional<ClientError>& error) {
-	if (eagleMode_) {
+	if (settings_->getSetting(SettingConstants::FORGET_PASSWORDS)) {
 		purgeCachedCredentials();
 	}
 	if (quitRequested_) {
@@ -575,7 +568,7 @@ void MainController::handleDisconnected(const boost::optional<ClientError>& erro
 			loginWindow_->setIsLoggingIn(false);
 		} else {
 			logout();
-			if (eagleMode_) {
+			if (settings_->getSetting(SettingConstants::FORGET_PASSWORDS)) {
 				message = str(format(QT_TRANSLATE_NOOP("", "Disconnected from %1%: %2%. To reconnect, Sign Out and provide your password again.")) % jid_.getDomain() % message);
 			} else {
 				if (!offlineRequested_) {
@@ -616,7 +609,7 @@ void MainController::handleCancelLoginRequest() {
 }
 
 void MainController::signOut() {
-	if (eagleMode_) {
+	if (settings_->getSetting(SettingConstants::FORGET_PASSWORDS)) {
 		purgeCachedCredentials();
 	}
 	eventController_->clear();
@@ -626,7 +619,7 @@ void MainController::signOut() {
 }
 
 void MainController::logout() {
-	if (eagleMode_) {
+	if (settings_->getSetting(SettingConstants::FORGET_PASSWORDS)) {
 		purgeCachedCredentials();
 	}
 	systemTrayController_->setMyStatusType(StatusShow::None);
diff --git a/Swift/Controllers/MainController.h b/Swift/Controllers/MainController.h
index 013f8bb..45e4ccf 100644
--- a/Swift/Controllers/MainController.h
+++ b/Swift/Controllers/MainController.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2011 Kevin Smith
+ * Copyright (c) 2010-2012 Kevin Smith
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
@@ -84,8 +84,7 @@ namespace Swift {
 					Notifier* notifier,
 					URIHandler* uriHandler,
 					IdleDetector* idleDetector,
-					bool useDelayForLatency,
-					bool eagleMode);
+					bool useDelayForLatency);
 			~MainController();
 
 
@@ -100,7 +99,7 @@ namespace Swift {
 			void handleServerDiscoInfoResponse(boost::shared_ptr<DiscoInfo>, ErrorPayload::ref);
 			void handleEventQueueLengthChange(int count);
 			void handleVCardReceived(const JID& j, VCard::ref vCard);
-			void handleUIEvent(boost::shared_ptr<UIEvent> event);
+			void handleSettingChanged(const std::string& settingPath);
 			void handlePurgeSavedLoginRequest(const std::string& username);
 			void sendPresence(boost::shared_ptr<Presence> presence);
 			void handleInputIdleChanged(bool);
@@ -166,7 +165,6 @@ namespace Swift {
 			bool quitRequested_;
 			bool offlineRequested_;
 			static const int SecondsToWaitBeforeForceQuitting;
-			bool eagleMode_;
 			FileTransferOverview* ftOverview_;
 	};
 }
diff --git a/Swift/Controllers/ProfileSettingsProvider.cpp b/Swift/Controllers/ProfileSettingsProvider.cpp
new file mode 100644
index 0000000..c1b4b13
--- /dev/null
+++ b/Swift/Controllers/ProfileSettingsProvider.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2010-2012 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include "Swift/Controllers/ProfileSettingsProvider.h"
+
+namespace Swift {
+
+ProfileSettingsProvider::ProfileSettingsProvider(const std::string& profile, SettingsProvider* provider) :
+	profile_(profile) {
+	provider_ = provider;
+	bool found = false;
+	foreach (std::string existingProfile, provider->getAvailableProfiles()) {
+		if (existingProfile == profile) {
+			found = true;
+		}
+	}
+	if (!found) {
+		provider_->createProfile(profile);
+	}
+}
+
+ProfileSettingsProvider::~ProfileSettingsProvider() {
+}
+
+std::string ProfileSettingsProvider::getStringSetting(const std::string &settingPath) {
+	//FIXME: Remove shim
+	SettingsProvider::Setting<std::string> setting(profileSettingPath(settingPath), "");
+	return provider_->getSetting(setting);
+}
+
+void ProfileSettingsProvider::storeString(const std::string &settingPath, const std::string &settingValue) {
+	//FIXME: Remove shim
+	if (!getIsSettingFinal(settingPath)) {
+		SettingsProvider::Setting<std::string> setting(profileSettingPath(settingPath), "");
+		provider_->storeSetting(setting, settingValue);
+	}
+}
+
+int ProfileSettingsProvider::getIntSetting(const std::string& settingPath, int defaultValue) {
+	//FIXME: Remove shim
+	SettingsProvider::Setting<int> setting(profileSettingPath(settingPath), defaultValue);
+	return provider_->getSetting(setting);
+}
+void ProfileSettingsProvider::storeInt(const std::string& settingPath, int settingValue) {
+	//FIXME: Remove shim
+	if (!getIsSettingFinal(settingPath)) {
+		SettingsProvider::Setting<int> setting(profileSettingPath(settingPath), 0);
+		provider_->storeSetting(setting, settingValue);
+	}
+}
+
+bool ProfileSettingsProvider::getIsSettingFinal(const std::string& settingPath) {
+	//FIXME: Remove shim
+	SettingsProvider::Setting<int> setting(settingPath, 0);
+	return provider_->getIsSettingFinal(setting);
+}
+
+
+std::string ProfileSettingsProvider::profileSettingPath(const std::string &settingPath) {
+	return profile_ + ":" + settingPath;
+}
+
+
+}
+
diff --git a/Swift/Controllers/ProfileSettingsProvider.h b/Swift/Controllers/ProfileSettingsProvider.h
index 8ba250c..ebc515a 100644
--- a/Swift/Controllers/ProfileSettingsProvider.h
+++ b/Swift/Controllers/ProfileSettingsProvider.h
@@ -1,38 +1,29 @@
 /*
- * Copyright (c) 2010 Kevin Smith
+ * Copyright (c) 2010-2012 Kevin Smith
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
 
 #pragma once
 
-#include "Swift/Controllers/Settings/SettingsProvider.h"
+#include <Swift/Controllers/Settings/SettingsProvider.h>
 #include <Swiften/Base/foreach.h>
 
 namespace Swift {
 
 class ProfileSettingsProvider {
 	public:
-		ProfileSettingsProvider(const std::string& profile, SettingsProvider* provider) : profile_(profile) {
-			provider_ = provider;
-			bool found = false;
-			foreach (std::string existingProfile, provider->getAvailableProfiles()) {
-				if (existingProfile == profile) {
-					found = true;
-				}
-			}
-			if (!found) {
-				provider_->createProfile(profile);
-			}
-		};
-		virtual ~ProfileSettingsProvider() {};
-		virtual std::string getStringSetting(const std::string &settingPath) {return provider_->getStringSetting(profileSettingPath(settingPath));};
-		virtual void storeString(const std::string &settingPath, const std::string &settingValue) {provider_->storeString(profileSettingPath(settingPath), settingValue);};
-		virtual int getIntSetting(const std::string& settingPath, int defaultValue) {return provider_->getIntSetting(settingPath, defaultValue);}
-		virtual void storeInt(const std::string& settingPath, int settingValue) {provider_->storeInt(settingPath, settingValue);}
+		ProfileSettingsProvider(const std::string& profile, SettingsProvider* provider);
+		virtual ~ProfileSettingsProvider();
+		virtual std::string getStringSetting(const std::string &settingPath);
+		virtual void storeString(const std::string &settingPath, const std::string &settingValue);
+		virtual int getIntSetting(const std::string& settingPath, int defaultValue);
+		virtual void storeInt(const std::string& settingPath, int settingValue);
+		/** See @SettingsProvider::getIsSettingFinal for discussion of what this means.*/
+		virtual bool getIsSettingFinal(const std::string& settingPath);
 		
 	private:
-		std::string profileSettingPath(const std::string &settingPath) {return profile_ + ":" + settingPath;};
+		std::string profileSettingPath(const std::string &settingPath);
 		SettingsProvider* provider_; 
 		std::string profile_;
 };
diff --git a/Swift/Controllers/Roster/RosterController.cpp b/Swift/Controllers/Roster/RosterController.cpp
index 66948c1..d3a00dd 100644
--- a/Swift/Controllers/Roster/RosterController.cpp
+++ b/Swift/Controllers/Roster/RosterController.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Kevin Smith
+ * Copyright (c) 2010-2012 Kevin Smith
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
@@ -35,7 +35,6 @@
 #include "Swift/Controllers/UIEvents/RemoveRosterItemUIEvent.h"
 #include "Swift/Controllers/UIEvents/RenameRosterItemUIEvent.h"
 #include "Swift/Controllers/UIEvents/RenameGroupUIEvent.h"
-#include "Swift/Controllers/UIEvents/ToggleShowOfflineUIEvent.h"
 #include "Swift/Controllers/UIEvents/SendFileUIEvent.h"
 #include <Swiften/FileTransfer/FileTransferManager.h>
 #include <Swiften/Client/NickManager.h>
@@ -44,11 +43,10 @@
 #include <Swiften/Elements/DiscoInfo.h>
 #include <Swiften/Disco/EntityCapsManager.h>
 #include <Swiften/Jingle/JingleSessionManager.h>
+#include <Swift/Controllers/SettingConstants.h>
 
 namespace Swift {
 
-static const std::string SHOW_OFFLINE = "showOffline";
-
 /**
  * The controller does not gain ownership of these parameters.
  */
@@ -83,12 +81,12 @@ RosterController::RosterController(const JID& jid, XMPPRoster* xmppRoster, Avata
 	
 	entityCapsManager_->onCapsChanged.connect(boost::bind(&RosterController::handleOnCapsChanged, this, _1));
 
-	if (settings->getBoolSetting(SHOW_OFFLINE, false)) {
-		uiEventStream->onUIEvent(boost::shared_ptr<UIEvent>(new ToggleShowOfflineUIEvent(true)));
-	}
+	settings_->onSettingChanged.connect(boost::bind(&RosterController::handleSettingChanged, this, _1));
+
 }
 
 RosterController::~RosterController() {	
+	settings_->onSettingChanged.disconnect(boost::bind(&RosterController::handleSettingChanged, this, _1));
 	nickManager_->onOwnNickChanged.disconnect(boost::bind(&MainWindow::setMyNick, mainWindow_, _1));
 	
 	delete offlineFilter_;
@@ -109,8 +107,8 @@ void RosterController::setEnabled(bool enabled) {
 }
 
 void RosterController::handleShowOfflineToggled(bool state) {
-	if (state != settings_->getBoolSetting(SHOW_OFFLINE, false)) {
-		settings_->storeBool(SHOW_OFFLINE, state);
+	if (state != settings_->getSetting(SettingConstants::SHOW_OFFLINE)) {
+		settings_->storeSetting(SettingConstants::SHOW_OFFLINE, state);
 	}
 	if (state) {
 		roster_->removeFilter(offlineFilter_);
@@ -181,11 +179,14 @@ void RosterController::handleOnJIDUpdated(const JID& jid, const std::string& old
 	applyAllPresenceTo(jid);
 }
 
-void RosterController::handleUIEvent(boost::shared_ptr<UIEvent> event) {
-	if (boost::shared_ptr<ToggleShowOfflineUIEvent> showOfflineEvent = boost::dynamic_pointer_cast<ToggleShowOfflineUIEvent>(event)) {
-		handleShowOfflineToggled(showOfflineEvent->getShow());
+void RosterController::handleSettingChanged(const std::string& settingPath) {
+	if (settingPath == SettingConstants::SHOW_OFFLINE.getKey()) {
+		handleShowOfflineToggled(settings_->getSetting(SettingConstants::SHOW_OFFLINE));
 	}
-	else if (boost::shared_ptr<AddContactUIEvent> addContactEvent = boost::dynamic_pointer_cast<AddContactUIEvent>(event)) {
+}
+
+void RosterController::handleUIEvent(boost::shared_ptr<UIEvent> event) {
+	if (boost::shared_ptr<AddContactUIEvent> addContactEvent = boost::dynamic_pointer_cast<AddContactUIEvent>(event)) {
 		RosterItemPayload item;
 		item.setName(addContactEvent->getName());
 		item.setJID(addContactEvent->getJID());
diff --git a/Swift/Controllers/Roster/RosterController.h b/Swift/Controllers/Roster/RosterController.h
index 66748ca..5e40124 100644
--- a/Swift/Controllers/Roster/RosterController.h
+++ b/Swift/Controllers/Roster/RosterController.h
@@ -74,6 +74,7 @@ namespace Swift {
 			void applyAllPresenceTo(const JID& jid);
 			void handleEditProfileRequest();
 			void handleOnCapsChanged(const JID& jid);
+			void handleSettingChanged(const std::string& settingPath);
 
 			JID myJID_;
 			XMPPRoster* xmppRoster_;
diff --git a/Swift/Controllers/Roster/RosterGroupExpandinessPersister.cpp b/Swift/Controllers/Roster/RosterGroupExpandinessPersister.cpp
index 0a242ae..81f0c12 100644
--- a/Swift/Controllers/Roster/RosterGroupExpandinessPersister.cpp
+++ b/Swift/Controllers/Roster/RosterGroupExpandinessPersister.cpp
@@ -1,17 +1,18 @@
 /*
- * Copyright (c) 2010 Kevin Smith
+ * Copyright (c) 2010-2012 Kevin Smith
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
 
-#include "RosterGroupExpandinessPersister.h"
+#include <Swift/Controllers/Roster/RosterGroupExpandinessPersister.h>
 
 #include <boost/bind.hpp>
 #include <vector>
 
 #include <Swiften/Base/foreach.h>
-#include "Swiften/Base/String.h"
-#include "Swift/Controllers/Roster/GroupRosterItem.h"
+#include <Swiften/Base/String.h>
+#include <Swift/Controllers/Roster/GroupRosterItem.h>
+#include <Swift/Controllers/SettingConstants.h>
 
 namespace Swift {
 
@@ -48,15 +49,15 @@ void RosterGroupExpandinessPersister::save() {
 		}
 		setting += group;
 	}
-	settings_->storeString(SettingPath, setting);
+	settings_->storeSetting(SettingConstants::EXPANDED_ROSTER_GROUPS, setting);
 }
 
 void RosterGroupExpandinessPersister::load() {
-	std::string saved = settings_->getStringSetting(SettingPath);
+	std::string saved = settings_->getSetting(SettingConstants::EXPANDED_ROSTER_GROUPS);
 	std::vector<std::string> collapsed = String::split(saved, '\n');
 	collapsed_.insert(collapsed.begin(), collapsed.end());
 }
 
-const std::string RosterGroupExpandinessPersister::SettingPath = "GroupExpandiness";
+
 
 }
diff --git a/Swift/Controllers/Roster/RosterGroupExpandinessPersister.h b/Swift/Controllers/Roster/RosterGroupExpandinessPersister.h
index 63affe4..73c4f29 100644
--- a/Swift/Controllers/Roster/RosterGroupExpandinessPersister.h
+++ b/Swift/Controllers/Roster/RosterGroupExpandinessPersister.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Kevin Smith
+ * Copyright (c) 2010-2012 Kevin Smith
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
@@ -22,6 +22,5 @@ namespace Swift {
 			std::set<std::string> collapsed_;
 			Roster* roster_;
 			SettingsProvider* settings_;
-			static const std::string SettingPath;
 	};
 }
diff --git a/Swift/Controllers/SConscript b/Swift/Controllers/SConscript
index e48f382..02e212b 100644
--- a/Swift/Controllers/SConscript
+++ b/Swift/Controllers/SConscript
@@ -54,6 +54,9 @@ if env["SCONS_STAGE"] == "build" :
 			"UIInterfaces/XMLConsoleWidget.cpp",
 			"UIInterfaces/ChatListWindow.cpp",
 			"PreviousStatusStore.cpp",
+			"ProfileSettingsProvider.cpp",
+			"Settings/SettingsProviderHierachy.cpp",
+			"Settings/XMLSettingsProvider.cpp",
 			"Storages/CertificateStorageFactory.cpp",
 			"Storages/CertificateStorage.cpp",
 			"Storages/CertificateFileStorage.cpp",
@@ -67,6 +70,7 @@ if env["SCONS_STAGE"] == "build" :
 			"Translator.cpp",
 			"XMPPURIController.cpp",
 			"ChatMessageSummarizer.cpp",
+			"SettingConstants.cpp"
 		])
 
 	env.Append(UNITTEST_SOURCES = [
diff --git a/Swift/Controllers/SettingConstants.cpp b/Swift/Controllers/SettingConstants.cpp
new file mode 100644
index 0000000..7ab4ac4
--- /dev/null
+++ b/Swift/Controllers/SettingConstants.cpp
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2012 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swift/Controllers/SettingConstants.h>
+
+namespace Swift {
+
+const SettingsProvider::Setting<bool> SettingConstants::IDLE_GOES_OFFLINE = SettingsProvider::Setting<bool>("idleGoesOffline", false);
+const SettingsProvider::Setting<int> SettingConstants::IDLE_TIMEOUT = SettingsProvider::Setting<int>("idleTimeout", 600);
+const SettingsProvider::Setting<bool> SettingConstants::SHOW_NOTIFICATIONS = SettingsProvider::Setting<bool>("showNotifications", true);
+const SettingsProvider::Setting<bool> SettingConstants::REQUEST_DELIVERYRECEIPTS = SettingsProvider::Setting<bool>("requestDeliveryReceipts", false);
+const SettingsProvider::Setting<bool> SettingConstants::FORGET_PASSWORDS = SettingsProvider::Setting<bool>("forgetPasswords", false);
+const SettingsProvider::Setting<bool> SettingConstants::REMEMBER_RECENT_CHATS = SettingsProvider::Setting<bool>("rememberRecentChats", true);
+const SettingsProvider::Setting<std::string> SettingConstants::LAST_LOGIN_JID = SettingsProvider::Setting<std::string>("lastLoginJID", "");
+const SettingsProvider::Setting<bool> SettingConstants::LOGIN_AUTOMATICALLY = SettingsProvider::Setting<bool>("loginAutomatically", false);
+const SettingsProvider::Setting<bool> SettingConstants::SHOW_OFFLINE("showOffline", false);
+const SettingsProvider::Setting<std::string> SettingConstants::EXPANDED_ROSTER_GROUPS("GroupExpandiness", "");
+const SettingsProvider::Setting<bool> SettingConstants::PLAY_SOUNDS("playSounds", true);
+}
diff --git a/Swift/Controllers/SettingConstants.h b/Swift/Controllers/SettingConstants.h
new file mode 100644
index 0000000..ff1ed72
--- /dev/null
+++ b/Swift/Controllers/SettingConstants.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2012 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <Swift/Controllers/Settings/SettingsProvider.h>
+
+namespace Swift {
+	class SettingConstants {
+		public:
+			static const SettingsProvider::Setting<bool> IDLE_GOES_OFFLINE;
+			static const SettingsProvider::Setting<int> IDLE_TIMEOUT;
+			static const SettingsProvider::Setting<bool> SHOW_NOTIFICATIONS;
+			static const SettingsProvider::Setting<bool> REQUEST_DELIVERYRECEIPTS;
+			static const SettingsProvider::Setting<bool> FORGET_PASSWORDS;
+			static const SettingsProvider::Setting<bool> REMEMBER_RECENT_CHATS;
+			static const SettingsProvider::Setting<std::string> LAST_LOGIN_JID;
+			static const SettingsProvider::Setting<bool> LOGIN_AUTOMATICALLY;
+			static const SettingsProvider::Setting<bool> SHOW_OFFLINE;
+			static const SettingsProvider::Setting<std::string> EXPANDED_ROSTER_GROUPS;
+			static const SettingsProvider::Setting<bool> PLAY_SOUNDS;
+	};
+}
diff --git a/Swift/Controllers/Settings/DummySettingsProvider.h b/Swift/Controllers/Settings/DummySettingsProvider.h
index 90e1921..bb7d2e6 100644
--- a/Swift/Controllers/Settings/DummySettingsProvider.h
+++ b/Swift/Controllers/Settings/DummySettingsProvider.h
@@ -6,22 +6,44 @@
 
 #pragma once
 
-#include "Swift/Controllers/Settings/SettingsProvider.h"
+#include <Swift/Controllers/Settings/SettingsProvider.h>
+
+#include <map>
 
 namespace Swift {
 
 class DummySettingsProvider : public SettingsProvider {
 	public:
 		virtual ~DummySettingsProvider() {}
-		virtual std::string getStringSetting(const std::string&) {return "";}
-		virtual void storeString(const std::string &, const std::string &) {}
-		virtual bool getBoolSetting(const std::string &, bool ) {return true;}
-		virtual void storeBool(const std::string &, bool ) {}
-		virtual int getIntSetting(const std::string &, int ) {return 0;}
-		virtual void storeInt(const std::string &, int ) {}
+		virtual std::string getSetting(const Setting<std::string>& setting) {
+			return stringValues.find(setting.getKey()) != stringValues.end() ? stringValues[setting.getKey()] : setting.getDefaultValue();
+		};
+		virtual void storeSetting(const Setting<std::string>& setting, const std::string& value) {
+			stringValues[setting.getKey()] = value;
+			onSettingChanged(setting.getKey());
+		};
+		virtual bool getSetting(const Setting<bool>& setting) {
+			return boolValues.find(setting.getKey()) != boolValues.end() ? boolValues[setting.getKey()] : setting.getDefaultValue();
+		};
+		virtual void storeSetting(const Setting<bool>& setting, const bool& value) {
+			boolValues[setting.getKey()] = value;
+			onSettingChanged(setting.getKey());
+		};
+		virtual int getSetting(const Setting<int>& setting) {
+			return intValues.find(setting.getKey()) != intValues.end() ? intValues[setting.getKey()] : setting.getDefaultValue();
+		};
+		virtual void storeSetting(const Setting<int>& setting, const int& value) {
+			intValues[setting.getKey()] = value;
+			onSettingChanged(setting.getKey());
+		};
 		virtual std::vector<std::string> getAvailableProfiles() {return std::vector<std::string>();}
 		virtual void createProfile(const std::string& ) {}
 		virtual void removeProfile(const std::string& ) {}
+		virtual bool getIsSettingFinal(const std::string& ) {return false;}
+	private:
+		std::map<std::string, std::string> stringValues;
+		std::map<std::string, int> intValues;
+		std::map<std::string, bool> boolValues;
 };
 
 }
diff --git a/Swift/Controllers/Settings/SettingsProvider.h b/Swift/Controllers/Settings/SettingsProvider.h
index a5ff4eb..e884add 100644
--- a/Swift/Controllers/Settings/SettingsProvider.h
+++ b/Swift/Controllers/Settings/SettingsProvider.h
@@ -1,33 +1,73 @@
 /*
- * Copyright (c) 2010 Remko Tronçon
+ * Copyright (c) 2010-2012 Remko Tronçon
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
 
-#ifndef SWIFTEN_SettingsProvider_H
-#define SWIFTEN_SettingsProvider_H
+#pragma once
 
-#include <string>
+#include <Swiften/Base/boost_bsignals.h>
 
+#include <string>
 #include <vector>
 
 namespace Swift {
 
 class SettingsProvider {
+
+	public:
+		template <typename T>
+		class Setting {
+			public:
+				Setting(const std::string& key, const T& defaultValue) : key(key), defaultValue(defaultValue) {
+
+				}
+
+				const std::string& getKey() const {
+					return key;
+				}
+
+				const T& getDefaultValue() const {
+					return defaultValue;
+				}
+
+			private:
+				std::string key;
+				T defaultValue;
+		};
+
 	public:
 		virtual ~SettingsProvider() {}
-		virtual std::string getStringSetting(const std::string &settingPath) = 0;
-		virtual void storeString(const std::string &settingPath, const std::string &settingValue) = 0;
-		virtual bool getBoolSetting(const std::string &settingPath, bool defaultValue) = 0;
-		virtual void storeBool(const std::string &settingPath, bool settingValue) = 0;
-		virtual int getIntSetting(const std::string &settingPath, int defaultValue) = 0;
-		virtual void storeInt(const std::string &settingPath, int settingValue) = 0;
+		virtual std::string getSetting(const Setting<std::string>& setting) = 0;
+		virtual void storeSetting(const Setting<std::string>& setting, const std::string& value) = 0;
+		virtual bool getSetting(const Setting<bool>& setting) = 0;
+		virtual void storeSetting(const Setting<bool>& setting, const bool& value) = 0;
+		virtual int getSetting(const Setting<int>& setting) = 0;
+		virtual void storeSetting(const Setting<int>& setting, const int& value) = 0;
+
 		virtual std::vector<std::string> getAvailableProfiles() = 0;
 		virtual void createProfile(const std::string& profile) = 0;
 		virtual void removeProfile(const std::string& profile) = 0;
+		/** A final setting is one that this settings provider says may not be overriden by lower priority profiles.
+		 * e.g. An Administrator-set configuration to disallow saving user passwords could not be overridden by the user.
+		 */
+		template<typename T>
+		bool getIsSettingFinal(const Setting<T>& setting) {
+			return getIsSettingFinal(setting.getKey());
+		}
+
+		friend class SettingsProviderHierachy;
+	protected:
+		virtual bool getIsSettingFinal(const std::string& settingPath) = 0;
+
+	public:
+		/**
+		 * Emitted when a setting is changed.
+		 */
+		boost::signal<void (const std::string& /*Setting's Path*/)> onSettingChanged;
 };
 
 }
-#endif
+
 
 
diff --git a/Swift/Controllers/Settings/SettingsProviderHierachy.cpp b/Swift/Controllers/Settings/SettingsProviderHierachy.cpp
new file mode 100644
index 0000000..3b7d13c
--- /dev/null
+++ b/Swift/Controllers/Settings/SettingsProviderHierachy.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2012 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swift/Controllers/Settings/SettingsProviderHierachy.h>
+
+#include <Swiften/Base/foreach.h>
+#include <Swiften/Base/Log.h>
+namespace Swift {
+
+SettingsProviderHierachy::~SettingsProviderHierachy() {
+}
+
+std::string SettingsProviderHierachy::getSetting(const Setting<std::string>& setting) {
+	foreach (SettingsProvider* provider, providers_) {
+		std::string providerSetting = provider->getSetting(setting);
+		if (providerSetting != setting.getDefaultValue()) {
+			return providerSetting;
+		}
+	}
+	return setting.getDefaultValue();
+}
+
+void SettingsProviderHierachy::storeSetting(const Setting<std::string>& setting, const std::string& settingValue) {
+	if (!getIsSettingFinal(setting.getKey())) {
+		getWritableProvider()->storeSetting(setting, settingValue);
+	}
+}
+
+bool SettingsProviderHierachy::getSetting(const Setting<bool>& setting) {
+	foreach (SettingsProvider* provider, providers_) {
+		bool providerSetting = provider->getSetting(setting);
+		if (providerSetting != setting.getDefaultValue()) {
+			return providerSetting;
+		}
+	}
+	return setting.getDefaultValue();
+}
+
+void SettingsProviderHierachy::storeSetting(const Setting<bool>& setting, const bool& settingValue) {
+	if (!getIsSettingFinal(setting.getKey())) {
+		getWritableProvider()->storeSetting(setting, settingValue);
+	}
+}
+
+int SettingsProviderHierachy::getSetting(const Setting<int>& setting) {
+	foreach (SettingsProvider* provider, providers_) {
+		int providerSetting = provider->getSetting(setting);
+		if (providerSetting != setting.getDefaultValue()) {
+			return providerSetting;
+		}
+	}
+	return setting.getDefaultValue();
+}
+
+void SettingsProviderHierachy::storeSetting(const Setting<int>& setting, const int& settingValue) {
+	if (!getIsSettingFinal(setting.getKey())) {
+		getWritableProvider()->storeSetting(setting, settingValue);
+	}
+}
+
+std::vector<std::string> SettingsProviderHierachy::getAvailableProfiles() {
+	/* Always pull profiles from the topmost */
+	return getWritableProvider()->getAvailableProfiles();
+}
+
+void SettingsProviderHierachy::createProfile(const std::string& profile) {
+	return getWritableProvider()->createProfile(profile);
+}
+
+void SettingsProviderHierachy::removeProfile(const std::string& profile) {
+	return getWritableProvider()->removeProfile(profile);
+}
+
+bool SettingsProviderHierachy::getIsSettingFinal(const std::string& settingPath) {
+	bool isFinal = false;
+	foreach (SettingsProvider* provider, providers_) {
+		isFinal |= provider->getIsSettingFinal(settingPath);
+	}
+	return isFinal;
+}
+
+SettingsProvider* SettingsProviderHierachy::getWritableProvider() {
+	return providers_.back();
+}
+
+void SettingsProviderHierachy::addProviderToTopOfStack(SettingsProvider* provider) {
+	providers_.push_back(provider);
+	provider->onSettingChanged.connect(onSettingChanged);
+}
+
+}
+
diff --git a/Swift/Controllers/Settings/SettingsProviderHierachy.h b/Swift/Controllers/Settings/SettingsProviderHierachy.h
new file mode 100644
index 0000000..b7f6961
--- /dev/null
+++ b/Swift/Controllers/Settings/SettingsProviderHierachy.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2012 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <Swift/Controllers/Settings/SettingsProvider.h>
+
+namespace Swift {
+
+class SettingsProviderHierachy : public SettingsProvider {
+	public:
+		virtual ~SettingsProviderHierachy();
+		virtual std::string getSetting(const Setting<std::string>& setting);
+		virtual void storeSetting(const Setting<std::string>& setting, const std::string& value);
+		virtual bool getSetting(const Setting<bool>& setting);
+		virtual void storeSetting(const Setting<bool>& setting, const bool& value);
+		virtual int getSetting(const Setting<int>& setting);
+		virtual void storeSetting(const Setting<int>& setting, const int& value);
+		virtual std::vector<std::string> getAvailableProfiles();
+		virtual void createProfile(const std::string& profile);
+		virtual void removeProfile(const std::string& profile);
+	protected:
+		virtual bool getIsSettingFinal(const std::string& settingPath);
+
+	public:
+		/**
+		 * Adds a provider less significant than any already added.
+		 * This means that if an existing provider has a setting, this provider won't be asked.
+		 * Any settings will be pushed into the topmost (least significant) provider.
+		 * Does not take ownership of provider.
+		 */
+		void addProviderToTopOfStack(SettingsProvider* provider);
+	private:
+		SettingsProvider* getWritableProvider();
+	private:
+		/* Start/Left is most significant (lowest), left overrides right.*/
+		std::vector<SettingsProvider*> providers_;
+};
+
+}
+
+
+
diff --git a/Swift/Controllers/Settings/XMLSettingsProvider.cpp b/Swift/Controllers/Settings/XMLSettingsProvider.cpp
new file mode 100644
index 0000000..6ad3170
--- /dev/null
+++ b/Swift/Controllers/Settings/XMLSettingsProvider.cpp
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2012 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swift/Controllers/Settings/XMLSettingsProvider.h>
+
+#include <boost/lexical_cast.hpp>
+#include <boost/algorithm/string.hpp>
+
+#include <Swiften/Parser/PlatformXMLParserFactory.h>
+#include <Swiften/Parser/XMLParser.h>
+#include <Swiften/Base/Log.h>
+
+namespace Swift {
+
+XMLSettingsProvider::XMLSettingsProvider(const std::string& xmlConfig) : level_(0) {
+	if (!xmlConfig.empty()) {
+		PlatformXMLParserFactory factory;
+		XMLParser* parser = factory.createXMLParser(this);
+		if (parser->parse(xmlConfig)) {
+			SWIFT_LOG(debug) << "Found and parsed system config" << std::endl;
+		}
+		else {
+			SWIFT_LOG(debug) << "Found invalid system config" << std::endl;
+		}
+		delete parser;
+	}
+	else {
+		SWIFT_LOG(debug) << "No system config found" << std::endl;
+	}
+}
+
+XMLSettingsProvider::~XMLSettingsProvider() {
+
+}
+
+std::string XMLSettingsProvider::getSetting(const Setting<std::string>& setting) {
+	if (values_.find(setting.getKey()) != values_.end()) {
+		std::string value = values_[setting.getKey()];
+		return value;
+	}
+	return setting.getDefaultValue();
+}
+
+void XMLSettingsProvider::storeSetting(const Setting<std::string>& /*settingPath*/, const std::string& /*settingValue*/) {
+	assert(false);
+}
+
+bool XMLSettingsProvider::getSetting(const Setting<bool>& setting) {
+	if (values_.find(setting.getKey()) != values_.end()) {
+		std::string value = values_[setting.getKey()];
+		return boost::iequals(value, "true") || value == "1";
+	}
+	return setting.getDefaultValue();
+}
+
+void XMLSettingsProvider::storeSetting(const Setting<bool>& /*settingPath*/, const bool& /*settingValue*/) {
+	assert(false);
+}
+
+int XMLSettingsProvider::getSetting(const Setting<int>& setting) {
+	if (values_.find(setting.getKey()) != values_.end()) {
+		std::string value = values_[setting.getKey()];
+		try {
+			return value.empty() ? setting.getDefaultValue() : boost::lexical_cast<int>(value);;
+		}
+		catch(boost::bad_lexical_cast &) {}
+	}
+	return setting.getDefaultValue();
+}
+
+void XMLSettingsProvider::storeSetting(const Setting<int>& /*settingPath*/, const int& /*settingValue*/) {
+	assert(false);
+}
+
+std::vector<std::string> XMLSettingsProvider::getAvailableProfiles() {
+	assert(false);
+}
+
+void XMLSettingsProvider::createProfile(const std::string& /*profile*/) {
+	assert(false);
+}
+
+void XMLSettingsProvider::removeProfile(const std::string& /*profile*/) {
+	assert(false);
+}
+
+bool XMLSettingsProvider::getIsSettingFinal(const std::string& settingPath) {
+	return finals_.count(settingPath);
+}
+
+void XMLSettingsProvider::handleStartElement(const std::string& element, const std::string& /*ns*/, const AttributeMap& attributes) {
+	level_++;
+	if (level_ == SettingLevel) {
+		if (attributes.getBoolAttribute("final", false)) {
+			finals_.insert(element);
+		}
+		currentElement_ = element;
+		currentText_ = "";
+	}
+}
+
+void XMLSettingsProvider::handleEndElement(const std::string& /*element*/, const std::string& /*ns*/) {
+	if (level_ == SettingLevel) {
+		values_[currentElement_] = currentText_;
+		SWIFT_LOG(debug) << "Setting value of " << currentElement_ << " to " << currentText_ << std::endl;
+	}
+	level_--;
+}
+
+void XMLSettingsProvider::handleCharacterData(const std::string& data) {
+	if (level_ >= SettingLevel) {
+		currentText_ += data;
+	}
+}
+
+
+}
+
+
+
+
diff --git a/Swift/Controllers/Settings/XMLSettingsProvider.h b/Swift/Controllers/Settings/XMLSettingsProvider.h
new file mode 100644
index 0000000..61abd11
--- /dev/null
+++ b/Swift/Controllers/Settings/XMLSettingsProvider.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2012 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <Swift/Controllers/Settings/SettingsProvider.h>
+#include <Swiften/Parser/XMLParserClient.h>
+
+#include <map>
+#include <set>
+
+namespace Swift {
+
+class XMLSettingsProvider : public SettingsProvider, public XMLParserClient {
+	public:
+		XMLSettingsProvider(const std::string& xmlConfig);
+		virtual ~XMLSettingsProvider();
+		virtual std::string getSetting(const Setting<std::string>& setting);
+		virtual void storeSetting(const Setting<std::string>& setting, const std::string& value);
+		virtual bool getSetting(const Setting<bool>& setting);
+		virtual void storeSetting(const Setting<bool>& setting, const bool& value);
+		virtual int getSetting(const Setting<int>& setting);
+		virtual void storeSetting(const Setting<int>& setting, const int& value);
+		virtual std::vector<std::string> getAvailableProfiles();
+		virtual void createProfile(const std::string& profile);
+		virtual void removeProfile(const std::string& profile);
+
+		virtual void handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes);
+		virtual void handleEndElement(const std::string& element, const std::string& ns);
+		virtual void handleCharacterData(const std::string& data);
+
+	protected:
+		virtual bool getIsSettingFinal(const std::string& settingPath);
+	private:
+		std::map<std::string /*settingPath*/, std::string /*settingValue*/> values_;
+		/* Settings that are final*/
+		std::set<std::string /*settingPath*/> finals_;
+
+		enum Level {
+			TopLevel = 0,
+			SettingLevel = 2
+		};
+
+		int level_;
+		std::string currentElement_;
+		std::string currentText_;
+};
+
+}
+
+
+
+
diff --git a/Swift/Controllers/SoundEventController.cpp b/Swift/Controllers/SoundEventController.cpp
index 26847ed..d056990 100644
--- a/Swift/Controllers/SoundEventController.cpp
+++ b/Swift/Controllers/SoundEventController.cpp
@@ -1,31 +1,28 @@
 /*
- * Copyright (c) 2010 Kevin Smith
+ * Copyright (c) 2010-2012 Kevin Smith
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
 
-#include "Swift/Controllers/SoundEventController.h"
+#include <Swift/Controllers/SoundEventController.h>
 
 #include <boost/bind.hpp>
 
-#include "Swift/Controllers/XMPPEvents/EventController.h"
-#include "Swift/Controllers/SoundPlayer.h"
-#include "Swift/Controllers/UIEvents/UIEventStream.h"
-#include "Swift/Controllers/UIEvents/ToggleSoundsUIEvent.h"
+#include <Swift/Controllers/XMPPEvents/EventController.h>
+#include <Swift/Controllers/SoundPlayer.h>
+#include <Swift/Controllers/UIEvents/UIEventStream.h>
+#include <Swift/Controllers/SettingConstants.h>
 
 namespace Swift {
 
-SoundEventController::SoundEventController(EventController* eventController, SoundPlayer* soundPlayer, SettingsProvider* settings, UIEventStream* uiEvents) {
-	uiEvents_ = uiEvents;
+SoundEventController::SoundEventController(EventController* eventController, SoundPlayer* soundPlayer, SettingsProvider* settings) {
 	settings_ = settings;
 	eventController_ = eventController;
 	soundPlayer_ = soundPlayer;
-	uiEvents_->onUIEvent.connect(boost::bind(&SoundEventController::handleUIEvent, this, _1));
 	eventController_->onEventQueueEventAdded.connect(boost::bind(&SoundEventController::handleEventQueueEventAdded, this, _1));
+	settings_->onSettingChanged.connect(boost::bind(&SoundEventController::handleSettingChanged, this, _1));
 
-	bool playSounds = settings->getBoolSetting("playSounds", true);
-	playSounds_ = !playSounds;
-	setPlaySounds(playSounds);	
+	playSounds_ = settings->getSetting(SettingConstants::PLAY_SOUNDS);
 }
 
 void SoundEventController::handleEventQueueEventAdded(boost::shared_ptr<StanzaEvent> event) {
@@ -35,18 +32,13 @@ void SoundEventController::handleEventQueueEventAdded(boost::shared_ptr<StanzaEv
 }
 
 void SoundEventController::setPlaySounds(bool playSounds) {
-	bool transmit = playSounds != playSounds_;
 	playSounds_ = playSounds;
-	settings_->storeBool("playSounds", playSounds);
-	if (transmit) {
-		uiEvents_->send(boost::shared_ptr<ToggleSoundsUIEvent>(new ToggleSoundsUIEvent(playSounds_)));
-	}
+	settings_->storeSetting(SettingConstants::PLAY_SOUNDS, playSounds);
 }
 
-void SoundEventController::handleUIEvent(boost::shared_ptr<UIEvent> event) {
-	boost::shared_ptr<ToggleSoundsUIEvent> soundEvent = boost::dynamic_pointer_cast<ToggleSoundsUIEvent>(event);
-	if (soundEvent) {
-		setPlaySounds(soundEvent->getEnabled());
+void SoundEventController::handleSettingChanged(const std::string& settingPath) {
+	if (SettingConstants::PLAY_SOUNDS.getKey() == settingPath) {
+		playSounds_ = settings_->getSetting(SettingConstants::PLAY_SOUNDS);
 	}
 }
 
diff --git a/Swift/Controllers/SoundEventController.h b/Swift/Controllers/SoundEventController.h
index 5e00fc6..c6dec6f 100644
--- a/Swift/Controllers/SoundEventController.h
+++ b/Swift/Controllers/SoundEventController.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Kevin Smith
+ * Copyright (c) 2010-2012 Kevin Smith
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
@@ -8,26 +8,23 @@
 
 #include <boost/shared_ptr.hpp>
 
-#include "Swift/Controllers/XMPPEvents/StanzaEvent.h"
-#include "Swift/Controllers/Settings/SettingsProvider.h"
-#include "Swift/Controllers/UIEvents/UIEvent.h"
+#include <Swift/Controllers/XMPPEvents/StanzaEvent.h>
+#include <Swift/Controllers/Settings/SettingsProvider.h>
 
 namespace Swift {
 	class EventController;
 	class SoundPlayer;
-	class UIEventStream;
 	class SoundEventController {
 		public:
-			SoundEventController(EventController* eventController, SoundPlayer* soundPlayer, SettingsProvider* settings, UIEventStream* uiEvents);
+			SoundEventController(EventController* eventController, SoundPlayer* soundPlayer, SettingsProvider* settings);
 			void setPlaySounds(bool playSounds);
 			bool getSoundEnabled() {return playSounds_;};
 		private:
-			void handleUIEvent(boost::shared_ptr<UIEvent> event);
+			void handleSettingChanged(const std::string& settingPath);
 			void handleEventQueueEventAdded(boost::shared_ptr<StanzaEvent> event);
 			EventController* eventController_;
 			SoundPlayer* soundPlayer_;
 			bool playSounds_;
-			UIEventStream* uiEvents_;
 			SettingsProvider* settings_;
 	};
 }
diff --git a/Swift/Controllers/UIEvents/ToggleNotificationsUIEvent.h b/Swift/Controllers/UIEvents/ToggleNotificationsUIEvent.h
deleted file mode 100644
index 0f7acc8..0000000
--- a/Swift/Controllers/UIEvents/ToggleNotificationsUIEvent.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (c) 2010 Kevin Smith
- * Licensed under the GNU General Public License v3.
- * See Documentation/Licenses/GPLv3.txt for more information.
- */
-
-#pragma once
-
-#include "Swift/Controllers/UIEvents/UIEvent.h"
-
-namespace Swift {
-	class ToggleNotificationsUIEvent : public UIEvent {
-		public:
-			ToggleNotificationsUIEvent(bool enable) : enabled_(enable) {};
-			bool getEnabled() {return enabled_;};
-		private:
-			bool enabled_;
-	};
-}
diff --git a/Swift/Controllers/UIEvents/ToggleRequestDeliveryReceiptsUIEvent.h b/Swift/Controllers/UIEvents/ToggleRequestDeliveryReceiptsUIEvent.h
deleted file mode 100644
index 1ea2db5..0000000
--- a/Swift/Controllers/UIEvents/ToggleRequestDeliveryReceiptsUIEvent.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (c) 2011 Tobias Markmann
- * Licensed under the BSD license.
- * See http://www.opensource.org/licenses/bsd-license.php for more information.
- */
-
-#pragma once
-
-#include "Swift/Controllers/UIEvents/UIEvent.h"
-
-namespace Swift {
-	class ToggleRequestDeliveryReceiptsUIEvent : public UIEvent {
-		public:
-			ToggleRequestDeliveryReceiptsUIEvent(bool enable) : enabled_(enable) {}
-			bool getEnabled() {return enabled_;}
-		private:
-			bool enabled_;
-	};
-}
diff --git a/Swift/Controllers/UIEvents/ToggleShowOfflineUIEvent.h b/Swift/Controllers/UIEvents/ToggleShowOfflineUIEvent.h
deleted file mode 100644
index b45eb83..0000000
--- a/Swift/Controllers/UIEvents/ToggleShowOfflineUIEvent.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (c) 2010 Kevin Smith
- * Licensed under the GNU General Public License v3.
- * See Documentation/Licenses/GPLv3.txt for more information.
- */
-
-#pragma once
-
-#include "Swift/Controllers/UIEvents/UIEvent.h"
-
-namespace Swift {
-	class ToggleShowOfflineUIEvent : public UIEvent {
-		public:
-			ToggleShowOfflineUIEvent(bool show) : show_(show) {};
-			bool getShow() {return show_;};
-		private:
-			bool show_;
-	};
-}
diff --git a/Swift/Controllers/UIEvents/ToggleSoundsUIEvent.h b/Swift/Controllers/UIEvents/ToggleSoundsUIEvent.h
deleted file mode 100644
index 9e5cfc6..0000000
--- a/Swift/Controllers/UIEvents/ToggleSoundsUIEvent.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (c) 2010 Kevin Smith
- * Licensed under the GNU General Public License v3.
- * See Documentation/Licenses/GPLv3.txt for more information.
- */
-
-#pragma once
-
-#include "Swift/Controllers/UIEvents/UIEvent.h"
-
-namespace Swift {
-	class ToggleSoundsUIEvent : public UIEvent {
-		public:
-			ToggleSoundsUIEvent(bool enable) : enabled_(enable) {};
-			bool getEnabled() {return enabled_;};
-		private:
-			bool enabled_;
-	};
-}
diff --git a/Swift/QtUI/ChatList/QtChatListWindow.cpp b/Swift/QtUI/ChatList/QtChatListWindow.cpp
index 8de5720..5181040 100644
--- a/Swift/QtUI/ChatList/QtChatListWindow.cpp
+++ b/Swift/QtUI/ChatList/QtChatListWindow.cpp
@@ -6,6 +6,8 @@
 
 #include "Swift/QtUI/ChatList/QtChatListWindow.h"
 
+#include <Boost/bind.hpp>
+
 #include <QMenu>
 #include <QContextMenuEvent>
 
@@ -13,22 +15,24 @@
 #include <Swift/QtUI/ChatList/ChatListRecentItem.h>
 #include <Swift/QtUI/QtAddBookmarkWindow.h>
 #include <Swift/QtUI/QtEditBookmarkWindow.h>
+#include <Swift/QtUI/QtUISettingConstants.h>
 #include <Swift/Controllers/UIEvents/JoinMUCUIEvent.h>
 #include <Swift/Controllers/UIEvents/RequestChatUIEvent.h>
 #include <Swift/Controllers/UIEvents/AddMUCBookmarkUIEvent.h>
 #include <Swift/Controllers/UIEvents/RemoveMUCBookmarkUIEvent.h>
 #include <Swift/Controllers/UIEvents/EditMUCBookmarkUIEvent.h>
-#include <Swift/QtUI/QtUIPreferences.h>
+#include <Swift/Controllers/Settings/SettingsProvider.h>
+
 
 namespace Swift {
 
-QtChatListWindow::QtChatListWindow(UIEventStream *uiEventStream, QtUIPreferences* uiPreferences, QWidget* parent) : QTreeView(parent) {
+QtChatListWindow::QtChatListWindow(UIEventStream *uiEventStream, SettingsProvider* settings, QWidget* parent) : QTreeView(parent) {
 	eventStream_ = uiEventStream;
-	uiPreferences_ = uiPreferences;
+	settings_ = settings;;
 	bookmarksEnabled_ = false;
 	model_ = new ChatListModel();
 	setModel(model_);
-	delegate_ = new ChatListDelegate(uiPreferences_->getCompactRosters());
+	delegate_ = new ChatListDelegate(settings_->getSetting(QtUISettingConstants::COMPACT_ROSTER));
 	setItemDelegate(delegate_);
 	setHeaderHidden(true);
 #ifdef SWIFT_PLATFORM_MACOSX
@@ -41,19 +45,23 @@ QtChatListWindow::QtChatListWindow(UIEventStream *uiEventStream, QtUIPreferences
 	setupContextMenus();
 	connect(this, SIGNAL(activated(const QModelIndex&)), this, SLOT(handleItemActivated(const QModelIndex&)));
 	connect(this, SIGNAL(clicked(const QModelIndex&)), this, SLOT(handleClicked(const QModelIndex&)));
-	connect(uiPreferences_, SIGNAL(onCompactRostersChanged(bool)), this, SLOT(handleCompactRostersToggled(bool)));
+
+	settings_->onSettingChanged.connect(boost::bind(&QtChatListWindow::handleSettingChanged, this, _1));
 }
 
 QtChatListWindow::~QtChatListWindow() {
+	settings_->onSettingChanged.disconnect(boost::bind(&QtChatListWindow::handleSettingChanged, this, _1));
 	delete model_;
 	delete delegate_;
 	delete mucMenu_;
 	delete emptyMenu_;
 }
 
-void QtChatListWindow::handleCompactRostersToggled(bool compact) {
-	delegate_->setCompact(compact);
-	repaint();
+void QtChatListWindow::handleSettingChanged(const std::string& setting) {
+	if (setting == QtUISettingConstants::COMPACT_ROSTER.getKey()) {
+		delegate_->setCompact(settings_->getSetting(QtUISettingConstants::COMPACT_ROSTER));
+		repaint();
+	}
 }
 
 void QtChatListWindow::setBookmarksEnabled(bool enabled) {
diff --git a/Swift/QtUI/ChatList/QtChatListWindow.h b/Swift/QtUI/ChatList/QtChatListWindow.h
index af37015..33131ce 100644
--- a/Swift/QtUI/ChatList/QtChatListWindow.h
+++ b/Swift/QtUI/ChatList/QtChatListWindow.h
@@ -14,11 +14,11 @@
 #include "Swift/QtUI/ChatList/ChatListDelegate.h"
 
 namespace Swift {
-	class QtUIPreferences;
+	class SettingsProvider;
 	class QtChatListWindow : public QTreeView, public ChatListWindow {
 		Q_OBJECT
 		public:
-			QtChatListWindow(UIEventStream *uiEventStream, QtUIPreferences* uiPreferences, QWidget* parent = NULL);
+			QtChatListWindow(UIEventStream *uiEventStream, SettingsProvider* settings, QWidget* parent = NULL);
 			virtual ~QtChatListWindow();
 			void addMUCBookmark(const MUCBookmark& bookmark);
 			void removeMUCBookmark(const MUCBookmark& bookmark);
@@ -35,7 +35,7 @@ namespace Swift {
 			void handleEditBookmark();
 			void handleRemoveBookmark();
 			void handleClicked(const QModelIndex& index);
-			void handleCompactRostersToggled(bool);
+			void handleSettingChanged(const std::string& setting);
 
 		protected:
 			void contextMenuEvent(QContextMenuEvent* event);
@@ -49,7 +49,7 @@ namespace Swift {
 			QMenu* mucMenu_;
 			QMenu* emptyMenu_;
 			ChatListItem* contextMenuItem_;
-			QtUIPreferences* uiPreferences_;
+			SettingsProvider* settings_;
 	};
 
 }
diff --git a/Swift/QtUI/QtChatWindow.cpp b/Swift/QtUI/QtChatWindow.cpp
index 4cf606c..dd33e28 100644
--- a/Swift/QtUI/QtChatWindow.cpp
+++ b/Swift/QtUI/QtChatWindow.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2011 Kevin Smith
+ * Copyright (c) 2010-2012 Kevin Smith
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
@@ -45,13 +45,13 @@
 #include <QPushButton>
 #include <QFileDialog>
 #include <QMenu>
-#include <Swift/QtUI/QtUIPreferences.h>
+#include <Swift/Controllers/Settings/SettingsProvider.h>
 
 #include <QDebug>
 
 namespace Swift {
-QtChatWindow::QtChatWindow(const QString &contact, QtChatTheme* theme, UIEventStream* eventStream, QtUIPreferences* uiPreferences) : QtTabbable(), contact_(contact), previousMessageWasSelf_(false), previousMessageWasSystem_(false), previousMessageWasPresence_(false), previousMessageWasFileTransfer_(false), eventStream_(eventStream) {
-	uiPreferences_ = uiPreferences;
+QtChatWindow::QtChatWindow(const QString &contact, QtChatTheme* theme, UIEventStream* eventStream, SettingsProvider* settings) : QtTabbable(), contact_(contact), previousMessageWasSelf_(false), previousMessageWasSystem_(false), previousMessageWasPresence_(false), previousMessageWasFileTransfer_(false), eventStream_(eventStream) {
+	settings_ = settings;
 	unreadCount_ = 0;
 	idCounter_ = 0;
 	inputEnabled_ = true;
@@ -61,7 +61,6 @@ QtChatWindow::QtChatWindow(const QString &contact, QtChatTheme* theme, UIEventSt
 	isCorrection_ = false;
 	correctionEnabled_ = Maybe;
 	updateTitleWithUnreadCount();
-	QtSettingsProvider settings;
 
 #ifdef SWIFT_EXPERIMENTAL_FT
 	setAcceptDrops(true);
@@ -110,7 +109,7 @@ QtChatWindow::QtChatWindow(const QString &contact, QtChatTheme* theme, UIEventSt
 	messageLog_ = new QtChatView(theme, this);
 	logRosterSplitter_->addWidget(messageLog_);
 
-	treeWidget_ = new QtOccupantListWidget(eventStream_, uiPreferences_, this);
+	treeWidget_ = new QtOccupantListWidget(eventStream_, settings_, this);
 	treeWidget_->hide();
 	logRosterSplitter_->addWidget(treeWidget_);
 	logRosterSplitter_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
diff --git a/Swift/QtUI/QtChatWindow.h b/Swift/QtUI/QtChatWindow.h
index 4f997c0..9203068 100644
--- a/Swift/QtUI/QtChatWindow.h
+++ b/Swift/QtUI/QtChatWindow.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2011 Kevin Smith
+ * Copyright (c) 2010-2012 Kevin Smith
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
@@ -32,12 +32,12 @@ namespace Swift {
 	class QtTextEdit;
 	class UIEventStream;
 	class QtFileTransferJSBridge;
-	class QtUIPreferences;
+	class SettingsProvider;
 
 	class QtChatWindow : public QtTabbable, public ChatWindow {
 		Q_OBJECT
 		public:
-			QtChatWindow(const QString &contact, QtChatTheme* theme, UIEventStream* eventStream, QtUIPreferences* uiPreferences);
+			QtChatWindow(const QString &contact, QtChatTheme* theme, UIEventStream* eventStream, SettingsProvider* settings);
 			~QtChatWindow();
 			std::string addMessage(const std::string &message, const std::string &senderName, bool senderIsSelf, boost::shared_ptr<SecurityLabel> label, const std::string& avatarPath, const boost::posix_time::ptime& time);
 			std::string addAction(const std::string &message, const std::string &senderName, bool senderIsSelf, boost::shared_ptr<SecurityLabel> label, const std::string& avatarPath, const boost::posix_time::ptime& time);
@@ -162,6 +162,6 @@ namespace Swift {
 			QPointer<QtMUCConfigurationWindow> mucConfigurationWindow_;
 			QPointer<QtAffiliationEditor> affiliationEditor_;
 			int idCounter_;
-			QtUIPreferences* uiPreferences_;
+			SettingsProvider* settings_;
 	};
 }
diff --git a/Swift/QtUI/QtChatWindowFactory.cpp b/Swift/QtUI/QtChatWindowFactory.cpp
index b860dae..7610082 100644
--- a/Swift/QtUI/QtChatWindowFactory.cpp
+++ b/Swift/QtUI/QtChatWindowFactory.cpp
@@ -20,15 +20,15 @@ namespace Swift {
 static const QString SPLITTER_STATE = "mucSplitterState";
 static const QString CHAT_TABS_GEOMETRY = "chatTabsGeometry";
 
-QtChatWindowFactory::QtChatWindowFactory(QSplitter* splitter, QtSettingsProvider* settings, QtChatTabs* tabs, const QString& themePath, QtUIPreferences* uiPreferences) : themePath_(themePath) {
+QtChatWindowFactory::QtChatWindowFactory(QSplitter* splitter, SettingsProvider* settings, QtSettingsProvider* qtSettings, QtChatTabs* tabs, const QString& themePath) : themePath_(themePath) {
+	qtOnlySettings_ = qtSettings;
 	settings_ = settings;
 	tabs_ = tabs;
-	uiPreferences_ = uiPreferences;
 	theme_ = NULL;
 	if (splitter) {
 		splitter->addWidget(tabs_);
 	} else if (tabs_) {
-		QVariant chatTabsGeometryVariant = settings_->getQSettings()->value(CHAT_TABS_GEOMETRY);
+		QVariant chatTabsGeometryVariant = qtOnlySettings_->getQSettings()->value(CHAT_TABS_GEOMETRY);
 		if (chatTabsGeometryVariant.isValid()) {
 			tabs_->restoreGeometry(chatTabsGeometryVariant.toByteArray());
 		}
@@ -49,11 +49,11 @@ ChatWindow* QtChatWindowFactory::createChatWindow(const JID &contact,UIEventStre
 		}
 	}
 
-	QtChatWindow *chatWindow = new QtChatWindow(P2QSTRING(contact.toString()), theme_, eventStream, uiPreferences_);
+	QtChatWindow *chatWindow = new QtChatWindow(P2QSTRING(contact.toString()), theme_, eventStream, settings_);
 	connect(chatWindow, SIGNAL(splitterMoved()), this, SLOT(handleSplitterMoved()));
 	connect(this, SIGNAL(changeSplitterState(QByteArray)), chatWindow, SLOT(handleChangeSplitterState(QByteArray)));
 
-	QVariant splitterState = settings_->getQSettings()->value(SPLITTER_STATE);
+	QVariant splitterState = qtOnlySettings_->getQSettings()->value(SPLITTER_STATE);
 	if(splitterState.isValid()) {
 		chatWindow->handleChangeSplitterState(splitterState.toByteArray());
 	}
@@ -61,7 +61,7 @@ ChatWindow* QtChatWindowFactory::createChatWindow(const JID &contact,UIEventStre
 	if (tabs_) {
 		tabs_->addTab(chatWindow);
 	} else {
-		QVariant chatGeometryVariant = settings_->getQSettings()->value(CHAT_TABS_GEOMETRY);
+		QVariant chatGeometryVariant = qtOnlySettings_->getQSettings()->value(CHAT_TABS_GEOMETRY);
 		if (chatGeometryVariant.isValid()) {
 			chatWindow->restoreGeometry(chatGeometryVariant.toByteArray());
 		}
@@ -71,12 +71,12 @@ ChatWindow* QtChatWindowFactory::createChatWindow(const JID &contact,UIEventStre
 }
 
 void QtChatWindowFactory::handleWindowGeometryChanged() {
-	settings_->getQSettings()->setValue(CHAT_TABS_GEOMETRY, qobject_cast<QWidget*>(sender())->saveGeometry());
+	qtOnlySettings_->getQSettings()->setValue(CHAT_TABS_GEOMETRY, qobject_cast<QWidget*>(sender())->saveGeometry());
 }
 
 void QtChatWindowFactory::handleSplitterMoved() {
 	QByteArray splitterState = qobject_cast<QtChatWindow*>(sender())->getSplitterState();
-	settings_->getQSettings()->setValue(SPLITTER_STATE, QVariant(splitterState));
+	qtOnlySettings_->getQSettings()->setValue(SPLITTER_STATE, QVariant(splitterState));
 	emit changeSplitterState(splitterState);
 }
 
diff --git a/Swift/QtUI/QtChatWindowFactory.h b/Swift/QtUI/QtChatWindowFactory.h
index f664c43..2a16c3b 100644
--- a/Swift/QtUI/QtChatWindowFactory.h
+++ b/Swift/QtUI/QtChatWindowFactory.h
@@ -20,7 +20,7 @@ namespace Swift {
 	class QtChatWindowFactory : public QObject, public ChatWindowFactory {
 		Q_OBJECT
 		public:
-			QtChatWindowFactory(QSplitter* splitter, QtSettingsProvider* settings, QtChatTabs* tabs, const QString& themePath, QtUIPreferences* uiPreferences);
+			QtChatWindowFactory(QSplitter* splitter, SettingsProvider* settings, QtSettingsProvider* qtSettings, QtChatTabs* tabs, const QString& themePath);
 			~QtChatWindowFactory();
 			ChatWindow* createChatWindow(const JID &contact, UIEventStream* eventStream);
 		signals:
@@ -30,10 +30,10 @@ namespace Swift {
 			void handleSplitterMoved();
 		private:
 			QString themePath_;
-			QtSettingsProvider* settings_;
+			SettingsProvider* settings_;
+			QtSettingsProvider* qtOnlySettings_;
 			QtChatTabs* tabs_;
 			QtChatTheme* theme_;
-			QtUIPreferences* uiPreferences_;
 	};
 }
 
diff --git a/Swift/QtUI/QtLoginWindow.cpp b/Swift/QtUI/QtLoginWindow.cpp
index fc99633..aafdef8 100644
--- a/Swift/QtUI/QtLoginWindow.cpp
+++ b/Swift/QtUI/QtLoginWindow.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2011 Kevin Smith
+ * Copyright (c) 2010-2012 Kevin Smith
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
@@ -27,22 +27,23 @@
 #include <QMessageBox>
 #include <QKeyEvent>
  
-#include "Swift/Controllers/UIEvents/UIEventStream.h"
-#include "Swift/Controllers/UIEvents/RequestXMLConsoleUIEvent.h"
-#include "Swift/Controllers/UIEvents/RequestFileTransferListUIEvent.h"
-#include "Swift/Controllers/UIEvents/ToggleSoundsUIEvent.h"
-#include "Swift/Controllers/UIEvents/ToggleNotificationsUIEvent.h"
-#include "Swiften/Base/Platform.h"
-#include "Swiften/Base/Paths.h"
-
-#include "QtAboutWidget.h"
-#include "QtSwiftUtil.h"
-#include "QtMainWindow.h"
-#include "QtUtilities.h"
+#include <Swift/Controllers/UIEvents/UIEventStream.h>
+#include <Swift/Controllers/UIEvents/RequestXMLConsoleUIEvent.h>
+#include <Swift/Controllers/UIEvents/RequestFileTransferListUIEvent.h>
+#include <Swift/Controllers/Settings/SettingsProvider.h>
+#include <Swift/Controllers/SettingConstants.h>
+#include <Swift/QtUI/QtUISettingConstants.h>
+#include <Swiften/Base/Platform.h>
+#include <Swiften/Base/Paths.h>
+
+#include <QtAboutWidget.h>
+#include <QtSwiftUtil.h>
+#include <QtMainWindow.h>
+#include <QtUtilities.h>
 
 namespace Swift{
 
-QtLoginWindow::QtLoginWindow(UIEventStream* uiEventStream, bool eagleMode) : QMainWindow(), eagleMode_(eagleMode) {
+QtLoginWindow::QtLoginWindow(UIEventStream* uiEventStream, SettingsProvider* settings) : QMainWindow(), settings_(settings) {
 	uiEventStream_ = uiEventStream;
 
 	setWindowTitle("Swift");
@@ -199,13 +200,13 @@ QtLoginWindow::QtLoginWindow(UIEventStream* uiEventStream, bool eagleMode) : QMa
 	swiftMenu_->addAction(quitAction);
 
 	setInitialMenus();
-	uiEventStream_->onUIEvent.connect(boost::bind(&QtLoginWindow::handleUIEvent, this, _1));
+	settings_->onSettingChanged.connect(boost::bind(&QtLoginWindow::handleSettingChanged, this, _1));
 
-
-	remember_->setEnabled(!eagleMode_);
-	loginAutomatically_->setEnabled(!eagleMode_);
-	xmlConsoleAction_->setEnabled(!eagleMode_);
-	if (eagleMode_) {
+	bool eagle = settings_->getSetting(SettingConstants::FORGET_PASSWORDS);
+	remember_->setEnabled(!eagle);
+	loginAutomatically_->setEnabled(!eagle);
+	xmlConsoleAction_->setEnabled(!eagle);
+	if (eagle) {
 		remember_->setChecked(false);
 		loginAutomatically_->setChecked(false);
 	}
@@ -237,14 +238,12 @@ bool QtLoginWindow::eventFilter(QObject *obj, QEvent *event) {
 	return QObject::eventFilter(obj, event);
 }
 
-void QtLoginWindow::handleUIEvent(boost::shared_ptr<UIEvent> event) {
-	boost::shared_ptr<ToggleSoundsUIEvent> soundEvent = boost::dynamic_pointer_cast<ToggleSoundsUIEvent>(event);
-	if (soundEvent) {
-		toggleSoundsAction_->setChecked(soundEvent->getEnabled());
+void QtLoginWindow::handleSettingChanged(const std::string& settingPath) {
+	if (settingPath == SettingConstants::PLAY_SOUNDS.getKey()) {
+		toggleSoundsAction_->setChecked(settings_->getSetting(SettingConstants::PLAY_SOUNDS));
 	}
-	boost::shared_ptr<ToggleNotificationsUIEvent> notificationsEvent = boost::dynamic_pointer_cast<ToggleNotificationsUIEvent>(event);
-	if (notificationsEvent) {
-		toggleNotificationsAction_->setChecked(notificationsEvent->getEnabled());
+	if (settingPath == SettingConstants::SHOW_NOTIFICATIONS.getKey()) {
+		toggleNotificationsAction_->setChecked(settings_->getSetting(SettingConstants::SHOW_NOTIFICATIONS));
 	}
 }
 
@@ -323,36 +322,27 @@ void QtLoginWindow::setIsLoggingIn(bool loggingIn) {
 	for (int i = 0; i < 5; i++) {
 		widgets[i]->setEnabled(!loggingIn);
 	}
-	remember_->setEnabled(!eagleMode_);
-	loginAutomatically_->setEnabled(!eagleMode_);
+	bool eagle = settings_->getSetting(SettingConstants::FORGET_PASSWORDS);
+	remember_->setEnabled(!eagle);
+	loginAutomatically_->setEnabled(!eagle);
 }
 
 void QtLoginWindow::loginClicked() {
 	if (username_->isEnabled()) {
-		if (eagleMode_) {
-			QString clickThroughPath(P2QSTRING((Paths::getExecutablePath() / "eagle-banner.txt").string()));
-			QFile clickThroughFile(clickThroughPath);
-			if (clickThroughFile.exists() && clickThroughFile.open(QIODevice::ReadOnly)) {
-				QString banner;
-				while (!clickThroughFile.atEnd()) {
-					QByteArray line = clickThroughFile.readLine();
-					banner += line + "\n";
-				}
-				if (!banner.isEmpty()) {
-					QMessageBox msgBox;
-					msgBox.setWindowTitle(tr("Confirm terms of use"));
-					msgBox.setText("");
-					msgBox.setInformativeText(banner);
-					msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
-					msgBox.setDefaultButton(QMessageBox::No);
-					if (msgBox.exec() != QMessageBox::Yes) {
-						return;
-					}
-				}
+		std::string banner = settings_->getSetting(QtUISettingConstants::CLICKTHROUGH_BANNER);
+		if (!banner.empty()) {
+			QMessageBox msgBox;
+			msgBox.setWindowTitle(tr("Confirm terms of use"));
+			msgBox.setText("");
+			msgBox.setInformativeText(P2QSTRING(banner));
+			msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
+			msgBox.setDefaultButton(QMessageBox::No);
+			if (msgBox.exec() != QMessageBox::Yes) {
+				return;
 			}
 		}
 		onLoginRequest(Q2PSTRING(username_->currentText()), Q2PSTRING(password_->text()), Q2PSTRING(certificateFile_), remember_->isChecked(), loginAutomatically_->isChecked());
-		if (eagleMode_) { /* Mustn't remember logins */
+		if (settings_->getSetting(SettingConstants::FORGET_PASSWORDS)) { /* Mustn't remember logins */
 			username_->clearEditText();
 			password_->setText("");
 		}
@@ -398,11 +388,11 @@ void QtLoginWindow::handleShowFileTransferOverview() {
 }
 
 void QtLoginWindow::handleToggleSounds(bool enabled) {
-	uiEventStream_->send(boost::shared_ptr<ToggleSoundsUIEvent>(new ToggleSoundsUIEvent(enabled)));
+	settings_->storeSetting(SettingConstants::PLAY_SOUNDS, enabled);
 }
 
 void QtLoginWindow::handleToggleNotifications(bool enabled) {
-	uiEventStream_->send(boost::shared_ptr<ToggleNotificationsUIEvent>(new ToggleNotificationsUIEvent(enabled)));
+	settings_->storeSetting(SettingConstants::SHOW_NOTIFICATIONS, enabled);
 }
 
 void QtLoginWindow::handleQuit() {
diff --git a/Swift/QtUI/QtLoginWindow.h b/Swift/QtUI/QtLoginWindow.h
index df133b1..dcd7c18 100644
--- a/Swift/QtUI/QtLoginWindow.h
+++ b/Swift/QtUI/QtLoginWindow.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2011 Kevin Smith
+ * Copyright (c) 2010-2012 Kevin Smith
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
@@ -14,16 +14,17 @@
 #include <QStackedWidget>
 #include <QMenuBar>
 
-#include "Swift/Controllers/UIInterfaces/LoginWindow.h"
-#include "Swift/Controllers/UIEvents/UIEventStream.h"
-#include "Swift/Controllers/UIInterfaces/MainWindow.h"
-#include "QtAboutWidget.h"
+#include <Swift/Controllers/UIInterfaces/LoginWindow.h>
+#include <Swift/Controllers/UIEvents/UIEventStream.h>
+#include <Swift/Controllers/UIInterfaces/MainWindow.h>
+#include <QtAboutWidget.h>
 
 class QLabel;
 class QToolButton;
 class QComboBox;
 
 namespace Swift {
+	class SettingsProvider;
 	class QtLoginWindow : public QMainWindow, public LoginWindow {
 		Q_OBJECT
 		public:
@@ -34,7 +35,7 @@ namespace Swift {
 			};
 
 		public:
-			QtLoginWindow(UIEventStream* uiEventStream, bool eagleMode);
+			QtLoginWindow(UIEventStream* uiEventStream, SettingsProvider* settings);
 
 			void morphInto(MainWindow *mainWindow);
 			virtual void loggedOut();
@@ -66,7 +67,7 @@ namespace Swift {
 			void handleUsernameTextChanged();
 			void resizeEvent(QResizeEvent* event);
 			void moveEvent(QMoveEvent* event);
-			void handleUIEvent(boost::shared_ptr<UIEvent> event);
+			void handleSettingChanged(const std::string& settingPath);
 
 		protected:
 			bool eventFilter(QObject *obj, QEvent *event);
@@ -94,7 +95,7 @@ namespace Swift {
 			QAction* toggleNotificationsAction_;
 			UIEventStream* uiEventStream_;
 			QPointer<QtAboutWidget> aboutDialog_;
-			bool eagleMode_;
+			SettingsProvider* settings_;
 			QAction* xmlConsoleAction_;
 			QAction* fileTransferOverviewAction_;
 	};
diff --git a/Swift/QtUI/QtMainWindow.cpp b/Swift/QtUI/QtMainWindow.cpp
index 199e388..9f66b31 100644
--- a/Swift/QtUI/QtMainWindow.cpp
+++ b/Swift/QtUI/QtMainWindow.cpp
@@ -24,7 +24,6 @@
 #include <Swift/QtUI/QtSwiftUtil.h>
 #include <Swift/QtUI/QtTabWidget.h>
 #include <Swift/QtUI/QtSettingsProvider.h>
-#include <Swift/QtUI/QtUIPreferences.h>
 #include <Swift/QtUI/QtLoginWindow.h>
 #include <Roster/QtRosterWidget.h>
 #include <Swift/Controllers/UIEvents/RequestJoinMUCUIEvent.h>
@@ -32,17 +31,14 @@
 #include <Swift/Controllers/UIEvents/RequestChatWithUserDialogUIEvent.h>
 #include <Swift/Controllers/UIEvents/RequestProfileEditorUIEvent.h>
 #include <Swift/Controllers/UIEvents/JoinMUCUIEvent.h>
-#include <Swift/Controllers/UIEvents/ToggleShowOfflineUIEvent.h>
 #include <Swift/Controllers/UIEvents/RequestAdHocUIEvent.h>
-#include <Swift/Controllers/UIEvents/ToggleRequestDeliveryReceiptsUIEvent.h>
+#include <Swift/QtUI/QtUISettingConstants.h>
+#include <Swift/Controllers/SettingConstants.h>
 
 namespace Swift {
 
-#define CURRENT_ROSTER_TAB "current_roster_tab"
-
-QtMainWindow::QtMainWindow(QtSettingsProvider* settings, UIEventStream* uiEventStream, QtUIPreferences* uiPreferences, QtLoginWindow::QtMenus loginMenus) : QWidget(), MainWindow(false), loginMenus_(loginMenus) {
+QtMainWindow::QtMainWindow(SettingsProvider* settings, UIEventStream* uiEventStream, QtLoginWindow::QtMenus loginMenus) : QWidget(), MainWindow(false), loginMenus_(loginMenus) {
 	uiEventStream_ = uiEventStream;
-	uiPreferences_ = uiPreferences;
 	settings_ = settings;
 	setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
 	QBoxLayout *mainLayout = new QBoxLayout(QBoxLayout::TopToBottom, this);
@@ -66,7 +62,7 @@ QtMainWindow::QtMainWindow(QtSettingsProvider* settings, UIEventStream* uiEventS
 	contactTabLayout->setSpacing(0);
 	contactTabLayout->setContentsMargins(0, 0, 0, 0);
 
-	treeWidget_ = new QtRosterWidget(uiEventStream_, uiPreferences_, this);
+	treeWidget_ = new QtRosterWidget(uiEventStream_, settings_, this);
 	contactTabLayout->addWidget(treeWidget_);
 
 	tabs_->addTab(contactsTabWidget_, tr("&Contacts"));
@@ -74,13 +70,13 @@ QtMainWindow::QtMainWindow(QtSettingsProvider* settings, UIEventStream* uiEventS
 	eventWindow_ = new QtEventWindow(uiEventStream_);
 	connect(eventWindow_, SIGNAL(onNewEventCountUpdated(int)), this, SLOT(handleEventCountUpdated(int)));
 
-	chatListWindow_ = new QtChatListWindow(uiEventStream_, uiPreferences_);
+	chatListWindow_ = new QtChatListWindow(uiEventStream_, settings_);
 	connect(chatListWindow_, SIGNAL(onCountUpdated(int)), this, SLOT(handleChatCountUpdated(int)));
 
 	tabs_->addTab(chatListWindow_, tr("C&hats"));
 	tabs_->addTab(eventWindow_, tr("&Notices"));
 
-	tabs_->setCurrentIndex(settings_->getIntSetting(CURRENT_ROSTER_TAB, 0));
+	tabs_->setCurrentIndex(settings_->getSetting(QtUISettingConstants::CURRENT_ROSTER_TAB));
 
 	connect(tabs_, SIGNAL(currentChanged(int)), this, SLOT(handleTabChanged(int)));
 
@@ -140,19 +136,20 @@ QtMainWindow::QtMainWindow(QtSettingsProvider* settings, UIEventStream* uiEventS
 	serverAdHocCommandActions_.append(adHocAction);
 
 	lastOfflineState_ = false;
-	uiEventStream_->onUIEvent.connect(boost::bind(&QtMainWindow::handleUIEvent, this, _1));
+
+	settings_->onSettingChanged.connect(boost::bind(&QtMainWindow::handleSettingChanged, this, _1));
 }
 
 QtMainWindow::~QtMainWindow() {
-	uiEventStream_->onUIEvent.disconnect(boost::bind(&QtMainWindow::handleUIEvent, this, _1));
+	settings_->onSettingChanged.disconnect(boost::bind(&QtMainWindow::handleSettingChanged, this, _1));
 }
 
 void QtMainWindow::handleTabChanged(int index) {
-	settings_->storeInt(CURRENT_ROSTER_TAB, index);
+	settings_->storeSetting(QtUISettingConstants::CURRENT_ROSTER_TAB, index);
 }
 
 void QtMainWindow::handleToggleRequestDeliveryReceipts(bool enabled) {
-	uiEventStream_->send(boost::make_shared<ToggleRequestDeliveryReceiptsUIEvent>(enabled));
+	settings_->storeSetting(SettingConstants::REQUEST_DELIVERYRECEIPTS, enabled);
 }
 
 QtEventWindow* QtMainWindow::getEventWindow() {
@@ -220,14 +217,12 @@ void QtMainWindow::handleStatusChanged(StatusShow::Type showType, const QString
 	onChangeStatusRequest(showType, Q2PSTRING(statusMessage));
 }
 
-void QtMainWindow::handleUIEvent(boost::shared_ptr<UIEvent> event) {
-	boost::shared_ptr<ToggleShowOfflineUIEvent> toggleEvent = boost::dynamic_pointer_cast<ToggleShowOfflineUIEvent>(event);
-	if (toggleEvent) {
-		handleShowOfflineToggled(toggleEvent->getShow());
+void QtMainWindow::handleSettingChanged(const std::string& settingPath) {
+	if (settingPath == SettingConstants::SHOW_OFFLINE.getKey()) {
+		handleShowOfflineToggled(settings_->getSetting(SettingConstants::SHOW_OFFLINE));
 	}
-	boost::shared_ptr<ToggleRequestDeliveryReceiptsUIEvent> deliveryReceiptEvent = boost::dynamic_pointer_cast<ToggleRequestDeliveryReceiptsUIEvent>(event);
-	if (deliveryReceiptEvent) {
-		toggleRequestDeliveryReceipts_->setChecked(deliveryReceiptEvent->getEnabled());
+	if (settingPath == SettingConstants::REQUEST_DELIVERYRECEIPTS.getKey()) {
+		toggleRequestDeliveryReceipts_->setChecked(settings_->getSetting(SettingConstants::REQUEST_DELIVERYRECEIPTS));
 	}
 }
 
@@ -235,7 +230,7 @@ void QtMainWindow::handleShowOfflineToggled(bool state) {
 	if (state != lastOfflineState_) {
 		lastOfflineState_ = state;
 		showOfflineAction_->setChecked(state);
-		uiEventStream_->onUIEvent(boost::shared_ptr<UIEvent>(new ToggleShowOfflineUIEvent(state)));
+		settings_->storeSetting(SettingConstants::SHOW_OFFLINE, state);
 	}
 }
 
diff --git a/Swift/QtUI/QtMainWindow.h b/Swift/QtUI/QtMainWindow.h
index 3c8bdec..44f8a25 100644
--- a/Swift/QtUI/QtMainWindow.h
+++ b/Swift/QtUI/QtMainWindow.h
@@ -30,13 +30,13 @@ namespace Swift {
 	class TreeWidget;
 	class UIEventStream;
 	class QtTabWidget;
-	class QtSettingsProvider;
+	class SettingsProvider;
 	class QtUIPreferences;
 
 	class QtMainWindow : public QWidget, public MainWindow {
 		Q_OBJECT
 		public:
-			QtMainWindow(QtSettingsProvider*, UIEventStream* eventStream, QtUIPreferences* uiPreferences, QtLoginWindow::QtMenus loginMenus);
+			QtMainWindow(SettingsProvider*, UIEventStream* eventStream, QtLoginWindow::QtMenus loginMenus);
 			virtual ~QtMainWindow();
 			std::vector<QMenu*> getMenus() {return menus_;}
 			void setMyNick(const std::string& name);
@@ -51,7 +51,7 @@ namespace Swift {
 			void setAvailableAdHocCommands(const std::vector<DiscoItems::Item>& commands);
 		private slots:
 			void handleStatusChanged(StatusShow::Type showType, const QString &statusMessage);
-			void handleUIEvent(boost::shared_ptr<UIEvent> event);
+			void handleSettingChanged(const std::string& settingPath);
 			void handleShowOfflineToggled(bool);
 			void handleJoinMUCAction();
 			void handleSignOutAction();
@@ -66,7 +66,7 @@ namespace Swift {
 			void handleToggleRequestDeliveryReceipts(bool enabled);
 
 		private:
-			QtSettingsProvider* settings_;
+			SettingsProvider* settings_;
 			QtLoginWindow::QtMenus loginMenus_;
 			std::vector<QMenu*> menus_;
 			QtRosterWidget* treeWidget_;
@@ -86,6 +86,5 @@ namespace Swift {
 			bool lastOfflineState_;
 			std::vector<DiscoItems::Item> serverAdHocCommands_;
 			QList<QAction*> serverAdHocCommandActions_;
-			QtUIPreferences* uiPreferences_;
 	};
 }
diff --git a/Swift/QtUI/QtNameWidget.cpp b/Swift/QtUI/QtNameWidget.cpp
index 96f9c0d..08e32f5 100644
--- a/Swift/QtUI/QtNameWidget.cpp
+++ b/Swift/QtUI/QtNameWidget.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Remko Tronçon
+ * Copyright (c) 2010-2012 Remko Tronçon
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
@@ -13,15 +13,16 @@
 
 #include <Swift/QtUI/QtElidingLabel.h>
 #include <Swift/QtUI/QtSettingsProvider.h>
+#include <Swift/QtUI/QtUISettingConstants.h>
 
 namespace Swift {
 
-QtNameWidget::QtNameWidget(QtSettingsProvider* settings, QWidget *parent) : QWidget(parent), settings(settings) {
+QtNameWidget::QtNameWidget(SettingsProvider* settings, QWidget *parent) : QWidget(parent), settings(settings) {
 	QHBoxLayout* mainLayout = new QHBoxLayout(this);
 	mainLayout->setSpacing(0);
 	mainLayout->setContentsMargins(0,0,0,0);
 
-	mode = settings->getBoolSetting("showNickInRosterHeader", true) ? ShowNick : ShowJID;
+	mode = settings->getSetting(QtUISettingConstants::SHOW_NICK_IN_ROSTER_HEADER) ? ShowNick : ShowJID;
 
 	textLabel = new QtElidingLabel(this);
 	QFont font = textLabel->font();
@@ -72,7 +73,7 @@ void QtNameWidget::mousePressEvent(QMouseEvent* event) {
 	else if (result == editProfile) {
 		emit onChangeNickRequest();
 	}
-	settings->storeBool("showNickInRosterHeader", mode == ShowNick);
+	settings->storeSetting(QtUISettingConstants::SHOW_NICK_IN_ROSTER_HEADER, mode == ShowNick);
 	updateText();
 }
 
diff --git a/Swift/QtUI/QtNameWidget.h b/Swift/QtUI/QtNameWidget.h
index 674d55c..0f00c41 100644
--- a/Swift/QtUI/QtNameWidget.h
+++ b/Swift/QtUI/QtNameWidget.h
@@ -10,13 +10,13 @@
 
 namespace Swift {
 	class QtElidingLabel;
-	class QtSettingsProvider;
+	class SettingsProvider;
 
 	class QtNameWidget : public QWidget {
 			Q_OBJECT
 
 		public:
-			QtNameWidget(QtSettingsProvider* settings, QWidget *parent);
+			QtNameWidget(SettingsProvider* settings, QWidget *parent);
 
 			void setNick(const QString& text);
 			void setJID(const QString& jid);
@@ -34,7 +34,7 @@ namespace Swift {
 				ShowJID,
 			};
 
-			QtSettingsProvider* settings;
+			SettingsProvider* settings;
 			Mode mode;
 			QtElidingLabel* textLabel;
 			QString jid;
diff --git a/Swift/QtUI/QtRosterHeader.cpp b/Swift/QtUI/QtRosterHeader.cpp
index 5fb4d1a..98e75c2 100644
--- a/Swift/QtUI/QtRosterHeader.cpp
+++ b/Swift/QtUI/QtRosterHeader.cpp
@@ -23,7 +23,7 @@
 #include "QtScaledAvatarCache.h"
 
 namespace Swift {
-QtRosterHeader::QtRosterHeader(QtSettingsProvider* settings, QWidget* parent) : QWidget(parent) {
+QtRosterHeader::QtRosterHeader(SettingsProvider* settings, QWidget* parent) : QWidget(parent) {
 	QHBoxLayout* topLayout = new QHBoxLayout();
 	topLayout->setSpacing(3);
 	topLayout->setContentsMargins(4,4,4,4);
diff --git a/Swift/QtUI/QtRosterHeader.h b/Swift/QtUI/QtRosterHeader.h
index 3380610..050460c 100644
--- a/Swift/QtUI/QtRosterHeader.h
+++ b/Swift/QtUI/QtRosterHeader.h
@@ -23,12 +23,12 @@ namespace Swift {
 	class QtClickableLabel;
 	class QtStatusWidget;
 	class QtNameWidget;
-	class QtSettingsProvider;
+	class SettingsProvider;
 	
 	class QtRosterHeader : public QWidget {
 		Q_OBJECT
 	public:
-		QtRosterHeader(QtSettingsProvider* settings, QWidget* parent = NULL);
+		QtRosterHeader(SettingsProvider* settings, QWidget* parent = NULL);
 		void setAvatar(const QString& path);
 
 		void setJID(const QString& jid);
diff --git a/Swift/QtUI/QtSettingsProvider.cpp b/Swift/QtUI/QtSettingsProvider.cpp
index b8ef9bb..0c4d49b 100644
--- a/Swift/QtUI/QtSettingsProvider.cpp
+++ b/Swift/QtUI/QtSettingsProvider.cpp
@@ -1,10 +1,10 @@
 /*
- * Copyright (c) 2010 Kevin Smith
+ * Copyright (c) 2010-2012 Kevin Smith
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
 
-#include "QtSettingsProvider.h"
+#include <QtSettingsProvider.h>
 
 #include <QStringList>
 #include <QFile>
@@ -18,33 +18,54 @@ QtSettingsProvider::~QtSettingsProvider() {
 
 }
 
-std::string QtSettingsProvider::getStringSetting(const std::string &settingPath) {
-	QVariant setting = settings_.value(settingPath.c_str());
-	return setting.isNull() ? "" : std::string(setting.toString().toUtf8());
+std::string QtSettingsProvider::getSetting(const Setting<std::string>& setting) {
+	QVariant variant = settings_.value(setting.getKey().c_str());
+	return variant.isNull() ? setting.getDefaultValue() : std::string(variant.toString().toUtf8());
 }
 
-void QtSettingsProvider::storeString(const std::string &settingPath, const std::string &settingValue) {
-	settings_.setValue(settingPath.c_str(), settingValue.c_str());
+void QtSettingsProvider::storeSetting(const Setting<std::string>& setting, const std::string& settingValue) {
+	bool changed = false;
+	if (getSetting(setting) != settingValue) {
+		changed = true;
+	}
+	settings_.setValue(setting.getKey().c_str(), settingValue.c_str());
+	if (changed) {
+		onSettingChanged(setting.getKey());
+	}
 	updatePermissions();
 }
 
-bool QtSettingsProvider::getBoolSetting(const std::string &settingPath, bool defaultValue) {
-	QVariant setting = settings_.value(settingPath.c_str());
-	return setting.isNull() ? defaultValue : setting.toBool();
+bool QtSettingsProvider::getSetting(const Setting<bool>& setting) {
+	QVariant variant = settings_.value(setting.getKey().c_str());
+	return variant.isNull() ? setting.getDefaultValue() : variant.toBool();
 }
 
-void QtSettingsProvider::storeBool(const std::string &settingPath, bool settingValue) {
-	settings_.setValue(settingPath.c_str(), settingValue);
+void QtSettingsProvider::storeSetting(const Setting<bool>& setting, const bool& settingValue) {
+	bool changed = false;
+	if (getSetting(setting) != settingValue) {
+		changed = true;
+	}
+	settings_.setValue(setting.getKey().c_str(), settingValue);
+	if (changed) {
+		onSettingChanged(setting.getKey());
+	}
 	updatePermissions();
 }
 
-int QtSettingsProvider::getIntSetting(const std::string &settingPath, int defaultValue) {
-	QVariant setting = settings_.value(settingPath.c_str());
-	return setting.isNull() ? defaultValue : setting.toInt();
+int QtSettingsProvider::getSetting(const Setting<int>& setting) {
+	QVariant variant = settings_.value(setting.getKey().c_str());
+	return variant.isNull() ? setting.getDefaultValue() : variant.toInt();
 }
 
-void QtSettingsProvider::storeInt(const std::string &settingPath, int settingValue) {
-	settings_.setValue(settingPath.c_str(), settingValue);
+void QtSettingsProvider::storeSetting(const Setting<int>& setting, const int& settingValue) {
+	bool changed = false;
+	if (getSetting(setting) != settingValue) {
+		changed = true;
+	}
+	settings_.setValue(setting.getKey().c_str(), settingValue);
+	if (changed) {
+		onSettingChanged(setting.getKey());
+	}
 	updatePermissions();
 }
 
@@ -90,5 +111,9 @@ void QtSettingsProvider::updatePermissions() {
 #endif
 }
 
+bool QtSettingsProvider::getIsSettingFinal(const std::string& /*settingPath*/) {
+	return false;
+}
+
 }
 
diff --git a/Swift/QtUI/QtSettingsProvider.h b/Swift/QtUI/QtSettingsProvider.h
index 8eeb854..ececa6e 100644
--- a/Swift/QtUI/QtSettingsProvider.h
+++ b/Swift/QtUI/QtSettingsProvider.h
@@ -1,13 +1,12 @@
 /*
- * Copyright (c) 2010 Kevin Smith
+ * Copyright (c) 2010-2012 Kevin Smith
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
 
-#ifndef SWIFT_QtSettingsProvider_H
-#define SWIFT_QtSettingsProvider_H
+#pragma once
 
-#include "Swift/Controllers/Settings/SettingsProvider.h"
+#include <Swift/Controllers/Settings/SettingsProvider.h>
 
 #include <QSettings>
 
@@ -17,16 +16,18 @@ class QtSettingsProvider : public SettingsProvider {
 	public:
 		QtSettingsProvider();
 		virtual ~QtSettingsProvider();
-		virtual std::string getStringSetting(const std::string &settingPath);
-		virtual void storeString(const std::string &settingPath, const std::string &settingValue);
-		virtual bool getBoolSetting(const std::string &settingPath, bool defaultValue);
-		virtual void storeBool(const std::string &settingPath, bool settingValue);
-		virtual int getIntSetting(const std::string &settingPath, int defaultValue);
-		virtual void storeInt(const std::string &settingPath, int settingValue);
+		virtual std::string getSetting(const Setting<std::string>& setting);
+		virtual void storeSetting(const Setting<std::string>& setting, const std::string& value);
+		virtual bool getSetting(const Setting<bool>& setting);
+		virtual void storeSetting(const Setting<bool>& setting, const bool& value);
+		virtual int getSetting(const Setting<int>& setting);
+		virtual void storeSetting(const Setting<int>& setting, const int& value);
 		virtual std::vector<std::string> getAvailableProfiles();
 		virtual void createProfile(const std::string& profile);
 		virtual void removeProfile(const std::string& profile);
 		QSettings* getQSettings();
+	protected:
+		virtual bool getIsSettingFinal(const std::string& settingPath);
 	
 	private:
 		void updatePermissions();
@@ -36,7 +37,7 @@ class QtSettingsProvider : public SettingsProvider {
 };
 
 }
-#endif
+
 
 
 
diff --git a/Swift/QtUI/QtSwift.cpp b/Swift/QtUI/QtSwift.cpp
index f706deb..066d22e 100644
--- a/Swift/QtUI/QtSwift.cpp
+++ b/Swift/QtUI/QtSwift.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2011 Kevin Smith
+ * Copyright (c) 2010-2012 Kevin Smith
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
@@ -12,27 +12,31 @@
 #include <boost/bind.hpp>
 #include <QMessageBox>
 #include <QApplication>
-
-#include "QtLoginWindow.h"
-#include "QtChatTabs.h"
-#include "QtSystemTray.h"
-#include "QtSoundPlayer.h"
-#include "QtSwiftUtil.h"
-#include "QtUIFactory.h"
-#include "QtChatWindowFactory.h"
+#include <qDebug.h>
+
+#include <QtLoginWindow.h>
+#include <QtChatTabs.h>
+#include <QtSystemTray.h>
+#include <QtSoundPlayer.h>
+#include <QtSwiftUtil.h>
+#include <QtUIFactory.h>
+#include <QtChatWindowFactory.h>
 #include <Swiften/Base/Log.h>
 #include <Swift/Controllers/Storages/CertificateFileStorageFactory.h>
-#include "Swift/Controllers/Storages/FileStoragesFactory.h"
-#include "SwifTools/Application/PlatformApplicationPathProvider.h"
+#include <Swift/Controllers/Storages/FileStoragesFactory.h>
+#include <SwifTools/Application/PlatformApplicationPathProvider.h>
 #include <string>
-#include "Swiften/Base/Platform.h"
-#include "Swiften/Elements/Presence.h"
-#include "Swiften/Client/Client.h"
-#include "Swift/Controllers/MainController.h"
-#include "Swift/Controllers/ApplicationInfo.h"
-#include "Swift/Controllers/BuildVersion.h"
-#include "SwifTools/AutoUpdater/AutoUpdater.h"
-#include "SwifTools/AutoUpdater/PlatformAutoUpdaterFactory.h"
+#include <Swiften/Base/Platform.h>
+#include <Swiften/Elements/Presence.h>
+#include <Swiften/Client/Client.h>
+#include <Swift/Controllers/Settings/XMLSettingsProvider.h>
+#include <Swift/Controllers/Settings/SettingsProviderHierachy.h>
+#include <Swift/Controllers/MainController.h>
+#include <Swift/Controllers/ApplicationInfo.h>
+#include <Swift/Controllers/BuildVersion.h>
+#include <SwifTools/AutoUpdater/AutoUpdater.h>
+#include <SwifTools/AutoUpdater/PlatformAutoUpdaterFactory.h>
+#include "Swiften/Base/Paths.h"
 
 #if defined(SWIFTEN_PLATFORM_WINDOWS)
 #include "WindowsNotifier.h"
@@ -77,11 +81,22 @@ po::options_description QtSwift::getOptionsDescription() {
 		("latency-debug", "Use latency debugging (unsupported)")
 		("multi-account", po::value<int>()->default_value(1), "Number of accounts to open windows for (unsupported)")
 		("start-minimized", "Don't show the login/roster window at startup")
-		("eagle-mode", "Settings more suitable for military/secure deployments")
 		;
 	return result;
 }
 
+XMLSettingsProvider* QtSwift::loadSettingsFile(const QString& fileName) {
+	QFile configFile(fileName);
+	if (configFile.exists() && configFile.open(QIODevice::ReadOnly)) {
+		QString xmlString;
+		while (!configFile.atEnd()) {
+			QByteArray line = configFile.readLine();
+			xmlString += line + "\n";
+		}
+		return new XMLSettingsProvider(Q2PSTRING(xmlString));
+	}
+	return new XMLSettingsProvider("");
+}
 
 QtSwift::QtSwift(const po::variables_map& options) : networkFactories_(&clientMainThreadCaller_), autoUpdater_(NULL), idleDetector_(&idleQuerier_, networkFactories_.getTimerFactory(), 1000) {
 	if (options.count("netbook-mode")) {
@@ -94,6 +109,12 @@ QtSwift::QtSwift(const po::variables_map& options) : networkFactories_(&clientMa
 	QCoreApplication::setOrganizationDomain(SWIFT_ORGANIZATION_DOMAIN);
 	QCoreApplication::setApplicationVersion(buildVersion);
 
+	qtSettings_ = new QtSettingsProvider();
+	xmlSettings_ = loadSettingsFile(P2QSTRING((Paths::getExecutablePath() / "system-settings.xml").string()));
+	settingsHierachy_ = new SettingsProviderHierachy();
+	settingsHierachy_->addProviderToTopOfStack(xmlSettings_);
+	settingsHierachy_->addProviderToTopOfStack(qtSettings_);
+
 	int numberOfAccounts = 1;
 	try {
 		numberOfAccounts = options["multi-account"].as<int>();
@@ -108,12 +129,10 @@ QtSwift::QtSwift(const po::variables_map& options) : networkFactories_(&clientMa
 
 	tabs_ = options.count("no-tabs") && !(splitter_ > 0) ? NULL : new QtChatTabs();
 	bool startMinimized = options.count("start-minimized") > 0;
-	bool eagleMode = options.count("eagle-mode") > 0;
-	settings_ = new QtSettingsProvider();
 	applicationPathProvider_ = new PlatformApplicationPathProvider(SWIFT_APPLICATION_NAME);
 	storagesFactory_ = new FileStoragesFactory(applicationPathProvider_->getDataDir());
 	certificateStorageFactory_ = new CertificateFileStorageFactory(applicationPathProvider_->getDataDir(), tlsFactories_.getCertificateFactory());
-	chatWindowFactory_ = new QtChatWindowFactory(splitter_, settings_, tabs_, "", &uiPreferences_);
+	chatWindowFactory_ = new QtChatWindowFactory(splitter_, settingsHierachy_, qtSettings_, tabs_, "");
 	soundPlayer_ = new QtSoundPlayer(applicationPathProvider_);
 
 	// Ugly, because the dock depends on the tray, but the temporary
@@ -154,13 +173,13 @@ QtSwift::QtSwift(const po::variables_map& options) : networkFactories_(&clientMa
 			// Don't add the first tray (see note above)
 			systemTrays_.push_back(new QtSystemTray());
 		}
-		QtUIFactory* uiFactory = new QtUIFactory(settings_, tabs_, splitter_, systemTrays_[i], chatWindowFactory_, startMinimized, eagleMode, &uiPreferences_);
+		QtUIFactory* uiFactory = new QtUIFactory(settingsHierachy_, qtSettings_, tabs_, splitter_, systemTrays_[i], chatWindowFactory_, startMinimized);
 		uiFactories_.push_back(uiFactory);
 		MainController* mainController = new MainController(
 				&clientMainThreadCaller_,
 				&networkFactories_,
 				uiFactory,
-				settings_,
+				settingsHierachy_,
 				systemTrays_[i],
 				soundPlayer_,
 				storagesFactory_,
@@ -169,8 +188,7 @@ QtSwift::QtSwift(const po::variables_map& options) : networkFactories_(&clientMa
 				notifier_,
 				uriHandler_,
 				&idleDetector_,
-				options.count("latency-debug") > 0,
-				eagleMode);
+				options.count("latency-debug") > 0);
 		mainControllers_.push_back(mainController);
 	}
 
@@ -191,7 +209,9 @@ QtSwift::~QtSwift() {
 	foreach (MainController* controller, mainControllers_) {
 		delete controller;
 	}
-	delete settings_;
+	delete settingsHierachy_;
+	delete qtSettings_;
+	delete xmlSettings_;
 	foreach (QtSystemTray* tray, systemTrays_) {
 		delete tray;
 	}
diff --git a/Swift/QtUI/QtSwift.h b/Swift/QtUI/QtSwift.h
index c808fa0..7a49fa7 100644
--- a/Swift/QtUI/QtSwift.h
+++ b/Swift/QtUI/QtSwift.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Kevin Smith
+ * Copyright (c) 2010-2012 Kevin Smith
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
@@ -23,7 +23,6 @@
 #endif
 #include "SwifTools/Idle/PlatformIdleQuerier.h"
 #include "SwifTools/Idle/ActualIdleDetector.h"
-#include <Swift/QtUI/QtUIPreferences.h>
 
 namespace po = boost::program_options;
 
@@ -48,6 +47,8 @@ namespace Swift {
 	class QtUserSearchWindowFactory;
 	class EventLoop;
 	class URIHandler;
+	class SettingsProviderHierachy;
+	class XMLSettingsProvider;
 		
 	class QtSwift : public QObject {
 		Q_OBJECT
@@ -56,6 +57,8 @@ namespace Swift {
 			static po::options_description getOptionsDescription();
 			~QtSwift();
 		private:
+			XMLSettingsProvider* loadSettingsFile(const QString& fileName);
+		private:
 			QtEventLoop clientMainThreadCaller_;
 			PlatformTLSFactories tlsFactories_;
 			BoostNetworkFactories networkFactories_;
@@ -63,7 +66,9 @@ namespace Swift {
 			std::vector<MainController*> mainControllers_;
 			std::vector<QtSystemTray*> systemTrays_;
 			std::vector<QtUIFactory*> uiFactories_;
-			QtSettingsProvider *settings_;
+			QtSettingsProvider* qtSettings_;
+			XMLSettingsProvider* xmlSettings_;
+			SettingsProviderHierachy* settingsHierachy_;
 			QSplitter* splitter_;
 			QtSoundPlayer* soundPlayer_;
 			Dock* dock_;
@@ -76,7 +81,6 @@ namespace Swift {
 			Notifier* notifier_;
 			PlatformIdleQuerier idleQuerier_;
 			ActualIdleDetector idleDetector_;
-			QtUIPreferences uiPreferences_;
 #if defined(SWIFTEN_PLATFORM_MACOSX)
 			CocoaApplication cocoaApplication_;
 #endif
diff --git a/Swift/QtUI/QtUIFactory.cpp b/Swift/QtUI/QtUIFactory.cpp
index 88da781..c686442 100644
--- a/Swift/QtUI/QtUIFactory.cpp
+++ b/Swift/QtUI/QtUIFactory.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Remko Tronçon
+ * Copyright (c) 2010-2012 Remko Tronçon
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
@@ -25,13 +25,13 @@
 #include "QtContactEditWindow.h"
 #include "QtAdHocCommandWindow.h"
 #include "QtFileTransferListWidget.h"
-
-#define CHATWINDOW_FONT_SIZE "chatWindowFontSize"
+#include <Swift/Controllers/Settings/SettingsProviderHierachy.h>
+#include <Swift/QtUI/QtUISettingConstants.h>
 
 namespace Swift {
 
-QtUIFactory::QtUIFactory(QtSettingsProvider* settings, QtChatTabs* tabs, QSplitter* netbookSplitter, QtSystemTray* systemTray, QtChatWindowFactory* chatWindowFactory, bool startMinimized, bool eagleMode, QtUIPreferences* uiPreferences) : settings(settings), tabs(tabs), netbookSplitter(netbookSplitter), systemTray(systemTray), chatWindowFactory(chatWindowFactory), lastMainWindow(NULL), loginWindow(NULL), startMinimized(startMinimized), eagleMode(eagleMode), uiPreferences(uiPreferences)  {
-	chatFontSize = settings->getIntSetting(CHATWINDOW_FONT_SIZE, 0);
+QtUIFactory::QtUIFactory(SettingsProviderHierachy* settings, QtSettingsProvider* qtOnlySettings, QtChatTabs* tabs, QSplitter* netbookSplitter, QtSystemTray* systemTray, QtChatWindowFactory* chatWindowFactory, bool startMinimized) : settings(settings), qtOnlySettings(qtOnlySettings), tabs(tabs), netbookSplitter(netbookSplitter), systemTray(systemTray), chatWindowFactory(chatWindowFactory), lastMainWindow(NULL), loginWindow(NULL), startMinimized(startMinimized) {
+	chatFontSize = settings->getSetting(QtUISettingConstants::CHATWINDOW_FONT_SIZE);
 }
 
 XMLConsoleWidget* QtUIFactory::createXMLConsoleWidget() {
@@ -55,19 +55,19 @@ FileTransferListWidget* QtUIFactory::createFileTransferListWidget() {
 }
 
 MainWindow* QtUIFactory::createMainWindow(UIEventStream* eventStream) {
-	lastMainWindow  = new QtMainWindow(settings, eventStream, uiPreferences, loginWindow->getMenus());
+	lastMainWindow  = new QtMainWindow(settings, eventStream, loginWindow->getMenus());
 	return lastMainWindow;
 }
 
 LoginWindow* QtUIFactory::createLoginWindow(UIEventStream* eventStream) {
-	loginWindow = new QtLoginWindow(eventStream, eagleMode);
+	loginWindow = new QtLoginWindow(eventStream, settings);
 	if (netbookSplitter) {
 		netbookSplitter->insertWidget(0, loginWindow);
 	}
 	connect(systemTray, SIGNAL(clicked()), loginWindow, SLOT(bringToFront()));
 
 #ifndef SWIFT_MOBILE
-	QVariant loginWindowGeometryVariant = settings->getQSettings()->value("loginWindowGeometry");
+	QVariant loginWindowGeometryVariant = qtOnlySettings->getQSettings()->value("loginWindowGeometry");
 	if (loginWindowGeometryVariant.isValid()) {
 		loginWindow->restoreGeometry(loginWindowGeometryVariant.toByteArray());
 	}
@@ -78,7 +78,7 @@ LoginWindow* QtUIFactory::createLoginWindow(UIEventStream* eventStream) {
 }
 
 void QtUIFactory::handleLoginWindowGeometryChanged() {
-	settings->getQSettings()->setValue("loginWindowGeometry", loginWindow->saveGeometry());
+	qtOnlySettings->getQSettings()->setValue("loginWindowGeometry", loginWindow->saveGeometry());
 }
 
 EventWindow* QtUIFactory::createEventWindow() {
@@ -115,7 +115,7 @@ ChatWindow* QtUIFactory::createChatWindow(const JID& contact, UIEventStream* eve
 
 void QtUIFactory::handleChatWindowFontResized(int size) {
 	chatFontSize = size;
-	settings->storeInt(CHATWINDOW_FONT_SIZE, size);
+	settings->storeSetting(QtUISettingConstants::CHATWINDOW_FONT_SIZE, size);
 }
 
 UserSearchWindow* QtUIFactory::createUserSearchWindow(UserSearchWindow::Type type, UIEventStream* eventStream, const std::set<std::string>& groups) {
diff --git a/Swift/QtUI/QtUIFactory.h b/Swift/QtUI/QtUIFactory.h
index db33365..c9e2f2e 100644
--- a/Swift/QtUI/QtUIFactory.h
+++ b/Swift/QtUI/QtUIFactory.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Remko Tronçon
+ * Copyright (c) 2010-2012 Remko Tronçon
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
@@ -10,12 +10,12 @@
 #include <QPointer>
 
 #include <Swift/Controllers/UIInterfaces/UIFactory.h>
-#include <Swift/QtUI/QtUIPreferences.h>
 
 class QSplitter;
 
 namespace Swift {
 	class QtSettingsProvider;
+	class SettingsProviderHierachy;
 	class QtChatTabs;
 	class QtSystemTray;
 	class QtLoginWindow;
@@ -27,7 +27,7 @@ namespace Swift {
 	class QtUIFactory : public QObject, public UIFactory {
 			Q_OBJECT
 		public:
-			QtUIFactory(QtSettingsProvider* settings, QtChatTabs* tabs, QSplitter* netbookSplitter, QtSystemTray* systemTray, QtChatWindowFactory* chatWindowFactory, bool startMinimized, bool eagleMode, QtUIPreferences* uiPreferences);
+			QtUIFactory(SettingsProviderHierachy* settings, QtSettingsProvider* qtOnlySettings, QtChatTabs* tabs, QSplitter* netbookSplitter, QtSystemTray* systemTray, QtChatWindowFactory* chatWindowFactory, bool startMinimized);
 
 			virtual XMLConsoleWidget* createXMLConsoleWidget();
 			virtual MainWindow* createMainWindow(UIEventStream* eventStream);
@@ -48,7 +48,8 @@ namespace Swift {
 			void handleChatWindowFontResized(int);
 
 		private:
-			QtSettingsProvider* settings;
+			SettingsProviderHierachy* settings;
+			QtSettingsProvider* qtOnlySettings;
 			QtChatTabs* tabs;
 			QSplitter* netbookSplitter;
 			QtSystemTray* systemTray;
@@ -58,7 +59,5 @@ namespace Swift {
 			std::vector<QPointer<QtChatWindow> > chatWindows;
 			bool startMinimized;
 			int chatFontSize;
-			bool eagleMode;
-			QtUIPreferences* uiPreferences;
 	};
 }
diff --git a/Swift/QtUI/QtUIPreferences.cpp b/Swift/QtUI/QtUIPreferences.cpp
deleted file mode 100644
index 6662e71..0000000
--- a/Swift/QtUI/QtUIPreferences.cpp
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (c) 2011 Kevin Smith
- * Licensed under the GNU General Public License v3.
- * See Documentation/Licenses/GPLv3.txt for more information.
- */
-
-#include <Swift/QtUI/QtUIPreferences.h>
-
-namespace Swift {
-QtUIPreferences::QtUIPreferences() : compactRosters_(false) {
-	
-}
-
-QtUIPreferences::~QtUIPreferences() {
-	
-}
-
-void QtUIPreferences::setCompactRosters(bool compact) {
-	compactRosters_ = compact;
-	emit onCompactRostersChanged(compact);
-}
-
-bool QtUIPreferences::getCompactRosters() {
-	return compactRosters_;
-}
-
-}
diff --git a/Swift/QtUI/QtUIPreferences.h b/Swift/QtUI/QtUIPreferences.h
deleted file mode 100644
index e537e80..0000000
--- a/Swift/QtUI/QtUIPreferences.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (c) 2011 Kevin Smith
- * Licensed under the GNU General Public License v3.
- * See Documentation/Licenses/GPLv3.txt for more information.
- */
-
-#pragma once
-
-#include <QObject>
-
-namespace Swift {
-	class QtUIPreferences : public QObject {
-		Q_OBJECT
-		public:
-			QtUIPreferences();
-			~QtUIPreferences();
-			bool getCompactRosters();
-		public slots:
-			void setCompactRosters(bool compact);
-		signals:
-			void onCompactRostersChanged(bool /*now*/);
-		private:
-			bool compactRosters_;
-	};
-}
\ No newline at end of file
diff --git a/Swift/QtUI/QtUISettingConstants.cpp b/Swift/QtUI/QtUISettingConstants.cpp
new file mode 100644
index 0000000..046ccc1
--- /dev/null
+++ b/Swift/QtUI/QtUISettingConstants.cpp
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2012 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swift/QtUI/QtUISettingConstants.h>
+
+namespace Swift {
+
+const SettingsProvider::Setting<bool> QtUISettingConstants::COMPACT_ROSTER("compactRoster", false);
+const SettingsProvider::Setting<std::string> QtUISettingConstants::CLICKTHROUGH_BANNER("clickthroughBanner", "");
+const SettingsProvider::Setting<int> QtUISettingConstants::CURRENT_ROSTER_TAB("currentRosterTab", 0);
+const SettingsProvider::Setting<bool> QtUISettingConstants::SHOW_NICK_IN_ROSTER_HEADER("showNickInRosterHeader", true);
+const SettingsProvider::Setting<int> QtUISettingConstants::CHATWINDOW_FONT_SIZE("chatWindowFontSize", 0);
+}
diff --git a/Swift/QtUI/QtUISettingConstants.h b/Swift/QtUI/QtUISettingConstants.h
new file mode 100644
index 0000000..82f98bb
--- /dev/null
+++ b/Swift/QtUI/QtUISettingConstants.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2012 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <Swift/Controllers/Settings/SettingsProvider.h>
+
+namespace Swift {
+	class QtUISettingConstants {
+		public:
+			static const SettingsProvider::Setting<bool> COMPACT_ROSTER;
+			static const SettingsProvider::Setting<std::string> CLICKTHROUGH_BANNER;
+			static const SettingsProvider::Setting<int> CURRENT_ROSTER_TAB;
+			static const SettingsProvider::Setting<bool> SHOW_NICK_IN_ROSTER_HEADER;
+			static const SettingsProvider::Setting<int> CHATWINDOW_FONT_SIZE;
+	};
+}
diff --git a/Swift/QtUI/Roster/QtOccupantListWidget.cpp b/Swift/QtUI/Roster/QtOccupantListWidget.cpp
index f864919..0b3722c 100644
--- a/Swift/QtUI/Roster/QtOccupantListWidget.cpp
+++ b/Swift/QtUI/Roster/QtOccupantListWidget.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011 Kevin Smith
+ * Copyright (c) 2011-2012 Kevin Smith
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
@@ -19,7 +19,7 @@
 
 namespace Swift {
 
-QtOccupantListWidget::QtOccupantListWidget(UIEventStream* eventStream, QtUIPreferences* uiPreferences, QWidget* parent) : QtTreeWidget(eventStream, uiPreferences, parent) {
+QtOccupantListWidget::QtOccupantListWidget(UIEventStream* eventStream, SettingsProvider* settings, QWidget* parent) : QtTreeWidget(eventStream, settings, parent) {
 
 }
 
diff --git a/Swift/QtUI/Roster/QtOccupantListWidget.h b/Swift/QtUI/Roster/QtOccupantListWidget.h
index da7c463..729115a 100644
--- a/Swift/QtUI/Roster/QtOccupantListWidget.h
+++ b/Swift/QtUI/Roster/QtOccupantListWidget.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011 Kevin Smith
+ * Copyright (c) 2011-2012 Kevin Smith
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
@@ -12,12 +12,12 @@
 #include "Swift/Controllers/UIInterfaces/ChatWindow.h"
 
 namespace Swift {
-class QtUIPreferences;
+class SettingsProvider;
 
 class QtOccupantListWidget : public QtTreeWidget {
 	Q_OBJECT
 	public:
-		QtOccupantListWidget(UIEventStream* eventStream, QtUIPreferences* uiPreferences, QWidget* parent = 0);
+		QtOccupantListWidget(UIEventStream* eventStream, SettingsProvider* settings, QWidget* parent = 0);
 		virtual ~QtOccupantListWidget();
 		void setAvailableOccupantActions(const std::vector<ChatWindow::OccupantAction>& actions);
 		boost::signal<void (ChatWindow::OccupantAction, ContactRosterItem*)> onOccupantActionSelected;
diff --git a/Swift/QtUI/Roster/QtRosterWidget.cpp b/Swift/QtUI/Roster/QtRosterWidget.cpp
index ac4b500..e3fee24 100644
--- a/Swift/QtUI/Roster/QtRosterWidget.cpp
+++ b/Swift/QtUI/Roster/QtRosterWidget.cpp
@@ -23,7 +23,7 @@
 
 namespace Swift {
 
-QtRosterWidget::QtRosterWidget(UIEventStream* eventStream, QtUIPreferences* uiPreferences, QWidget* parent) : QtTreeWidget(eventStream, uiPreferences, parent) {
+QtRosterWidget::QtRosterWidget(UIEventStream* eventStream, SettingsProvider* settings, QWidget* parent) : QtTreeWidget(eventStream, settings, parent) {
 
 }
 
diff --git a/Swift/QtUI/Roster/QtRosterWidget.h b/Swift/QtUI/Roster/QtRosterWidget.h
index 01f4726..549fe92 100644
--- a/Swift/QtUI/Roster/QtRosterWidget.h
+++ b/Swift/QtUI/Roster/QtRosterWidget.h
@@ -14,7 +14,7 @@ class QtUIPreferences;
 class QtRosterWidget : public QtTreeWidget {
 	Q_OBJECT
 	public:
-		QtRosterWidget(UIEventStream* eventStream, QtUIPreferences* uiPreferences, QWidget* parent = 0);
+		QtRosterWidget(UIEventStream* eventStream, SettingsProvider* settings, QWidget* parent = 0);
 		virtual ~QtRosterWidget();
 	public slots:
 		void handleEditUserActionTriggered(bool checked);
diff --git a/Swift/QtUI/Roster/QtTreeWidget.cpp b/Swift/QtUI/Roster/QtTreeWidget.cpp
index 4382125..5fdf138 100644
--- a/Swift/QtUI/Roster/QtTreeWidget.cpp
+++ b/Swift/QtUI/Roster/QtTreeWidget.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Kevin Smith
+ * Copyright (c) 2010-2012 Kevin Smith
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
@@ -7,6 +7,7 @@
 #include "Roster/QtTreeWidget.h"
 
 #include <boost/smart_ptr/make_shared.hpp>
+#include <boost/bind.hpp>
 
 #include <QUrl>
 
@@ -17,16 +18,17 @@
 #include <Swift/Controllers/UIEvents/RequestChatUIEvent.h>
 #include <Swift/Controllers/UIEvents/SendFileUIEvent.h>
 #include <QtSwiftUtil.h>
-#include <Swift/QtUI/QtUIPreferences.h>
+#include <Swift/Controllers/Settings/SettingsProvider.h>
+#include <Swift/QtUI/QtUISettingConstants.h>
 
 namespace Swift {
 
-QtTreeWidget::QtTreeWidget(UIEventStream* eventStream, QtUIPreferences* uiPreferences, QWidget* parent) : QTreeView(parent) {
+QtTreeWidget::QtTreeWidget(UIEventStream* eventStream, SettingsProvider* settings, QWidget* parent) : QTreeView(parent) {
 	eventStream_ = eventStream;
-	uiPreferences_ = uiPreferences;
+	settings_ = settings;
 	model_ = new RosterModel(this);
 	setModel(model_);
-	delegate_ = new RosterDelegate(this, uiPreferences_->getCompactRosters());
+	delegate_ = new RosterDelegate(this, settings_->getSetting(QtUISettingConstants::COMPACT_ROSTER));
 	setItemDelegate(delegate_);
 	setHeaderHidden(true);
 #ifdef SWIFT_PLATFORM_MACOSX
@@ -45,17 +47,21 @@ QtTreeWidget::QtTreeWidget(UIEventStream* eventStream, QtUIPreferences* uiPrefer
 	connect(this, SIGNAL(expanded(const QModelIndex&)), this, SLOT(handleExpanded(const QModelIndex&)));
 	connect(this, SIGNAL(collapsed(const QModelIndex&)), this, SLOT(handleCollapsed(const QModelIndex&)));
 	connect(this, SIGNAL(clicked(const QModelIndex&)), this, SLOT(handleClicked(const QModelIndex&)));
-	connect(uiPreferences_, SIGNAL(onCompactRostersChanged(bool)), this, SLOT(handleCompactRostersToggled(bool)));
+
+	settings_->onSettingChanged.connect(boost::bind(&QtTreeWidget::handleSettingChanged, this, _1));
 }
 
 QtTreeWidget::~QtTreeWidget() {
+	settings_->onSettingChanged.disconnect(boost::bind(&QtTreeWidget::handleSettingChanged, this, _1));
 	delete model_;
 	delete delegate_;
 }
 
-void QtTreeWidget::handleCompactRostersToggled(bool compact) {
-	delegate_->setCompact(compact);
-	repaint();
+void QtTreeWidget::handleSettingChanged(const std::string& setting) {
+	if (setting == QtUISettingConstants::COMPACT_ROSTER.getKey()) {
+		delegate_->setCompact(settings_->getSetting(QtUISettingConstants::COMPACT_ROSTER));
+		repaint();
+	}
 }
 
 void QtTreeWidget::setRosterModel(Roster* roster) {
diff --git a/Swift/QtUI/Roster/QtTreeWidget.h b/Swift/QtUI/Roster/QtTreeWidget.h
index 705c039..7c10a6a 100644
--- a/Swift/QtUI/Roster/QtTreeWidget.h
+++ b/Swift/QtUI/Roster/QtTreeWidget.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Kevin Smith
+ * Copyright (c) 2010-2012 Kevin Smith
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
@@ -16,12 +16,12 @@
 
 namespace Swift {
 class UIEventStream;
-class QtUIPreferences;
+class SettingsProvider;
 
 class QtTreeWidget : public QTreeView{
 	Q_OBJECT
 	public:
-		QtTreeWidget(UIEventStream* eventStream, QtUIPreferences* uiPreferences, QWidget* parent = 0);
+		QtTreeWidget(UIEventStream* eventStream, SettingsProvider* settings, QWidget* parent = 0);
 		~QtTreeWidget();
 		void show();
 		QtTreeWidgetItem* getRoot();
@@ -35,7 +35,7 @@ class QtTreeWidget : public QTreeView{
 		void handleExpanded(const QModelIndex&);
 		void handleCollapsed(const QModelIndex&);
 		void handleClicked(const QModelIndex&);
-		void handleCompactRostersToggled(bool compact);
+		void handleSettingChanged(const std::string& setting);
 	protected:
 		void dragEnterEvent(QDragEnterEvent* event);
 		void dropEvent(QDropEvent* event);
@@ -55,7 +55,7 @@ class QtTreeWidget : public QTreeView{
 		Roster* roster_;
 		RosterDelegate* delegate_;
 		QtTreeWidgetItem* treeRoot_;
-		QtUIPreferences* uiPreferences_;
+		SettingsProvider* settings_;
 };
 
 }
diff --git a/Swift/QtUI/SConscript b/Swift/QtUI/SConscript
index 2283001..d37958f 100644
--- a/Swift/QtUI/SConscript
+++ b/Swift/QtUI/SConscript
@@ -72,7 +72,7 @@ sources = [
     "QtNameWidget.cpp",
     "QtSettingsProvider.cpp",
     "QtStatusWidget.cpp",
-		"QtScaledAvatarCache.cpp",
+    "QtScaledAvatarCache.cpp",
     "QtSwift.cpp",
     "QtURIHandler.cpp",
     "QtChatView.cpp",
@@ -99,7 +99,7 @@ sources = [
     "SystemMessageSnippet.cpp",
     "QtElidingLabel.cpp",
     "QtFormWidget.cpp",
-	"QtFormResultItemModel.cpp",
+    "QtFormResultItemModel.cpp",
     "QtLineEdit.cpp",
     "QtJoinMUCWindow.cpp",
     "Roster/RosterModel.cpp",
@@ -140,7 +140,7 @@ sources = [
     "QtFileTransferJSBridge.cpp",
     "QtMUCConfigurationWindow.cpp",
     "QtAffiliationEditor.cpp",
-    "QtUIPreferences.cpp"
+    "QtUISettingConstants.cpp"
   ]
 
 myenv["SWIFT_VERSION"] = Version.getBuildVersion(env.Dir("#").abspath, "swift")
-- 
cgit v0.10.2-6-g49f6