From 5df9d52d48b56a5d8f36a45ced0393c99473f536 Mon Sep 17 00:00:00 2001
From: William Todd Stinson <stinson@lindenlab.com>
Date: Wed, 12 Dec 2012 18:49:07 -0800
Subject: [PATCH] CHUI-499: Refactoring the persistent notification storage so
 that I can reuse the functionality for do-not-disturb mode.

---
 indra/llui/llnotifications.h                  |   2 +-
 indra/newview/CMakeLists.txt                  |   2 +
 indra/newview/llchannelmanager.cpp            |   2 +-
 indra/newview/llnotificationstorage.cpp       | 203 +++--------------
 indra/newview/llnotificationstorage.h         |  34 ++-
 .../llpersistentnotificationstorage.cpp       | 210 ++++++++++++++++++
 .../newview/llpersistentnotificationstorage.h |  63 ++++++
 7 files changed, 322 insertions(+), 194 deletions(-)
 create mode 100644 indra/newview/llpersistentnotificationstorage.cpp
 create mode 100644 indra/newview/llpersistentnotificationstorage.h

diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h
index 056a316d401..8bb79b57e3c 100644
--- a/indra/llui/llnotifications.h
+++ b/indra/llui/llnotifications.h
@@ -1026,7 +1026,7 @@ class LLPostponedNotification
 
 // Stores only persistent notifications.
 // Class users can use connectChanged() to process persistent notifications
