diff options
| author | Richard Linden <none@none> | 2012-05-21 17:16:11 -0700 | 
|---|---|---|
| committer | Richard Linden <none@none> | 2012-05-21 17:16:11 -0700 | 
| commit | 61bc25211be31ad28b8ae342c17b4ea1c32d955c (patch) | |
| tree | 05f7e0fd17bda6273fdf55cda379fd5596bbcd16 | |
| parent | 4c7142f4836da9da77ac6ff2910aaa19506a655b (diff) | |
CHUI-111 FIX Saved notifications are not sorted in same order after logout and relog.
sort notifications in separate list
llnotification now uses param block to serialize to llsd
| -rw-r--r-- | indra/llui/llnotifications.cpp | 138 | ||||
| -rw-r--r-- | indra/llui/llnotifications.h | 148 | ||||
| -rw-r--r-- | indra/llui/llsdparam.cpp | 8 | ||||
| -rw-r--r-- | indra/llxuixml/llinitparam.h | 4 | ||||
| -rw-r--r-- | indra/newview/llnotificationstorage.cpp | 18 | ||||
| -rw-r--r-- | indra/newview/lltoastnotifypanel.cpp | 24 | 
6 files changed, 137 insertions, 203 deletions
diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp index 663749b983..08b93ead40 100644 --- a/indra/llui/llnotifications.cpp +++ b/indra/llui/llnotifications.cpp @@ -105,39 +105,7 @@ LLNotificationForm::Params::Params()  	form_elements("")  {} -// Local channel for persistent notifications -// Stores only persistent notifications. -// Class users can use connectChanged() to process persistent notifications -// (see LLNotificationStorage for example). -class LLPersistentNotificationChannel : public LLNotificationChannel -{ -	LOG_CLASS(LLPersistentNotificationChannel); -public: -	LLPersistentNotificationChannel() : -		LLNotificationChannel("Persistent", "Visible", ¬ificationFilter, LLNotificationComparators::orderByUUID()) -	{ -	} -private: - -	// The channel gets all persistent notifications except those that have been canceled -	static bool notificationFilter(LLNotificationPtr pNotification) -	{ -		bool handle_notification = false; - -		handle_notification = pNotification->isPersistent() -			&& !pNotification->isCancelled(); - -		return handle_notification; -	} - -	void onDelete(LLNotificationPtr pNotification) -	{ -		// we want to keep deleted notifications in our log, otherwise some  -		// notifications will be lost on exit. -		mItems.insert(pNotification); -	} -};  bool filterIgnoredNotifications(LLNotificationPtr notification)  { @@ -502,18 +470,18 @@ LLNotificationVisibilityRule::LLNotificationVisibilityRule(const LLNotificationV  	}  } -LLNotification::LLNotification(const LLNotification::Params& p) :  +LLNotification::LLNotification(const LLSDParamAdapter<Params>& p) :   	mTimestamp(p.time_stamp),   	mSubstitutions(p.substitutions),  	mPayload(p.payload), -	mExpiresAt(0), +	mExpiresAt(p.expiry),  	mTemporaryResponder(false),  	mRespondedTo(false),  	mPriority(p.priority),  	mCancelled(false),  	mIgnored(false),  	mResponderObj(NULL), -	mIsReusable(false) +	mId(p.id.isProvided() ? p.id : LLUUID::generateNewID())  {  	if (p.functor.name.isChosen())  	{ @@ -536,52 +504,32 @@ LLNotification::LLNotification(const LLNotification::Params& p) :  		mResponderObj = p.responder;  	} -	mId.generate();  	init(p.name, p.form_elements);  } -LLNotification::LLNotification(const LLSD& sd) : -	mTemporaryResponder(false), -	mRespondedTo(false), -	mCancelled(false), -	mIgnored(false), -	mResponderObj(NULL), -	mIsReusable(false) -{  -	mId.generate(); -	mSubstitutions = sd["substitutions"]; -	mPayload = sd["payload"];  -	mTimestamp = sd["time"];  -	mExpiresAt = sd["expiry"]; -	mPriority = (ENotificationPriority)sd["priority"].asInteger(); -	mResponseFunctorName = sd["responseFunctor"].asString(); -	std::string templatename = sd["name"].asString(); -	init(templatename, LLSD()); -	// replace form with serialized version -	mForm = LLNotificationFormPtr(new LLNotificationForm(sd["form"])); -} - -  LLSD LLNotification::asLLSD()  { -	LLSD output; -	output["id"] = mId; -	output["name"] = mTemplatep->mName; -	output["form"] = getForm()->asLLSD(); -	output["substitutions"] = mSubstitutions; -	output["payload"] = mPayload; -	output["time"] = mTimestamp; -	output["expiry"] = mExpiresAt; -	output["priority"] = (S32)mPriority; -	output["responseFunctor"] = mResponseFunctorName; -	output["reusable"] = mIsReusable; +	LLParamSDParser parser; -	if(mResponder) +	Params p; +	p.id = mId; +	p.name = mTemplatep->mName; +	p.form_elements = getForm()->asLLSD(); + +	p.substitutions = mSubstitutions; +	p.payload = mPayload; +	p.time_stamp = mTimestamp; +	p.expiry = mExpiresAt; +	p.priority = mPriority; + +	if(!mResponseFunctorName.empty())  	{ -		output["responder"] = mResponder->asLLSD(); +		p.functor.name = mResponseFunctorName;  	} +	LLSD output; +	parser.writeSD(output, p);  	return output;  } @@ -1056,8 +1004,8 @@ bool LLNotificationChannelBase::updateItem(const LLSD& payload, LLNotificationPt  		{  			// not in our list, add it and say so  			mItems.insert(pNotification); -			abortProcessing = mChanged(payload);  			onLoad(pNotification); +			abortProcessing = mChanged(payload);  		}  	}  	else if (cmd == "change") @@ -1072,18 +1020,18 @@ bool LLNotificationChannelBase::updateItem(const LLSD& payload, LLNotificationPt  			{  				// it already existed, so this is a change  				// since it changed in place, all we have to do is resend the signal -				abortProcessing = mChanged(payload);  				onChange(pNotification); +				abortProcessing = mChanged(payload);  			}  			else  			{  				// not in our list, add it and say so  				mItems.insert(pNotification); +				onChange(pNotification);  				// our payload is const, so make a copy before changing it  				LLSD newpayload = payload;  				newpayload["sigtype"] = "add";  				abortProcessing = mChanged(newpayload); -				onChange(pNotification);  			}  		}  		else @@ -1092,11 +1040,11 @@ bool LLNotificationChannelBase::updateItem(const LLSD& payload, LLNotificationPt  			{  				// it already existed, so this is a delete  				mItems.erase(pNotification); +				onChange(pNotification);  				// our payload is const, so make a copy before changing it  				LLSD newpayload = payload;  				newpayload["sigtype"] = "delete";  				abortProcessing = mChanged(newpayload); -				onChange(pNotification);  			}  			// didn't pass, not on our list, do nothing  		} @@ -1110,8 +1058,8 @@ bool LLNotificationChannelBase::updateItem(const LLSD& payload, LLNotificationPt  		{  			// not in our list, add it and say so  			mItems.insert(pNotification); -			abortProcessing = mChanged(payload);  			onAdd(pNotification); +			abortProcessing = mChanged(payload);  		}  	}  	else if (cmd == "delete") @@ -1119,16 +1067,16 @@ bool LLNotificationChannelBase::updateItem(const LLSD& payload, LLNotificationPt  		// if we have it in our list, pass on the delete, then delete it, else do nothing  		if (wasFound)  		{ -			abortProcessing = mChanged(payload);  			mItems.erase(pNotification);  			onDelete(pNotification); +			abortProcessing = mChanged(payload);  		}  	}  	return abortProcessing;  }  LLNotificationChannel::LLNotificationChannel(const Params& p) -:	LLNotificationChannelBase(p.filter(), p.comparator()), +:	LLNotificationChannelBase(p.filter()),  	LLInstanceTracker<LLNotificationChannel, std::string>(p.name.isProvided() ? p.name : LLUUID::generateNewID().asString()),  	mName(p.name.isProvided() ? p.name : LLUUID::generateNewID().asString())  { @@ -1141,9 +1089,8 @@ LLNotificationChannel::LLNotificationChannel(const Params& p)  LLNotificationChannel::LLNotificationChannel(const std::string& name,   											 const std::string& parent, -											 LLNotificationFilter filter,  -											 LLNotificationComparator comparator)  -:	LLNotificationChannelBase(filter, comparator), +											 LLNotificationFilter filter)  +:	LLNotificationChannelBase(filter),  	LLInstanceTracker<LLNotificationChannel, std::string>(name),  	mName(name)  { @@ -1151,18 +1098,6 @@ LLNotificationChannel::LLNotificationChannel(const std::string& name,  	connectToChannel(parent);  } - -void LLNotificationChannel::setComparator(LLNotificationComparator comparator)  -{  -	mComparator = comparator;  -	LLNotificationSet s2(mComparator); -	s2.insert(mItems.begin(), mItems.end()); -	mItems.swap(s2); -	 -	// notify clients that we've been resorted -	mChanged(LLSD().with("sigtype", "sort"));  -} -  bool LLNotificationChannel::isEmpty() const  {  	return mItems.empty(); @@ -1178,6 +1113,11 @@ LLNotificationChannel::Iterator LLNotificationChannel::end()  	return mItems.end();  } +size_t LLNotificationChannel::size() +{ +	return mItems.size(); +} +  std::string LLNotificationChannel::summarize()  {  	std::string s("Channel '"); @@ -1205,19 +1145,17 @@ void LLNotificationChannel::connectToChannel( const std::string& channel_name )  	}  } - -  // ---  // END OF LLNotificationChannel implementation  // ========================================================= -// ========================================================= +// ==============================================	===========  // LLNotifications implementation  // --- -LLNotifications::LLNotifications() : LLNotificationChannelBase(LLNotificationFilters::includeEverything, -															   LLNotificationComparators::orderByUUID()), -									mIgnoreAllNotifications(false) +LLNotifications::LLNotifications()  +:	LLNotificationChannelBase(LLNotificationFilters::includeEverything), +	mIgnoreAllNotifications(false)  {  	LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Notification.Show", boost::bind(&LLNotifications::addFromCallback, this, _2)); @@ -1705,7 +1643,7 @@ void LLNotifications::update(const LLNotificationPtr pNotif)  LLNotificationPtr LLNotifications::find(LLUUID uuid)  { -	LLNotificationPtr target = LLNotificationPtr(new LLNotification(uuid)); +	LLNotificationPtr target = LLNotificationPtr(new LLNotification(LLNotification::Params().id(uuid)));  	LLNotificationSet::iterator it=mItems.find(target);  	if (it == mItems.end())  	{ diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h index e9449eae69..783e9ffc88 100644 --- a/indra/llui/llnotifications.h +++ b/indra/llui/llnotifications.h @@ -88,10 +88,6 @@  #include <boost/enable_shared_from_this.hpp>  #include <boost/type_traits.hpp> -// we want to minimize external dependencies, but this one is important -#include "llsd.h" - -// and we need this to manage the notification callbacks  #include "llevents.h"  #include "llfunctorregistry.h"  #include "llinitparam.h" @@ -99,6 +95,7 @@  #include "llnotificationptr.h"  #include "llpointer.h"  #include "llrefcount.h" +#include "llsdparam.h"  class LLAvatarName;  typedef enum e_notification_priority @@ -309,13 +306,13 @@ public:  		friend class LLNotification;  		Mandatory<std::string>					name; - -		// optional -		Optional<LLSD>							substitutions; -		Optional<LLSD>							payload; +		Optional<LLUUID>						id; +		Optional<LLSD>							substitutions, +												form_elements, +												payload;  		Optional<ENotificationPriority, NotificationPriorityValues>	priority; -		Optional<LLSD>							form_elements; -		Optional<LLDate>						time_stamp; +		Optional<LLDate>						time_stamp, +												expiry;  		Optional<LLNotificationContext*>		context;  		Optional<void*>							responder; @@ -326,7 +323,7 @@ public:  			Alternative<LLNotificationResponderPtr>						responder;  			Functor() -			:	name("functor_name"), +			:	name("responseFunctor"),  				function("functor"),  				responder("responder")  			{} @@ -335,10 +332,13 @@ public:  		Params()  		:	name("name"), +			id("id"),  			priority("priority", NOTIFICATION_PRIORITY_UNSPECIFIED), -			time_stamp("time_stamp"), +			time_stamp("time"),  			payload("payload"), -			form_elements("form_elements") +			form_elements("form"), +			substitutions("substitutions"), +			expiry("expiry")  		{  			time_stamp = LLDate::now();  			responder = NULL; @@ -347,9 +347,11 @@ public:  		Params(const std::string& _name)   		:	name("name"),  			priority("priority", NOTIFICATION_PRIORITY_UNSPECIFIED), -			time_stamp("time_stamp"), +			time_stamp("time"),  			payload("payload"), -			form_elements("form_elements") +			form_elements("form"), +			substitutions("substitutions"), +			expiry("expiry")  		{  			functor.name = _name;  			name = _name; @@ -362,7 +364,7 @@ public:  private: -	LLUUID mId; +	const LLUUID mId;  	LLSD mPayload;  	LLSD mSubstitutions;  	LLDate mTimestamp; @@ -374,7 +376,6 @@ private:  	ENotificationPriority mPriority;  	LLNotificationFormPtr mForm;  	void* mResponderObj; // TODO - refactor/remove this field -	bool mIsReusable;  	LLNotificationResponderPtr mResponder;  	// a reference to the template @@ -399,18 +400,10 @@ private:  	void init(const std::string& template_name, const LLSD& form_elements); -	LLNotification(const Params& p); - -	// this is just for making it easy to look things up in a set organized by UUID -- DON'T USE IT -	// for anything real! - LLNotification(LLUUID uuid) : mId(uuid), mCancelled(false), mRespondedTo(false), mIgnored(false), mPriority(NOTIFICATION_PRIORITY_UNSPECIFIED), mTemporaryResponder(false) {} -  	void cancel();  public: - -	// constructor from a saved notification -	LLNotification(const LLSD& sd); +	LLNotification(const LLSDParamAdapter<Params>& p);  	void setResponseFunctor(std::string const &responseFunctorName); @@ -555,8 +548,6 @@ public:  		return mId;  	} -	bool isReusable() { return mIsReusable; } -  	// comparing two notifications normally means comparing them by UUID (so we can look them  	// up quickly this way)  	bool operator<(const LLNotification& rhs) const @@ -668,44 +659,18 @@ namespace LLNotificationFilters  namespace LLNotificationComparators  { -	typedef enum e_direction { ORDER_DECREASING, ORDER_INCREASING } EDirection; - -	// generic order functor that takes method or member variable reference -	template<typename T> -	struct orderBy +	struct orderByUUID  	{ -		typedef boost::function<T (LLNotificationPtr)> field_t; -        	orderBy(field_t field, EDirection direction = ORDER_INCREASING) : mField(field), mDirection(direction) {}  		bool operator()(LLNotificationPtr lhs, LLNotificationPtr rhs)  		{ -			if (mDirection == ORDER_DECREASING) -			{ -				return mField(lhs) > mField(rhs); -			} -			else -			{ -				return mField(lhs) < mField(rhs); -			} +			return lhs->id() < rhs->id();  		} - -		field_t mField; -		EDirection mDirection; -	}; - -	struct orderByUUID : public orderBy<const LLUUID&> -	{ -		orderByUUID(EDirection direction = ORDER_INCREASING) : orderBy<const LLUUID&>(&LLNotification::id, direction) {} -	}; - -	struct orderByDate : public orderBy<const LLDate&> -	{ -		orderByDate(EDirection direction = ORDER_INCREASING) : orderBy<const LLDate&>(&LLNotification::getDate, direction) {}  	};  };  typedef boost::function<bool (LLNotificationPtr)> LLNotificationFilter;  typedef boost::function<bool (LLNotificationPtr, LLNotificationPtr)> LLNotificationComparator; -typedef std::set<LLNotificationPtr, LLNotificationComparator> LLNotificationSet; +typedef std::set<LLNotificationPtr, LLNotificationComparators::orderByUUID> LLNotificationSet;  typedef std::multimap<std::string, LLNotificationPtr> LLNotificationMap;  // ======================================================== @@ -731,8 +696,9 @@ class LLNotificationChannelBase :  {  	LOG_CLASS(LLNotificationChannelBase);  public: -	LLNotificationChannelBase(LLNotificationFilter filter, LLNotificationComparator comp) :  -		mFilter(filter), mItems(comp)  +	LLNotificationChannelBase(LLNotificationFilter filter)  +	:	mFilter(filter),  +		mItems()   	{}  	virtual ~LLNotificationChannelBase() {}  	// you can also connect to a Channel, so you can be notified of @@ -829,18 +795,11 @@ public:  	{  		Mandatory<std::string>				name;  		Optional<LLNotificationFilter>		filter; -		Optional<LLNotificationComparator>	comparator;  		Multiple<std::string>				sources; - -		Params() -		:	comparator("", LLNotificationComparators::orderByUUID()) -		{}  	};  	LLNotificationChannel(const Params& p = Params()); - -	LLNotificationChannel(const std::string& name, const std::string& parent, -		LLNotificationFilter filter, LLNotificationComparator comparator=LLNotificationComparators::orderByUUID()); +	LLNotificationChannel(const std::string& name, const std::string& parent, LLNotificationFilter filter);  	virtual ~LLNotificationChannel() {}  	typedef LLNotificationSet::iterator Iterator; @@ -853,11 +812,8 @@ public:      Iterator begin();      Iterator end(); +	size_t size(); -    // Channels have a comparator to control sort order; -	// the default sorts by arrival date -    void setComparator(LLNotificationComparator comparator); -	  	std::string summarize();  private: @@ -1047,5 +1003,55 @@ protected:  	std::string mName;  }; +// Stores only persistent notifications. +// Class users can use connectChanged() to process persistent notifications +// (see LLNotificationStorage for example). +class LLPersistentNotificationChannel : public LLNotificationChannel +{ +	LOG_CLASS(LLPersistentNotificationChannel); +public: +	LLPersistentNotificationChannel()  +		:	LLNotificationChannel("Persistent", "Visible", ¬ificationFilter) +	{ +	} + +	typedef std::vector<LLNotificationPtr> history_list_t; +	history_list_t::iterator beginHistory() { sortHistory(); return mHistory.begin(); } +	history_list_t::iterator endHistory() { return mHistory.end(); } + +private: + +	void sortHistory() +	{ +		struct sortByTime +		{ +			S32 operator ()(const LLNotificationPtr& a, const LLNotificationPtr& b) +			{ +				return a->getDate() < b->getDate(); +			} +		}; +		std::sort(mHistory.begin(), mHistory.end(), sortByTime()); +	} + + +	// The channel gets all persistent notifications except those that have been canceled +	static bool notificationFilter(LLNotificationPtr pNotification) +	{ +		bool handle_notification = false; + +		handle_notification = pNotification->isPersistent() +			&& !pNotification->isCancelled(); + +		return handle_notification; +	} + +	void onAdd(LLNotificationPtr p)  +	{ +		mHistory.push_back(p); +	} + +	std::vector<LLNotificationPtr> mHistory; +}; +  #endif//LL_LLNOTIFICATIONS_H diff --git a/indra/llui/llsdparam.cpp b/indra/llui/llsdparam.cpp index bcfb38aa11..811e20e810 100644 --- a/indra/llui/llsdparam.cpp +++ b/indra/llui/llsdparam.cpp @@ -283,7 +283,10 @@ void LLParamSDParserUtilities::readSDValues(read_sd_cb_t cb, const LLSD& sd, LLI  			it != sd.endArray();  			++it)  		{ -			stack.back().second = true; +			if (!stack.empty()) +			{ +				stack.back().second = true; +			}  			readSDValues(cb, *it, stack);  		}  	} @@ -336,7 +339,6 @@ namespace LLInitParam  	void ParamValue<LLSD, NOT_BLOCK>::serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block) const  	{  		// read from LLSD value and serialize out to parser (which could be LLSD, XUI, etc) -		Parser::name_stack_t stack; -		LLParamSDParserUtilities::readSDValues(boost::bind(&serializeElement, boost::ref(p), _1, _2), mValue, stack); +		LLParamSDParserUtilities::readSDValues(boost::bind(&serializeElement, boost::ref(p), _1, _2), mValue, name_stack);  	}  } diff --git a/indra/llxuixml/llinitparam.h b/indra/llxuixml/llinitparam.h index 29f4a09cb7..435db1699c 100644 --- a/indra/llxuixml/llinitparam.h +++ b/indra/llxuixml/llinitparam.h @@ -1024,7 +1024,9 @@ namespace LLInitParam  				if (!parser.writeValue(typed_param.getValue(), name_stack))   				{  					std::string calculated_key = typed_param.calcValueName(typed_param.getValue()); -					if (!diff_param || !ParamCompare<std::string>::equals(static_cast<const self_t*>(diff_param)->getValueName(), calculated_key)) +					if (calculated_key.size()  +						&& (!diff_param  +							|| !ParamCompare<std::string>::equals(static_cast<const self_t*>(diff_param)->getValueName(), calculated_key)))  					{  						parser.writeValue(calculated_key, name_stack);  					} diff --git a/indra/newview/llnotificationstorage.cpp b/indra/newview/llnotificationstorage.cpp index fb1adc7ddf..a31b95811e 100644 --- a/indra/newview/llnotificationstorage.cpp +++ b/indra/newview/llnotificationstorage.cpp @@ -84,9 +84,11 @@ bool LLPersistentNotificationStorage::onPersistentChannelChanged(const LLSD& pay  	return false;  } +static LLFastTimer::DeclareTimer FTM_SAVE_NOTIFICATIONS("Save Notifications"); +  void LLPersistentNotificationStorage::saveNotifications()  { -	// TODO - think about save optimization. +	LLFastTimer _(FTM_SAVE_NOTIFICATIONS);  	llofstream notify_file(mFileName.c_str());  	if (!notify_file.is_open()) @@ -98,10 +100,15 @@ void LLPersistentNotificationStorage::saveNotifications()  	LLSD output;  	LLSD& data = output["data"]; -	LLNotificationChannelPtr history_channel = LLNotifications::instance().getChannel("Persistent"); -	LLNotificationSet::iterator it = history_channel->begin(); +	boost::intrusive_ptr<LLPersistentNotificationChannel> history_channel = boost::dynamic_pointer_cast<LLPersistentNotificationChannel>(LLNotifications::instance().getChannel("Persistent")); +	if (!history_channel) +	{ +		return; +	} -	for ( ; history_channel->end() != it; ++it) +	for ( std::vector<LLNotificationPtr>::iterator it = history_channel->beginHistory(), end_it = history_channel->endHistory(); +		it != end_it; +		++it)  	{  		LLNotificationPtr notification = *it; @@ -120,8 +127,11 @@ void LLPersistentNotificationStorage::saveNotifications()  	formatter->format(output, notify_file, LLSDFormatter::OPTIONS_PRETTY);  } +static LLFastTimer::DeclareTimer FTM_LOAD_NOTIFICATIONS("Load Notifications"); +  void LLPersistentNotificationStorage::loadNotifications()  { +	LLFastTimer _(FTM_LOAD_NOTIFICATIONS);  	LLResponderRegistry::registerResponders();  	LLNotifications::instance().getChannel("Persistent")-> diff --git a/indra/newview/lltoastnotifypanel.cpp b/indra/newview/lltoastnotifypanel.cpp index 77a5a5d17d..884df27a18 100644 --- a/indra/newview/lltoastnotifypanel.cpp +++ b/indra/newview/lltoastnotifypanel.cpp @@ -60,19 +60,6 @@ LLToastNotifyPanel::LLToastNotifyPanel(const LLNotificationPtr& notification, co  	LLInstanceTracker(notification->getID())  {  	init(rect, show_images); - - -	//if(notification->isRespondedTo()) -	//{ -	//	// User selected an option in toast, now disable required buttons in IM window -	//	disableRespondedOptions(notification); -	//} -	// -	//if(notification->isReusable()) -	//{ -	//	mButtonClickConnection = sButtonClickSignal.connect( -	//		boost::bind(&LLToastNotifyPanel::disableRespondedOptions, this, notification)); -	//}  }  void LLToastNotifyPanel::addDefaultButton()  { @@ -354,17 +341,6 @@ void LLToastNotifyPanel::onClickButton(void* data)  	{  		response[button_name] = true;  	} -	 -	bool is_reusable = self->mNotification->isReusable(); -	// When we call respond(), LLOfferInfo will delete itself in inventory_offer_callback(),  -	// lets copy it while it's still valid. -	LLOfferInfo* old_info = static_cast<LLOfferInfo*>(self->mNotification->getResponder()); -	LLOfferInfo* new_info = NULL; -	if(is_reusable && old_info) -	{ -		new_info = new LLOfferInfo(*old_info); -		self->mNotification->setResponder(new_info); -	}  	// disable all buttons  	self->mControlPanel->setEnabled(FALSE);  | 
