diff options
Diffstat (limited to 'indra/newview')
| -rw-r--r-- | indra/newview/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | indra/newview/llchannelmanager.cpp | 45 | ||||
| -rw-r--r-- | indra/newview/llnotificationstorage.cpp | 228 | ||||
| -rw-r--r-- | indra/newview/llnotificationstorage.h | 65 | ||||
| -rw-r--r-- | indra/newview/llpanelgroup.h | 2 | ||||
| -rw-r--r-- | indra/newview/llscriptfloater.cpp | 10 | ||||
| -rw-r--r-- | indra/newview/llscriptfloater.h | 2 | ||||
| -rw-r--r-- | indra/newview/lltoastnotifypanel.cpp | 2 | ||||
| -rw-r--r-- | indra/newview/llviewermessage.cpp | 58 | ||||
| -rw-r--r-- | indra/newview/llviewermessage.h | 25 | ||||
| -rw-r--r-- | indra/newview/skins/default/xui/en/notifications.xml | 4 | 
11 files changed, 412 insertions, 31 deletions
| diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index c372edbea1..d0cb3dd2ab 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -295,6 +295,7 @@ set(viewer_SOURCE_FILES      llnotificationmanager.cpp      llnotificationofferhandler.cpp      llnotificationscripthandler.cpp +    llnotificationstorage.cpp      llnotificationtiphandler.cpp      lloutfitslist.cpp      lloutputmonitorctrl.cpp @@ -800,6 +801,7 @@ set(viewer_HEADER_FILES      llnetmap.h      llnotificationhandler.h      llnotificationmanager.h +    llnotificationstorage.h      lloutfitslist.h      lloutputmonitorctrl.h      llpanelavatar.h diff --git a/indra/newview/llchannelmanager.cpp b/indra/newview/llchannelmanager.cpp index 769387c26c..4f9434030f 100644 --- a/indra/newview/llchannelmanager.cpp +++ b/indra/newview/llchannelmanager.cpp @@ -35,6 +35,7 @@  #include "llchannelmanager.h"  #include "llappviewer.h" +#include "llnotificationstorage.h"  #include "llviewercontrol.h"  #include "llviewerwindow.h"  #include "llrootview.h" @@ -107,31 +108,35 @@ void LLChannelManager::onLoginCompleted()  	if(!away_notifications)  	{  		onStartUpToastClose(); -		return;  	} -	 -	// create a channel for the StartUp Toast -	LLChannelManager::Params p; -	p.id = LLUUID(gSavedSettings.getString("StartUpChannelUUID")); -	p.channel_align = CA_RIGHT; -	mStartUpChannel = createChannel(p); - -	if(!mStartUpChannel) +	else  	{ -		onStartUpToastClose(); -		return; -	} +		// create a channel for the StartUp Toast +		LLChannelManager::Params p; +		p.id = LLUUID(gSavedSettings.getString("StartUpChannelUUID")); +		p.channel_align = CA_RIGHT; +		mStartUpChannel = createChannel(p); -	gViewerWindow->getRootView()->addChild(mStartUpChannel); +		if(!mStartUpChannel) +		{ +			onStartUpToastClose(); +		} +		else +		{ +			gViewerWindow->getRootView()->addChild(mStartUpChannel); -	// init channel's position and size -	S32 channel_right_bound = gViewerWindow->getWorldViewRectScaled().mRight - gSavedSettings.getS32("NotificationChannelRightMargin");  -	S32 channel_width = gSavedSettings.getS32("NotifyBoxWidth"); -	mStartUpChannel->init(channel_right_bound - channel_width, channel_right_bound); -	mStartUpChannel->setMouseDownCallback(boost::bind(&LLNotificationWellWindow::onStartUpToastClick, LLNotificationWellWindow::getInstance(), _2, _3, _4)); +			// init channel's position and size +			S32 channel_right_bound = gViewerWindow->getWorldViewRectScaled().mRight - gSavedSettings.getS32("NotificationChannelRightMargin");  +			S32 channel_width = gSavedSettings.getS32("NotifyBoxWidth"); +			mStartUpChannel->init(channel_right_bound - channel_width, channel_right_bound); +			mStartUpChannel->setMouseDownCallback(boost::bind(&LLNotificationWellWindow::onStartUpToastClick, LLNotificationWellWindow::getInstance(), _2, _3, _4)); + +			mStartUpChannel->setCommitCallback(boost::bind(&LLChannelManager::onStartUpToastClose, this)); +			mStartUpChannel->createStartUpToast(away_notifications, gSavedSettings.getS32("StartUpToastLifeTime")); +		} +	} -	mStartUpChannel->setCommitCallback(boost::bind(&LLChannelManager::onStartUpToastClose, this)); -	mStartUpChannel->createStartUpToast(away_notifications, gSavedSettings.getS32("StartUpToastLifeTime")); +	LLPersistentNotificationStorage::getInstance()->loadNotifications();  }  //-------------------------------------------------------------------------- diff --git a/indra/newview/llnotificationstorage.cpp b/indra/newview/llnotificationstorage.cpp new file mode 100644 index 0000000000..316ff4324c --- /dev/null +++ b/indra/newview/llnotificationstorage.cpp @@ -0,0 +1,228 @@ +/** +* @file llnotificationstorage.cpp +* @brief LLPersistentNotificationStorage class implementation +* +* $LicenseInfo:firstyear=2010&license=viewergpl$ +* +* Copyright (c) 2010, Linden Research, Inc. +* +* Second Life Viewer Source Code +* The source code in this file ("Source Code") is provided by Linden Lab +* to you under the terms of the GNU General Public License, version 2.0 +* ("GPL"), unless you have obtained a separate licensing agreement +* ("Other License"), formally executed by you and Linden Lab.  Terms of +* the GPL can be found in doc/GPL-license.txt in this distribution, or +* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 +* +* There are special exceptions to the terms and conditions of the GPL as +* it is applied to this Source Code. View the full text of the exception +* in the file doc/FLOSS-exception.txt in this software distribution, or +* online at +* http://secondlifegrid.net/programs/open_source/licensing/flossexception +* +* By copying, modifying or distributing this software, you acknowledge +* that you have read and understood your obligations described above, +* and agree to abide by those obligations. +* +* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO +* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, +* COMPLETENESS OR PERFORMANCE. +* $/LicenseInfo$ +*/ + +#include "llviewerprecompiledheaders.h" // must be first include +#include "llnotificationstorage.h" + +#include "llxmlnode.h" // for linux compilers + +#include "llchannelmanager.h" +#include "llscreenchannel.h" +#include "llscriptfloater.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() +{ +	mFileName = gDirUtilp->getExpandedFilename ( LL_PATH_PER_SL_ACCOUNT, "open_notifications.xml" ); +} + +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; +} + +void LLPersistentNotificationStorage::saveNotifications() +{ +	// TODO - think about save optimization. + +	llofstream notify_file(mFileName.c_str()); +	if (!notify_file.is_open()) +	{ +		llwarns << "Failed to open " << mFileName << llendl; +		return; +	} + +	LLSD output; +	LLSD& data = output["data"]; + +	LLNotificationChannelPtr history_channel = LLNotifications::instance().getChannel("Persistent"); +	LLNotificationSet::iterator it = history_channel->begin(); + +	for ( ; history_channel->end() != it; ++it) +	{ +		LLNotificationPtr notification = *it; + +		// After a notification was placed in Persist channel, it can become +		// responded, expired - in this case we are should not save it +		if(notification->isRespondedTo() +			|| notification->isExpired()) +		{ +			continue; +		} + +		data.append(notification->asLLSD()); +	} + +	LLPointer<LLSDFormatter> formatter = new LLSDXMLFormatter(); +	formatter->format(output, notify_file, LLSDFormatter::OPTIONS_PRETTY); +} + +void LLPersistentNotificationStorage::loadNotifications() +{ +	LLResponderRegistry::registerResponders(); + +	LLNotifications::instance().getChannel("Persistent")-> +		connectChanged(boost::bind(&LLPersistentNotificationStorage::onPersistentChannelChanged, this, _1)); + +	llifstream notify_file(mFileName.c_str()); +	if (!notify_file.is_open()) +	{ +		llwarns << "Failed to open " << mFileName << llendl; +		return; +	} + +	LLSD input; +	LLPointer<LLSDParser> parser = new LLSDXMLParser(); +	if (parser->parse(notify_file, input, LLSDSerialize::SIZE_UNLIMITED) < 0) +	{ +		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) +		{ +			// hide saved toasts so they don't confuse the user +			notification_channel->hideToast(notification->getID()); +		} +	} +} + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +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) +	{ +		llwarns << "Responder for notification \'" << notification_name << "\' is not registered" << llendl; +		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/llnotificationstorage.h b/indra/newview/llnotificationstorage.h new file mode 100644 index 0000000000..5050781a85 --- /dev/null +++ b/indra/newview/llnotificationstorage.h @@ -0,0 +1,65 @@ +/** +* @file llnotificationstorage.h +* @brief LLNotificationStorage class declaration +* +* $LicenseInfo:firstyear=2010&license=viewergpl$ +* +* Copyright (c) 2010, Linden Research, Inc. +* +* Second Life Viewer Source Code +* The source code in this file ("Source Code") is provided by Linden Lab +* to you under the terms of the GNU General Public License, version 2.0 +* ("GPL"), unless you have obtained a separate licensing agreement +* ("Other License"), formally executed by you and Linden Lab.  Terms of +* the GPL can be found in doc/GPL-license.txt in this distribution, or +* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 +* +* There are special exceptions to the terms and conditions of the GPL as +* it is applied to this Source Code. View the full text of the exception +* in the file doc/FLOSS-exception.txt in this software distribution, or +* online at +* http://secondlifegrid.net/programs/open_source/licensing/flossexception +* +* By copying, modifying or distributing this software, you acknowledge +* that you have read and understood your obligations described above, +* and agree to abide by those obligations. +* +* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO +* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, +* COMPLETENESS OR PERFORMANCE. +* $/LicenseInfo$ +*/ + +#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: + +	LLPersistentNotificationStorage(); + +	void saveNotifications(); + +	void loadNotifications(); + +private: + +	bool onPersistentChannelChanged(const LLSD& payload); + +	std::string mFileName; +}; + +#endif // LL_NOTIFICATIONSTORAGE_H diff --git a/indra/newview/llpanelgroup.h b/indra/newview/llpanelgroup.h index 136868a60d..359f252383 100644 --- a/indra/newview/llpanelgroup.h +++ b/indra/newview/llpanelgroup.h @@ -37,7 +37,7 @@  #include "lltimer.h"  #include "llvoiceclient.h" -struct LLOfferInfo; +class LLOfferInfo;  const S32 UPDATE_MEMBERS_PER_FRAME = 500; diff --git a/indra/newview/llscriptfloater.cpp b/indra/newview/llscriptfloater.cpp index f35cb3516a..11b6c0a3ae 100644 --- a/indra/newview/llscriptfloater.cpp +++ b/indra/newview/llscriptfloater.cpp @@ -539,4 +539,14 @@ bool LLScriptFloaterManager::getFloaterPosition(const LLUUID& object_id, Floater  	return false;  } +void LLScriptFloaterManager::setFloaterVisible(const LLUUID& notification_id, bool visible) +{ +	LLScriptFloater* floater = LLFloaterReg::findTypedInstance<LLScriptFloater>( +		"script_floater", notification_id); +	if(floater) +	{ +		floater->setVisible(visible); +	} +} +  // EOF diff --git a/indra/newview/llscriptfloater.h b/indra/newview/llscriptfloater.h index ec3ec4b540..dc0cfc2400 100644 --- a/indra/newview/llscriptfloater.h +++ b/indra/newview/llscriptfloater.h @@ -99,6 +99,8 @@ public:  	bool getFloaterPosition(const LLUUID& object_id, FloaterPositionInfo& fpi); +	void setFloaterVisible(const LLUUID& notification_id, bool visible); +  protected:  	typedef std::map<std::string, EObjectType> object_type_map; diff --git a/indra/newview/lltoastnotifypanel.cpp b/indra/newview/lltoastnotifypanel.cpp index c9d2d404c0..089163929e 100644 --- a/indra/newview/lltoastnotifypanel.cpp +++ b/indra/newview/lltoastnotifypanel.cpp @@ -493,7 +493,7 @@ void LLToastNotifyPanel::onClickButton(void* data)  	{  		sButtonClickSignal(self->mNotification->getID(), button_name); -		if(new_info) +		if(new_info && !self->mNotification->isPersistent())  		{  			self->mNotification->setResponseFunctor(  				boost::bind(&LLOfferInfo::inventory_offer_callback, new_info, _1, _2)); diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 43c3042c65..486158272d 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -1247,6 +1247,16 @@ void inventory_offer_mute_callback(const LLUUID& blocked_id,  			gSavedSettings.getString("NotificationChannelUUID")), OfferMatcher(blocked_id));  } +LLOfferInfo::LLOfferInfo() + : LLNotificationResponderInterface() + , mFromGroup(FALSE) + , mFromObject(FALSE) + , mIM(IM_NOTHING_SPECIAL) + , mType(LLAssetType::AT_NONE) + , mPersist(false) +{ +} +  LLOfferInfo::LLOfferInfo(const LLSD& sd)  {  	mIM = (EInstantMessage)sd["im_type"].asInteger(); @@ -1260,6 +1270,7 @@ LLOfferInfo::LLOfferInfo(const LLSD& sd)  	mFromName = sd["from_name"].asString();  	mDesc = sd["description"].asString();  	mHost = LLHost(sd["sender"].asString()); +	mPersist = sd["persist"].asBoolean();  }  LLOfferInfo::LLOfferInfo(const LLOfferInfo& info) @@ -1275,6 +1286,7 @@ LLOfferInfo::LLOfferInfo(const LLOfferInfo& info)  	mFromName = info.mFromName;  	mDesc = info.mDesc;  	mHost = info.mHost; +	mPersist = info.mPersist;  }  LLSD LLOfferInfo::asLLSD() @@ -1291,9 +1303,15 @@ LLSD LLOfferInfo::asLLSD()  	sd["from_name"] = mFromName;  	sd["description"] = mDesc;  	sd["sender"] = mHost.getIPandPort(); +	sd["persist"] = mPersist;  	return sd;  } +void LLOfferInfo::fromLLSD(const LLSD& params) +{ +	*this = params; +} +  void LLOfferInfo::send_auto_receive_response(void)  {	  	LLMessageSystem* msg = gMessageSystem; @@ -1333,6 +1351,21 @@ void LLOfferInfo::send_auto_receive_response(void)  	}  } +void LLOfferInfo::handleRespond(const LLSD& notification, const LLSD& response) +{ +	initRespondFunctionMap(); + +	const std::string name = notification["name"].asString(); +	if(mRespondFunctions.find(name) == mRespondFunctions.end()) +	{ +		llwarns << "Unexpected notification name : " << name << llendl; +		llassert(!"Unexpected notification name"); +		return; +	} + +	mRespondFunctions[name](notification, response); +} +  bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& response)  {  	LLChat chat; @@ -1469,7 +1502,10 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD&  		gInventory.addObserver(opener);  	} -	delete this; +	if(!mPersist) +	{ +		delete this; +	}  	return false;  } @@ -1635,7 +1671,10 @@ bool LLOfferInfo::inventory_task_offer_callback(const LLSD& notification, const  		gInventory.addObserver(opener);  	} -	delete this; +	if(!mPersist) +	{ +		delete this; +	}  	return false;  } @@ -1651,6 +1690,15 @@ protected:  	}  }; +void LLOfferInfo::initRespondFunctionMap() +{ +	if(mRespondFunctions.empty()) +	{ +		mRespondFunctions["ObjectGiveItem"] = boost::bind(&LLOfferInfo::inventory_task_offer_callback, this, _1, _2); +		mRespondFunctions["UserGiveItem"] = boost::bind(&LLOfferInfo::inventory_offer_callback, this, _1, _2); +	} +} +  void inventory_offer_handler(LLOfferInfo* info)  {  	//Until throttling is implmented, busy mode should reject inventory instead of silently @@ -1767,7 +1815,8 @@ void inventory_offer_handler(LLOfferInfo* info)  		// Inventory Slurls don't currently work for non agent transfers, so only display the object name.  		args["ITEM_SLURL"] = msg;  		// Note: sets inventory_task_offer_callback as the callback -		p.substitutions(args).payload(payload).functor.function(boost::bind(&LLOfferInfo::inventory_task_offer_callback, info, _1, _2)); +		p.substitutions(args).payload(payload).functor.responder(LLNotificationResponderPtr(info)); +		info->mPersist = true;  		p.name = name_found ? "ObjectGiveItem" : "ObjectGiveItemUnknownUser";  		// Pop up inv offer chiclet and let the user accept (keep), or reject (and silently delete) the inventory.  		LLNotifications::instance().add(p); @@ -1779,7 +1828,8 @@ void inventory_offer_handler(LLOfferInfo* info)  		// *TODO fix memory leak  		// inventory_offer_callback() is not invoked if user received notification and   		// closes viewer(without responding the notification) -		p.substitutions(args).payload(payload).functor.function(boost::bind(&LLOfferInfo::inventory_offer_callback, info, _1, _2)); +		p.substitutions(args).payload(payload).functor.responder(LLNotificationResponderPtr(info)); +		info->mPersist = true;  		p.name = "UserGiveItem";  		// Prefetch the item into your local inventory. diff --git a/indra/newview/llviewermessage.h b/indra/newview/llviewermessage.h index 7c021dc05f..72ad3c8926 100644 --- a/indra/newview/llviewermessage.h +++ b/indra/newview/llviewermessage.h @@ -40,6 +40,7 @@  #include "lluuid.h"  #include "message.h"  #include "stdenums.h" +#include "llnotifications.h"  //  // Forward declarations @@ -210,11 +211,10 @@ bool highlight_offered_item(const LLUUID& item_id);  void set_dad_inventory_item(LLInventoryItem* inv_item, const LLUUID& into_folder_uuid); -struct LLOfferInfo +class LLOfferInfo : public LLNotificationResponderInterface  { -        LLOfferInfo() -	:	mFromGroup(FALSE), mFromObject(FALSE), -		mIM(IM_NOTHING_SPECIAL), mType(LLAssetType::AT_NONE) {}; +public: +	LLOfferInfo();  	LLOfferInfo(const LLSD& sd);  	LLOfferInfo(const LLOfferInfo& info); @@ -232,12 +232,27 @@ struct LLOfferInfo  	std::string mFromName;  	std::string mDesc;  	LLHost mHost; +	bool mPersist; + +	// LLNotificationResponderInterface implementation +	/*virtual*/ LLSD asLLSD(); +	/*virtual*/ void fromLLSD(const LLSD& params); +	/*virtual*/ void handleRespond(const LLSD& notification, const LLSD& response); -	LLSD asLLSD();  	void send_auto_receive_response(void); + +	// TODO - replace all references with handleRespond()  	bool inventory_offer_callback(const LLSD& notification, const LLSD& response);  	bool inventory_task_offer_callback(const LLSD& notification, const LLSD& response); +private: + +	void initRespondFunctionMap(); + +	typedef boost::function<bool (const LLSD&, const LLSD&)> respond_function_t; +	typedef std::map<std::string, respond_function_t> respond_function_map_t; + +	respond_function_map_t mRespondFunctions;  };  void process_feature_disabled_message(LLMessageSystem* msg, void**); diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 07304eb14e..5d184fea3a 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -5066,6 +5066,7 @@ No valid parcel could be found.    <notification     icon="notify.tga"     name="ObjectGiveItem" +   persist="true"     type="offer">  An object named [OBJECTFROMNAME] owned by [NAME_SLURL] has given you this [OBJECTTYPE]:  [ITEM_SLURL] @@ -5110,6 +5111,7 @@ An object named [OBJECTFROMNAME] owned by (an unknown Resident) has given you th    <notification     icon="notify.tga"     name="UserGiveItem" +   persist="true"     type="offer">  [NAME_SLURL] has given you this [OBJECTTYPE]:  [ITEM_SLURL] @@ -5162,6 +5164,7 @@ An object named [OBJECTFROMNAME] owned by (an unknown Resident) has given you th    <notification     icon="notify.tga"     name="TeleportOffered" +   persist="true"     type="offer">  [NAME_SLURL] has offered to teleport you to their location: @@ -5207,6 +5210,7 @@ An object named [OBJECTFROMNAME] owned by (an unknown Resident) has given you th    <notification     icon="notify.tga"     name="OfferFriendship" +   persist="true"     type="offer">  [NAME_SLURL] is offering friendship. | 
