PageRenderTime 26ms CodeModel.GetById 2ms app.highlight 20ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/newview/llnotificationstorage.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 221 lines | 139 code | 45 blank | 37 comment | 19 complexity | fe36554904878f1a6474d104f20f81d4 MD5 | raw file
  1/**
  2* @file llnotificationstorage.cpp
  3* @brief LLPersistentNotificationStorage class implementation
  4*
  5* $LicenseInfo:firstyear=2010&license=viewerlgpl$
  6* Second Life Viewer Source Code
  7* Copyright (C) 2010, Linden Research, Inc.
  8* 
  9* This library is free software; you can redistribute it and/or
 10* modify it under the terms of the GNU Lesser General Public
 11* License as published by the Free Software Foundation;
 12* version 2.1 of the License only.
 13* 
 14* This library is distributed in the hope that it will be useful,
 15* but WITHOUT ANY WARRANTY; without even the implied warranty of
 16* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 17* Lesser General Public License for more details.
 18* 
 19* You should have received a copy of the GNU Lesser General Public
 20* License along with this library; if not, write to the Free Software
 21* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 22* 
 23* Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 24* $/LicenseInfo$
 25*/
 26
 27#include "llviewerprecompiledheaders.h" // must be first include
 28#include "llnotificationstorage.h"
 29
 30#include "llxmlnode.h" // for linux compilers
 31
 32#include "llchannelmanager.h"
 33#include "llscreenchannel.h"
 34#include "llscriptfloater.h"
 35#include "llsdserialize.h"
 36#include "llviewermessage.h"
 37
 38//////////////////////////////////////////////////////////////////////////
 39
 40class LLResponderRegistry
 41{
 42public:
 43
 44	static void registerResponders();
 45
 46	static LLNotificationResponderInterface* createResponder(const std::string& notification_name, const LLSD& params);
 47
 48private:
 49
 50	template<typename RESPONDER_TYPE>
 51	static LLNotificationResponderInterface* create(const LLSD& params)
 52	{
 53		RESPONDER_TYPE* responder = new RESPONDER_TYPE();
 54		responder->fromLLSD(params);
 55		return responder;
 56	}
 57
 58	typedef boost::function<LLNotificationResponderInterface* (const LLSD& params)> responder_constructor_t;
 59
 60	static void add(const std::string& notification_name, const responder_constructor_t& ctr);
 61
 62private:
 63
 64	typedef std::map<std::string, responder_constructor_t> build_map_t;
 65
 66	static build_map_t sBuildMap;
 67};
 68
 69//////////////////////////////////////////////////////////////////////////
 70
 71LLPersistentNotificationStorage::LLPersistentNotificationStorage()
 72{
 73	mFileName = gDirUtilp->getExpandedFilename ( LL_PATH_PER_SL_ACCOUNT, "open_notifications.xml" );
 74}
 75
 76bool LLPersistentNotificationStorage::onPersistentChannelChanged(const LLSD& payload)
 77{
 78	// we ignore "load" messages, but rewrite the persistence file on any other
 79	const std::string sigtype = payload["sigtype"].asString();
 80	if ("load" != sigtype)
 81	{
 82		saveNotifications();
 83	}
 84	return false;
 85}
 86
 87void LLPersistentNotificationStorage::saveNotifications()
 88{
 89	// TODO - think about save optimization.
 90
 91	llofstream notify_file(mFileName.c_str());
 92	if (!notify_file.is_open())
 93	{
 94		llwarns << "Failed to open " << mFileName << llendl;
 95		return;
 96	}
 97
 98	LLSD output;
 99	LLSD& data = output["data"];
100
101	LLNotificationChannelPtr history_channel = LLNotifications::instance().getChannel("Persistent");
102	LLNotificationSet::iterator it = history_channel->begin();
103
104	for ( ; history_channel->end() != it; ++it)
105	{
106		LLNotificationPtr notification = *it;
107
108		// After a notification was placed in Persist channel, it can become
109		// responded, expired or canceled - in this case we are should not save it
110		if(notification->isRespondedTo() || notification->isCancelled()
111			|| notification->isExpired())
112		{
113			continue;
114		}
115
116		data.append(notification->asLLSD());
117	}
118
119	LLPointer<LLSDFormatter> formatter = new LLSDXMLFormatter();
120	formatter->format(output, notify_file, LLSDFormatter::OPTIONS_PRETTY);
121}
122
123void LLPersistentNotificationStorage::loadNotifications()
124{
125	LLResponderRegistry::registerResponders();
126
127	LLNotifications::instance().getChannel("Persistent")->
128		connectChanged(boost::bind(&LLPersistentNotificationStorage::onPersistentChannelChanged, this, _1));
129
130	llifstream notify_file(mFileName.c_str());
131	if (!notify_file.is_open())
132	{
133		llwarns << "Failed to open " << mFileName << llendl;
134		return;
135	}
136
137	LLSD input;
138	LLPointer<LLSDParser> parser = new LLSDXMLParser();
139	if (parser->parse(notify_file, input, LLSDSerialize::SIZE_UNLIMITED) < 0)
140	{
141		llwarns << "Failed to parse open notifications" << llendl;
142		return;
143	}
144
145	if (input.isUndefined())
146	{
147		return;
148	}
149
150	LLSD& data = input["data"];
151	if (data.isUndefined())
152	{
153		return;
154	}
155
156	using namespace LLNotificationsUI;
157	LLScreenChannel* notification_channel = dynamic_cast<LLScreenChannel*>(LLChannelManager::getInstance()->
158		findChannelByID(LLUUID(gSavedSettings.getString("NotificationChannelUUID"))));
159
160	LLNotifications& instance = LLNotifications::instance();
161
162	for (LLSD::array_const_iterator notification_it = data.beginArray();
163		notification_it != data.endArray();
164		++notification_it)
165	{
166		LLSD notification_params = *notification_it;
167		LLNotificationPtr notification(new LLNotification(notification_params));
168
169		LLNotificationResponderPtr responder(LLResponderRegistry::
170			createResponder(notification_params["name"], notification_params["responder"]));
171		notification->setResponseFunctor(responder);
172
173		instance.add(notification);
174
175		// hide script floaters so they don't confuse the user and don't overlap startup toast
176		LLScriptFloaterManager::getInstance()->setFloaterVisible(notification->getID(), false);
177
178		if(notification_channel)
179		{
180			// hide saved toasts so they don't confuse the user
181			notification_channel->hideToast(notification->getID());
182		}
183	}
184}
185
186//////////////////////////////////////////////////////////////////////////
187//////////////////////////////////////////////////////////////////////////
188//////////////////////////////////////////////////////////////////////////
189
190LLResponderRegistry::build_map_t LLResponderRegistry::sBuildMap;
191
192void LLResponderRegistry::registerResponders()
193{
194	sBuildMap.clear();
195
196	add("ObjectGiveItem", &create<LLOfferInfo>);
197	add("UserGiveItem", &create<LLOfferInfo>);
198}
199
200LLNotificationResponderInterface* LLResponderRegistry::createResponder(const std::string& notification_name, const LLSD& params)
201{
202	build_map_t::const_iterator it = sBuildMap.find(notification_name);
203	if(sBuildMap.end() == it)
204	{
205		return NULL;
206	}
207	responder_constructor_t ctr = it->second;
208	return ctr(params);
209}
210
211void LLResponderRegistry::add(const std::string& notification_name, const responder_constructor_t& ctr)
212{
213	if(sBuildMap.find(notification_name) != sBuildMap.end())
214	{
215		llwarns << "Responder is already registered : " << notification_name << llendl;
216		llassert(!"Responder already registered");
217	}
218	sBuildMap[notification_name] = ctr;
219}
220
221// EOF