-// (see LLNotificationStorage for example).
+// (see LLPersistentNotificationStorage for example).
 class LLPersistentNotificationChannel : public LLNotificationChannel
 {
 	LOG_CLASS(LLPersistentNotificationChannel);
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index c9176d71fbd..da1d96414b6 100755
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -448,6 +448,7 @@ set(viewer_SOURCE_FILES
     llpathfindingobject.cpp
     llpathfindingobjectlist.cpp
     llpathfindingpathtool.cpp
+    llpersistentnotificationstorage.cpp
     llphysicsmotion.cpp
     llphysicsshapebuilderutil.cpp
     llplacesinventorybridge.cpp
@@ -1021,6 +1022,7 @@ set(viewer_HEADER_FILES
     llpathfindingobject.h
     llpathfindingobjectlist.h
     llpathfindingpathtool.h
+    llpersistentnotificationstorage.h
     llphysicsmotion.h
     llphysicsshapebuilderutil.h
     llplacesinventorybridge.h
diff --git a/indra/newview/llchannelmanager.cpp b/indra/newview/llchannelmanager.cpp
index 987651fc804..79e2d376eaf 100644
--- a/indra/newview/llchannelmanager.cpp
+++ b/indra/newview/llchannelmanager.cpp
@@ -29,7 +29,7 @@
 #include "llchannelmanager.h"
 
 #include "llappviewer.h"
-#include "llnotificationstorage.h"
+#include "llpersistentnotificationstorage.h"
 #include "llviewercontrol.h"
 #include "llviewerwindow.h"
 #include "llrootview.h"
diff --git a/indra/newview/llnotificationstorage.cpp b/indra/newview/llnotificationstorage.cpp
index a31b95811e1..d25a2120598 100644
--- a/indra/newview/llnotificationstorage.cpp
+++ b/indra/newview/llnotificationstorage.cpp
@@ -25,207 +25,68 @@
 */
 
 #include "llviewerprecompiledheaders.h" // must be first include
+
 #include "llnotificationstorage.h"
 
-#include "llxmlnode.h" // for linux compilers
+#include <string>
 
-#include "llchannelmanager.h"
-#include "llscreenchannel.h"
-#include "llscriptfloater.h"
+#include "llerror.h"
+#include "llfile.h"
+#include "llpointer.h"
+#include "llsd.h"
 #include "llsdserialize.h"
-#include "llviewermessage.h"
-
-//////////////////////////////////////////////////////////////////////////
-
-class LLResponderRegistry
-{
-public:
-
-	static void registerResponders();
-
-	static LLNotificationResponderInterface* createResponder(const std::string& notification_name, const LLSD& params);
-
-private:
-
-	template<typename RESPONDER_TYPE>
-	static LLNotificationResponderInterface* create(const LLSD& params)
-	{
-		RESPONDER_TYPE* responder = new RESPONDER_TYPE();
-		responder->fromLLSD(params);
-		return responder;
-	}
-
-	typedef boost::function<LLNotificationResponderInterface* (const LLSD& params)> responder_constructor_t;
-
-	static void add(const std::string& notification_name, const responder_constructor_t& ctr);
-
-private:
-
-	typedef std::map<std::string, responder_constructor_t> build_map_t;
-
-	static build_map_t sBuildMap;
-};
 
-//////////////////////////////////////////////////////////////////////////
 
-LLPersistentNotificationStorage::LLPersistentNotificationStorage()
+LLNotificationStorage::LLNotificationStorage(std::string pFileName)
+	: mFileName(pFileName)
 {
-	mFileName = gDirUtilp->getExpandedFilename ( LL_PATH_PER_SL_ACCOUNT, "open_notifications.xml" );
 }
 
-bool LLPersistentNotificationStorage::onPersistentChannelChanged(const LLSD& payload)
+LLNotificationStorage::~LLNotificationStorage()
 {
-	// we ignore "load" messages, but rewrite the persistence file on any other
-	const std::string sigtype = payload["sigtype"].asString();
-	if ("load" != sigtype)
-	{
-		saveNotifications();
-	}
-	return false;
 }
 
-static LLFastTimer::DeclareTimer FTM_SAVE_NOTIFICATIONS("Save Notifications");
-
-void LLPersistentNotificationStorage::saveNotifications()
+bool LLNotificationStorage::writeNotifications(const LLSD& pNotificationData) const
 {
-	LLFastTimer _(FTM_SAVE_NOTIFICATIONS);
-
-	llofstream notify_file(mFileName.c_str());
-	if (!notify_file.is_open())
-	{
-		llwarns << "Failed to open " << mFileName << llendl;
-		return;
-	}
 
-	LLSD output;
-	LLSD& data = output["data"];
+	llofstream notifyFile(mFileName.c_str());
+	bool didFileOpen = notifyFile.is_open();
 
-	boost::intrusive_ptr<LLPersistentNotificationChannel> history_channel = boost::dynamic_pointer_cast<LLPersistentNotificationChannel>(LLNotifications::instance().getChannel("Persistent"));
-	if (!history_channel)
+	if (!didFileOpen)
 	{
-		return;
+		LL_WARNS("LLNotificationStorage") << "Failed to open file '" << mFileName << "'" << LL_ENDL;
 	}
-
-	for ( std::vector<LLNotificationPtr>::iterator it = history_channel->beginHistory(), end_it = history_channel->endHistory();
-		it != end_it;
-		++it)
+	else
 	{
-		LLNotificationPtr notification = *it;
-
-		// After a notification was placed in Persist channel, it can become
-		// responded, expired or canceled - in this case we are should not save it
-		if(notification->isRespondedTo() || notification->isCancelled()
-			|| notification->isExpired())
-		{
-			continue;
-		}
-
-		data.append(notification->asLLSD());
+		LLPointer<LLSDFormatter> formatter = new LLSDXMLFormatter();
+		formatter->format(pNotificationData, notifyFile, LLSDFormatter::OPTIONS_PRETTY);
 	}
 
-	LLPointer<LLSDFormatter> formatter = new LLSDXMLFormatter();
-	formatter->format(output, notify_file, LLSDFormatter::OPTIONS_PRETTY);
+	return didFileOpen;
 }
 
-static LLFastTimer::DeclareTimer FTM_LOAD_NOTIFICATIONS("Load Notifications");
-
-void LLPersistentNotificationStorage::loadNotifications()
+bool LLNotificationStorage::readNotifications(LLSD& pNotificationData) const
 {
-	LLFastTimer _(FTM_LOAD_NOTIFICATIONS);
-	LLResponderRegistry::registerResponders();
+	bool didFileRead;
 
-	LLNotifications::instance().getChannel("Persistent")->
-		connectChanged(boost::bind(&LLPersistentNotificationStorage::onPersistentChannelChanged, this, _1));
+	pNotificationData.clear();
 
-	llifstream notify_file(mFileName.c_str());
-	if (!notify_file.is_open())
+	llifstream notifyFile(mFileName.c_str());
+	didFileRead = notifyFile.is_open();
+	if (!didFileRead)
 	{
-		llwarns << "Failed to open " << mFileName << llendl;
-		return;
+		LL_WARNS("LLNotificationStorage") << "Failed to open file '" << mFileName << "'" << LL_ENDL;
 	}
-
-	LLSD input;
-	LLPointer<LLSDParser> parser = new LLSDXMLParser();
-	if (parser->parse(notify_file, input, LLSDSerialize::SIZE_UNLIMITED) < 0)
+	else
 	{
-		llwarns << "Failed to parse open notifications" << llendl;
-		return;
-	}
-
-	if (input.isUndefined())
-	{
-		return;
-	}
-
-	LLSD& data = input["data"];
-	if (data.isUndefined())
-	{
-		return;
-	}
-
-	using namespace LLNotificationsUI;
-	LLScreenChannel* notification_channel = dynamic_cast<LLScreenChannel*>(LLChannelManager::getInstance()->
-		findChannelByID(LLUUID(gSavedSettings.getString("NotificationChannelUUID"))));
-
-	LLNotifications& instance = LLNotifications::instance();
-
-	for (LLSD::array_const_iterator notification_it = data.beginArray();
-		notification_it != data.endArray();
-		++notification_it)
-	{
-		LLSD notification_params = *notification_it;
-		LLNotificationPtr notification(new LLNotification(notification_params));
-
-		LLNotificationResponderPtr responder(LLResponderRegistry::
-			createResponder(notification_params["name"], notification_params["responder"]));
-		notification->setResponseFunctor(responder);
-
-		instance.add(notification);
-
-		// hide script floaters so they don't confuse the user and don't overlap startup toast
-		LLScriptFloaterManager::getInstance()->setFloaterVisible(notification->getID(), false);
-
-		if(notification_channel)
+		LLPointer<LLSDParser> parser = new LLSDXMLParser();
+		didFileRead = (parser->parse(notifyFile, pNotificationData, LLSDSerialize::SIZE_UNLIMITED) >= 0);
+		if (!didFileRead)
 		{
-			// hide saved toasts so they don't confuse the user
-			notification_channel->hideToast(notification->getID());
+			LL_WARNS("LLNotificationStorage") << "Failed to parse open notifications from file '" << mFileName 
+				<< "'" << LL_ENDL;
 		}
 	}
-}
-
-//////////////////////////////////////////////////////////////////////////
-//////////////////////////////////////////////////////////////////////////
-//////////////////////////////////////////////////////////////////////////
 
-LLResponderRegistry::build_map_t LLResponderRegistry::sBuildMap;
-
-void LLResponderRegistry::registerResponders()
-{
-	sBuildMap.clear();
-
-	add("ObjectGiveItem", &create<LLOfferInfo>);
-	add("UserGiveItem", &create<LLOfferInfo>);
-}
-
-LLNotificationResponderInterface* LLResponderRegistry::createResponder(const std::string& notification_name, const LLSD& params)
-{
-	build_map_t::const_iterator it = sBuildMap.find(notification_name);
-	if(sBuildMap.end() == it)
-	{
-		return NULL;
-	}
-	responder_constructor_t ctr = it->second;
-	return ctr(params);
+	return didFileRead;
 }
-
-void LLResponderRegistry::add(const std::string& notification_name, const responder_constructor_t& ctr)
-{
-	if(sBuildMap.find(notification_name) != sBuildMap.end())
-	{
-		llwarns << "Responder is already registered : " << notification_name << llendl;
-		llassert(!"Responder already registered");
-	}
-	sBuildMap[notification_name] = ctr;
-}
-
-// EOF
diff --git a/indra/newview/llnotificationstorage.h b/indra/newview/llnotificationstorage.h
index 8635c797c0c..ab4da4e73f1 100644
--- a/indra/newview/llnotificationstorage.h
+++ b/indra/newview/llnotificationstorage.h
@@ -27,32 +27,24 @@
 #ifndef LL_NOTIFICATIONSTORAGE_H
 #define LL_NOTIFICATIONSTORAGE_H
 
-#include "llnotifications.h"
-
-// Class that saves not responded(unread) notifications.
-// Unread notifications are saved in open_notifications.xml in SL account folder
-//
-// Notifications that should be saved(if unread) are marked with persist="true" in notifications.xml
-// Notifications using functor responders are saved automatically (see llviewermessage.cpp
-// lure_callback_reg for example).
-// Notifications using object responders(LLOfferInfo) need additional tuning. Responder object should
-// be a) serializable(implement LLNotificationResponderInterface),
-// b) registered with LLResponderRegistry (found in llnotificationstorage.cpp).
-class LLPersistentNotificationStorage : public LLSingleton<LLPersistentNotificationStorage>
-{
-	LOG_CLASS(LLPersistentNotificationStorage);
-public:
+#include <string>
 
-	LLPersistentNotificationStorage();
+#include "llerror.h"
 
-	void saveNotifications();
+class LLSD;
 
-	void loadNotifications();
-
-private:
+class LLNotificationStorage
+{
+	LOG_CLASS(LLNotificationStorage);
+public:
+	LLNotificationStorage(std::string pFileName);
+	~LLNotificationStorage();
 
-	bool onPersistentChannelChanged(const LLSD& payload);
+protected:
+	bool writeNotifications(const LLSD& pNotificationData) const;
+	bool readNotifications(LLSD& pNotificationData) const;
 
+private:
 	std::string mFileName;
 };
 
diff --git a/indra/newview/llpersistentnotificationstorage.cpp b/indra/newview/llpersistentnotificationstorage.cpp
new file mode 100644
index 00000000000..7aaad64fd78
--- /dev/null
+++ b/indra/newview/llpersistentnotificationstorage.cpp
@@ -0,0 +1,210 @@
+/** 
+* @file llpersistentnotificationstorage.cpp
+* @brief Implementation of llpersistentnotificationstorage
+* @author Stinson@lindenlab.com
+*
+* $LicenseInfo:firstyear=2012&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2012, Linden Research, Inc.
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation;
+* version 2.1 of the License only.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*
+* Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+* $/LicenseInfo$
+*/
+
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llpersistentnotificationstorage.h"
+
+#include "llchannelmanager.h"
+#include "llnotificationstorage.h"
+#include "llscreenchannel.h"
+#include "llscriptfloater.h"
+#include "llviewermessage.h"
+
+class LLResponderRegistry
+{
+public:
+
+	static void registerResponders();
+
+	static LLNotificationResponderInterface* createResponder(const std::string& notification_name, const LLSD& params);
+
+protected:
+
+private:
+	template<typename RESPONDER_TYPE>
+	static LLNotificationResponderInterface* create(const LLSD& params)
+	{
+		RESPONDER_TYPE* responder = new RESPONDER_TYPE();
+		responder->fromLLSD(params);
+		return responder;
+	}
+
+	typedef boost::function<LLNotificationResponderInterface* (const LLSD& params)> responder_constructor_t;
+
+	static void add(const std::string& notification_name, const responder_constructor_t& ctr);
+
+	typedef std::map<std::string, responder_constructor_t> build_map_t;
+
+	static build_map_t sBuildMap;
+};
+
+LLPersistentNotificationStorage::LLPersistentNotificationStorage()
+	: LLSingleton<LLPersistentNotificationStorage>()
+	, LLNotificationStorage(gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "open_notifications.xml"))
+{
+}
+
+LLPersistentNotificationStorage::~LLPersistentNotificationStorage()
+{
+}
+
+static LLFastTimer::DeclareTimer FTM_SAVE_NOTIFICATIONS("Save Notifications");
+
+void LLPersistentNotificationStorage::saveNotifications()
+{
+	LLFastTimer _(FTM_SAVE_NOTIFICATIONS);
+
+	boost::intrusive_ptr<LLPersistentNotificationChannel> history_channel = boost::dynamic_pointer_cast<LLPersistentNotificationChannel>(LLNotifications::instance().getChannel("Persistent"));
+	if (!history_channel)
+	{
+		return;
+	}
+
+	LLSD output = LLSD::emptyMap();
+	LLSD& data = output["data"];
+
+	for ( std::vector<LLNotificationPtr>::iterator it = history_channel->beginHistory(), end_it = history_channel->endHistory();
+		it != end_it;
+		++it)
+	{
+		LLNotificationPtr notification = *it;
+
+		// After a notification was placed in Persist channel, it can become
+		// responded, expired or canceled - in this case we are should not save it
+		if(notification->isRespondedTo() || notification->isCancelled()
+			|| notification->isExpired())
+		{
+			continue;
+		}
+
+		data.append(notification->asLLSD());
+	}
+
+	writeNotifications(output);
+}
+
+static LLFastTimer::DeclareTimer FTM_LOAD_NOTIFICATIONS("Load Notifications");
+
+void LLPersistentNotificationStorage::loadNotifications()
+{
+	LLFastTimer _(FTM_LOAD_NOTIFICATIONS);
+	LLResponderRegistry::registerResponders();
+
+	LLNotifications::instance().getChannel("Persistent")->
+		connectChanged(boost::bind(&LLPersistentNotificationStorage::onPersistentChannelChanged, this, _1));
+
+	LLSD input;
+	if (!readNotifications(input) ||input.isUndefined())
+	{
+		return;
+	}
+
+	LLSD& data = input["data"];
+	if (data.isUndefined())
+	{
+		return;
+	}
+
+	using namespace LLNotificationsUI;
+	LLScreenChannel* notification_channel = dynamic_cast<LLScreenChannel*>(LLChannelManager::getInstance()->
+		findChannelByID(LLUUID(gSavedSettings.getString("NotificationChannelUUID"))));
+
+	LLNotifications& instance = LLNotifications::instance();
+
+	for (LLSD::array_const_iterator notification_it = data.beginArray();
+		notification_it != data.endArray();
+		++notification_it)
+	{
+		LLSD notification_params = *notification_it;
+		LLNotificationPtr notification(new LLNotification(notification_params));
+
+		LLNotificationResponderPtr responder(LLResponderRegistry::
+			createResponder(notification_params["name"], notification_params["responder"]));
+		notification->setResponseFunctor(responder);
+
+		instance.add(notification);
+
+		// hide script floaters so they don't confuse the user and don't overlap startup toast
+		LLScriptFloaterManager::getInstance()->setFloaterVisible(notification->getID(), false);
+
+		if(notification_channel)
+		{
+			// hide saved toasts so they don't confuse the user
+			notification_channel->hideToast(notification->getID());
+		}
+	}
+}
+
+bool LLPersistentNotificationStorage::onPersistentChannelChanged(const LLSD& payload)
+{
+	// we ignore "load" messages, but rewrite the persistence file on any other
+	const std::string sigtype = payload["sigtype"].asString();
+	if ("load" != sigtype)
+	{
+		saveNotifications();
+	}
+	return false;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+
+LLResponderRegistry::build_map_t LLResponderRegistry::sBuildMap;
+
+void LLResponderRegistry::registerResponders()
+{
+	sBuildMap.clear();
+
+	add("ObjectGiveItem", &create<LLOfferInfo>);
+	add("UserGiveItem", &create<LLOfferInfo>);
+}
+
+LLNotificationResponderInterface* LLResponderRegistry::createResponder(const std::string& notification_name, const LLSD& params)
+{
+	build_map_t::const_iterator it = sBuildMap.find(notification_name);
+	if(sBuildMap.end() == it)
+	{
+		return NULL;
+	}
+	responder_constructor_t ctr = it->second;
+	return ctr(params);
+}
+
+void LLResponderRegistry::add(const std::string& notification_name, const responder_constructor_t& ctr)
+{
+	if(sBuildMap.find(notification_name) != sBuildMap.end())
+	{
+		llwarns << "Responder is already registered : " << notification_name << llendl;
+		llassert(!"Responder already registered");
+	}
+	sBuildMap[notification_name] = ctr;
+}
+
+// EOF
diff --git a/indra/newview/llpersistentnotificationstorage.h b/indra/newview/llpersistentnotificationstorage.h
new file mode 100644
index 00000000000..98a825d2c13
--- /dev/null
+++ b/indra/newview/llpersistentnotificationstorage.h
@@ -0,0 +1,63 @@
+/** 
+* @file   llpersistentnotificationstorage.h
+* @brief  Header file for llpersistentnotificationstorage
+* @author Stinson@lindenlab.com
+*
+* $LicenseInfo:firstyear=2012&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2012, Linden Research, Inc.
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation;
+* version 2.1 of the License only.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*
+* Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+* $/LicenseInfo$
+*/
+#ifndef LL_LLPERSISTENTNOTIFICATIONSTORAGE_H
+#define LL_LLPERSISTENTNOTIFICATIONSTORAGE_H
+
+#include "llerror.h"
+#include "llnotificationstorage.h"
+#include "llsingleton.h"
+
+class LLSD;
+
+// Class that saves not responded(unread) notifications.
+// Unread notifications are saved in open_notifications.xml in SL account folder
+//
+// Notifications that should be saved(if unread) are marked with persist="true" in notifications.xml
+// Notifications using functor responders are saved automatically (see llviewermessage.cpp
+// lure_callback_reg for example).
+// Notifications using object responders(LLOfferInfo) need additional tuning. Responder object should
+// be a) serializable(implement LLNotificationResponderInterface),
+// b) registered with LLResponderRegistry (found in llpersistentnotificationstorage.cpp).
+
+class LLPersistentNotificationStorage : public LLSingleton<LLPersistentNotificationStorage>, public LLNotificationStorage
+{
+	LOG_CLASS(LLPersistentNotificationStorage);
+public:
+	LLPersistentNotificationStorage();
+	~LLPersistentNotificationStorage();
+
+	void saveNotifications();
+	void loadNotifications();
+
+protected:
+
+private:
+	bool onPersistentChannelChanged(const LLSD& payload);
+};
+
+#endif // LL_LLPERSISTENTNOTIFICATIONSTORAGE_H
+
-- 
GitLab