From 61c27f2663aee60ba6eaeed57341915c8b8b5097 Mon Sep 17 00:00:00 2001
From: brad kittenbrink <brad@lindenlab.com>
Date: Wed, 15 Jul 2009 17:54:11 -0700
Subject: [PATCH] Oops, LLNotificationsListener can't just be forward declared
 under gcc.

---
 indra/llui/llnotifications.h | 1825 +++++++++++++++++-----------------
 1 file changed, 912 insertions(+), 913 deletions(-)

diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h
index 971d11db971..93cdcbeefd0 100644
--- a/indra/llui/llnotifications.h
+++ b/indra/llui/llnotifications.h
@@ -1,913 +1,912 @@
-/**
-* @file llnotifications.h
-* @brief Non-UI manager and support for keeping a prioritized list of notifications
-* @author Q (with assistance from Richard and Coco)
-*
-* $LicenseInfo:firstyear=2008&license=viewergpl$
-* 
-* Copyright (c) 2008-2009, 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_LLNOTIFICATIONS_H
-#define LL_LLNOTIFICATIONS_H
-
-/**
- * This system is intended to provide a singleton mechanism for adding
- * notifications to one of an arbitrary set of event channels.
- * 
- * Controlling JIRA: DEV-9061
- *
- * Every notification has (see code for full list):
- *  - a textual name, which is used to look up its template in the XML files
- *  - a payload, which is a block of LLSD
- *  - a channel, which is normally extracted from the XML files but
- *	  can be overridden.
- *  - a timestamp, used to order the notifications
- *  - expiration time -- if nonzero, specifies a time after which the
- *    notification will no longer be valid.
- *  - a callback name and a couple of status bits related to callbacks (see below)
- * 
- * There is a management class called LLNotifications, which is an LLSingleton.
- * The class maintains a collection of all of the notifications received
- * or processed during this session, and also manages the persistence
- * of those notifications that must be persisted.
- * 
- * We also have Channels. A channel is a view on a collection of notifications;
- * The collection is defined by a filter function that controls which
- * notifications are in the channel, and its ordering is controlled by 
- * a comparator. 
- *
- * There is a hierarchy of channels; notifications flow down from
- * the management class (LLNotifications, which itself inherits from
- * The channel base class) to the individual channels.
- * Any change to notifications (add, delete, modify) is 
- * automatically propagated through the channel hierarchy.
- * 
- * We provide methods for adding a new notification, for removing
- * one, and for managing channels. Channels are relatively cheap to construct
- * and maintain, so in general, human interfaces should use channels to
- * select and manage their lists of notifications.
- * 
- * We also maintain a collection of templates that are loaded from the 
- * XML file of template translations. The system supports substitution
- * of named variables from the payload into the XML file.
- * 
- * By default, only the "unknown message" template is built into the system.
- * It is not an error to add a notification that's not found in the 
- * template system, but it is logged.
- *
- */
-
-#include <string>
-#include <list>
-#include <vector>
-#include <map>
-#include <set>
-#include <iomanip>
-#include <sstream>
-
-#include <boost/utility.hpp>
-#include <boost/shared_ptr.hpp>
-#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 "llui.h"
-#include "llmemory.h"
-
-class LLNotification;
-typedef boost::shared_ptr<LLNotification> LLNotificationPtr;
-
-	
-typedef enum e_notification_priority
-{
-	NOTIFICATION_PRIORITY_UNSPECIFIED,
-	NOTIFICATION_PRIORITY_LOW,
-	NOTIFICATION_PRIORITY_NORMAL,
-	NOTIFICATION_PRIORITY_HIGH,
-	NOTIFICATION_PRIORITY_CRITICAL
-} ENotificationPriority;
-
-typedef boost::function<void (const LLSD&, const LLSD&)> LLNotificationResponder;
-
-typedef LLFunctorRegistry<LLNotificationResponder> LLNotificationFunctorRegistry;
-typedef LLFunctorRegistration<LLNotificationResponder> LLNotificationFunctorRegistration;
-
-// context data that can be looked up via a notification's payload by the display logic
-// derive from this class to implement specific contexts
-class LLNotificationContext : public LLInstanceTracker<LLNotificationContext, LLUUID>
-{
-public:
-	LLNotificationContext() : LLInstanceTracker<LLNotificationContext, LLUUID>(LLUUID::generateNewID())
-	{
-	}
-
-	virtual ~LLNotificationContext() {}
-
-	LLSD asLLSD() const
-	{
-		return getKey();
-	}
-
-private:
-
-};
-
-// Contains notification form data, such as buttons and text fields along with
-// manipulator functions
-class LLNotificationForm
-{
-	LOG_CLASS(LLNotificationForm);
-
-public:
-	typedef enum e_ignore_type
-	{ 
-		IGNORE_NO,
-		IGNORE_WITH_DEFAULT_RESPONSE, 
-		IGNORE_WITH_LAST_RESPONSE, 
-		IGNORE_SHOW_AGAIN 
-	} EIgnoreType;
-
-	LLNotificationForm();
-	LLNotificationForm(const LLSD& sd);
-	LLNotificationForm(const std::string& name, const LLXMLNodePtr xml_node);
-
-	LLSD asLLSD() const;
-
-	S32 getNumElements() { return mFormData.size(); }
-	LLSD getElement(S32 index) { return mFormData.get(index); }
-	LLSD getElement(const std::string& element_name);
-	bool hasElement(const std::string& element_name);
-	void addElement(const std::string& type, const std::string& name, const LLSD& value = LLSD());
-	void formatElements(const LLSD& substitutions);
-	// appends form elements from another form serialized as LLSD
-	void append(const LLSD& sub_form);
-	std::string getDefaultOption();
-
-	EIgnoreType getIgnoreType() { return mIgnore; }
-	std::string getIgnoreMessage() { return mIgnoreMsg; }
-
-private:
-	LLSD	mFormData;
-	EIgnoreType mIgnore;
-	std::string mIgnoreMsg;
-};
-
-typedef boost::shared_ptr<LLNotificationForm> LLNotificationFormPtr;
-
-// This is the class of object read from the XML file (notifications.xml, 
-// from the appropriate local language directory).
-struct LLNotificationTemplate
-{
-	LLNotificationTemplate();
-    // the name of the notification -- the key used to identify it
-    // Ideally, the key should follow variable naming rules 
-    // (no spaces or punctuation).
-    std::string mName;
-    // The type of the notification
-    // used to control which queue it's stored in
-    std::string mType;
-    // The text used to display the notification. Replaceable parameters
-    // are enclosed in square brackets like this [].
-    std::string mMessage;
-	// The label for the notification; used for 
-	// certain classes of notification (those with a window and a window title). 
-	// Also used when a notification pops up underneath the current one.
-	// Replaceable parameters can be used in the label.
-	std::string mLabel;
-	// The name of the icon image. This should include an extension.
-	std::string mIcon;
-    // This is the Highlander bit -- "There Can Be Only One"
-    // An outstanding notification with this bit set
-    // is updated by an incoming notification with the same name,
-    // rather than creating a new entry in the queue.
-    // (used for things like progress indications, or repeating warnings
-    // like "the grid is going down in N minutes")
-    bool mUnique;
-    // if we want to be unique only if a certain part of the payload is constant
-    // specify the field names for the payload. The notification will only be
-    // combined if all of the fields named in the context are identical in the
-    // new and the old notification; otherwise, the notification will be
-    // duplicated. This is to support suppressing duplicate offers from the same
-    // sender but still differentiating different offers. Example: Invitation to
-    // conference chat.
-    std::vector<std::string> mUniqueContext;
-    // If this notification expires automatically, this value will be 
-    // nonzero, and indicates the number of seconds for which the notification
-    // will be valid (a teleport offer, for example, might be valid for 
-    // 300 seconds). 
-    U32 mExpireSeconds;
-    // if the offer expires, one of the options is chosen automatically
-    // based on its "value" parameter. This controls which one. 
-    // If expireSeconds is specified, expireOption should also be specified.
-    U32 mExpireOption;
-    // if the notification contains a url, it's stored here (and replaced 
-    // into the message where [_URL] is found)
-    std::string mURL;
-    // if there's a URL in the message, this controls which option visits
-    // that URL. Obsolete this and eliminate the buttons for affected
-    // messages when we allow clickable URLs in the UI
-    U32 mURLOption;
-	
-	U32 mURLOpenExternally;
-	//This is a flag that tells if the url needs to open externally dispite 
-	//what the user setting is.
-	
-	// does this notification persist across sessions? if so, it will be
-	// serialized to disk on first receipt and read on startup
-	bool mPersist;
-	// This is the name of the default functor, if present, to be
-	// used for the notification's callback. It is optional, and used only if 
-	// the notification is constructed without an identified functor.
-	std::string mDefaultFunctor;
-	// The form data associated with a given notification (buttons, text boxes, etc)
-    LLNotificationFormPtr mForm;
-	// default priority for notifications of this type
-	ENotificationPriority mPriority;
-	// UUID of the audio file to be played when this notification arrives
-	// this is loaded as a name, but looked up to get the UUID upon template load.
-	// If null, it wasn't specified.
-	LLUUID mSoundEffect;
-};
-
-// we want to keep a map of these by name, and it's best to manage them
-// with smart pointers
-typedef boost::shared_ptr<LLNotificationTemplate> LLNotificationTemplatePtr;
-
-/**
- * @class LLNotification
- * @brief The object that expresses the details of a notification
- * 
- * We make this noncopyable because
- * we want to manage these through LLNotificationPtr, and only
- * ever create one instance of any given notification.
- * 
- * The enable_shared_from_this flag ensures that if we construct
- * a smart pointer from a notification, we'll always get the same
- * shared pointer.
- */
-class LLNotification  : 
-	boost::noncopyable,
-	public boost::enable_shared_from_this<LLNotification>
-{
-LOG_CLASS(LLNotification);
-friend class LLNotifications;
-
-public:
-	// parameter object used to instantiate a new notification
-	struct Params : public LLInitParam::Block<Params>
-	{
-		friend class LLNotification;
-	
-		Mandatory<std::string>					name;
-
-		// optional
-		Optional<LLSD>							substitutions;
-		Optional<LLSD>							payload;
-		Optional<ENotificationPriority>			priority;
-		Optional<LLSD>							form_elements;
-		Optional<LLDate>						timestamp;
-		Optional<LLNotificationContext*>		context;
-
-		struct Functor : public LLInitParam::Choice<Functor>
-		{
-			Alternative<std::string>										name;
-			Alternative<LLNotificationFunctorRegistry::ResponseFunctor>	function;
-
-			Functor()
-			:	name("functor_name"),
-				function("functor")
-			{}
-		};
-		Optional<Functor>						functor;
-
-		Params()
-		:	name("name"),
-			priority("priority", NOTIFICATION_PRIORITY_UNSPECIFIED),
-			timestamp("time_stamp")
-		{
-			timestamp = LLDate::now();
-		}
-
-		Params(const std::string& _name) 
-			:	name("name"),
-				priority("priority", NOTIFICATION_PRIORITY_UNSPECIFIED),
-				timestamp("time_stamp")
-		{
-			functor.name = _name;
-			name = _name;
-			timestamp = LLDate::now();
-		}
-	};
-
-private:
-	
-	LLUUID mId;
-	LLSD mPayload;
-	LLSD mSubstitutions;
-	LLDate mTimestamp;
-	LLDate mExpiresAt;
-	bool mCancelled;
-	bool mRespondedTo; 	// once the notification has been responded to, this becomes true
-	bool mIgnored;
-	ENotificationPriority mPriority;
-	LLNotificationFormPtr mForm;
-	
-	// a reference to the template
-	LLNotificationTemplatePtr mTemplatep;
-	
-	/*
-	 We want to be able to store and reload notifications so that they can survive
-	 a shutdown/restart of the client. So we can't simply pass in callbacks;
-	 we have to specify a callback mechanism that can be used by name rather than 
-	 by some arbitrary pointer -- and then people have to initialize callbacks 
-	 in some useful location. So we use LLNotificationFunctorRegistry to manage them.
-	 */
-	 std::string mResponseFunctorName;
-	
-	/*
-	 In cases where we want to specify an explict, non-persisted callback, 
-	 we store that in the callback registry under a dynamically generated
-	 key, and store the key in the notification, so we can still look it up
-	 using the same mechanism.
-	 */
-	bool mTemporaryResponder;
-
-	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) {}
-
-	void cancel();
-
-	bool payloadContainsAll(const std::vector<std::string>& required_fields) const;
-
-public:
-
-	// constructor from a saved notification
-	LLNotification(const LLSD& sd);
-
-	void setResponseFunctor(std::string const &responseFunctorName);
-
-	typedef enum e_response_template_type
-	{
-		WITHOUT_DEFAULT_BUTTON,
-		WITH_DEFAULT_BUTTON
-	} EResponseTemplateType;
-
-	// return response LLSD filled in with default form contents and (optionally) the default button selected
-	LLSD getResponseTemplate(EResponseTemplateType type = WITHOUT_DEFAULT_BUTTON);
-
-	// returns index of first button with value==TRUE
-	// usually this the button the user clicked on
-	// returns -1 if no button clicked (e.g. form has not been displayed)
-	static S32 getSelectedOption(const LLSD& notification, const LLSD& response);
-	// returns name of first button with value==TRUE
-	static std::string getSelectedOptionName(const LLSD& notification);
-
-	// after someone responds to a notification (usually by clicking a button,
-	// but sometimes by filling out a little form and THEN clicking a button),
-    // the result of the response (the name and value of the button clicked,
-	// plus any other data) should be packaged up as LLSD, then passed as a
-	// parameter to the notification's respond() method here. This will look up
-	// and call the appropriate responder.
-	//
-	// response is notification serialized as LLSD:
-	// ["name"] = notification name
-	// ["form"] = LLSD tree that includes form description and any prefilled form data
-	// ["response"] = form data filled in by user
-	// (including, but not limited to which button they clicked on)
-	// ["payload"] = transaction specific data, such as ["source_id"] (originator of notification),  
-	//				["item_id"] (attached inventory item), etc.
-	// ["substitutions"] = string substitutions used to generate notification message
-    // from the template
-	// ["time"] = time at which notification was generated;
-	// ["expiry"] = time at which notification expires;
-	// ["responseFunctor"] = name of registered functor that handles responses to notification;
-	LLSD asLLSD();
-
-	void respond(const LLSD& sd);
-
-	void setIgnored(bool ignore);
-
-	bool isCancelled() const
-	{
-		return mCancelled;
-	}
-
-	bool isRespondedTo() const
-	{
-		return mRespondedTo;
-	}
-
-	bool isIgnored() const
-	{
-		return mIgnored;
-	}
-
-	const std::string& getName() const
-	{
-		return mTemplatep->mName;
-	}
-	
-	const LLUUID& id() const
-	{
-		return mId;
-	}
-	
-	const LLSD& getPayload() const
-	{
-		return mPayload;
-	}
-
-	const LLSD& getSubstitutions() const
-	{
-		return mSubstitutions;
-	}
-
-	const LLDate& getDate() const
-	{
-		return mTimestamp;
-	}
-
-	std::string getType() const
-	{
-		return (mTemplatep ? mTemplatep->mType : "");
-	}
-
-	std::string getMessage() const;
-	std::string getLabel() const;
-
-	std::string getURL() const;
-//	{
-//		return (mTemplatep ? mTemplatep->mURL : "");
-//	}
-
-	S32 getURLOption() const
-	{
-		return (mTemplatep ? mTemplatep->mURLOption : -1);
-	}
-    
-	S32 getURLOpenExternally() const
-	{
-		return(mTemplatep? mTemplatep->mURLOpenExternally : -1);
-	}
-	
-	const LLNotificationFormPtr getForm();
-
-	const LLDate getExpiration() const
-	{
-		return mExpiresAt;
-	}
-
-	ENotificationPriority getPriority() const
-	{
-		return mPriority;
-	}
-
-	const LLUUID getID() const
-	{
-		return mId;
-	}
-	
-	// comparing two notifications normally means comparing them by UUID (so we can look them
-	// up quickly this way)
-	bool operator<(const LLNotification& rhs) const
-	{
-		return mId < rhs.mId;
-	}
-
-	bool operator==(const LLNotification& rhs) const
-	{
-		return mId == rhs.mId;
-	}
-
-	bool operator!=(const LLNotification& rhs) const
-	{
-		return !operator==(rhs);
-	}
-
-	bool isSameObjectAs(const LLNotification* rhs) const
-	{
-		return this == rhs;
-	}
-	
-	// this object has been updated, so tell all our clients
-	void update();
-
-	void updateFrom(LLNotificationPtr other);
-	
-	// A fuzzy equals comparator.
-	// true only if both notifications have the same template and 
-	//     1) flagged as unique (there can be only one of these) OR 
-	//     2) all required payload fields of each also exist in the other.
-	bool isEquivalentTo(LLNotificationPtr that) const;
-	
-	// if the current time is greater than the expiration, the notification is expired
-	bool isExpired() const
-	{
-		if (mExpiresAt.secondsSinceEpoch() == 0)
-		{
-			return false;
-		}
-		
-		LLDate rightnow = LLDate::now();
-		return rightnow > mExpiresAt;
-	}
-	
-	std::string summarize() const;
-
-	bool hasUniquenessConstraints() const { return (mTemplatep ? mTemplatep->mUnique : false);}
-
-	virtual ~LLNotification() {}
-};
-
-std::ostream& operator<<(std::ostream& s, const LLNotification& notification);
-
-namespace LLNotificationFilters
-{
-	// a sample filter
-	bool includeEverything(LLNotificationPtr p);
-
-	typedef enum e_comparison 
-	{ 
-		EQUAL, 
-		LESS, 
-		GREATER, 
-		LESS_EQUAL, 
-		GREATER_EQUAL 
-	} EComparison;
-
-	// generic filter functor that takes method or member variable reference
-	template<typename T>
-	struct filterBy
-	{
-		typedef boost::function<T (LLNotificationPtr)>	field_t;
-		typedef typename boost::remove_reference<T>::type		value_t;
-		
-		filterBy(field_t field, value_t value, EComparison comparison = EQUAL) 
-			:	mField(field), 
-				mFilterValue(value),
-				mComparison(comparison)
-		{
-		}		
-		
-		bool operator()(LLNotificationPtr p)
-		{
-			switch(mComparison)
-			{
-			case EQUAL:
-				return mField(p) == mFilterValue;
-			case LESS:
-				return mField(p) < mFilterValue;
-			case GREATER:
-				return mField(p) > mFilterValue;
-			case LESS_EQUAL:
-				return mField(p) <= mFilterValue;
-			case GREATER_EQUAL:
-				return mField(p) >= mFilterValue;
-			default:
-				return false;
-			}
-		}
-
-		field_t mField;
-		value_t	mFilterValue;
-		EComparison mComparison;
-	};
-};
-
-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
-	{
-		typedef boost::function<T (LLNotificationPtr)> field_t;
-		orderBy(field_t field, EDirection = ORDER_INCREASING) : mField(field) {}
-		bool operator()(LLNotificationPtr lhs, LLNotificationPtr rhs)
-		{
-			if (mDirection == ORDER_DECREASING)
-			{
-				return mField(lhs) > mField(rhs);
-			}
-			else
-			{
-				return mField(lhs) < mField(rhs);
-			}
-		}
-
-		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::multimap<std::string, LLNotificationPtr> LLNotificationMap;
-
-// ========================================================
-// Abstract base class (interface) for a channel; also used for the master container.
-// This lets us arrange channels into a call hierarchy.
-
-// We maintain a heirarchy of notification channels; events are always started at the top
-// and propagated through the hierarchy only if they pass a filter.
-// Any channel can be created with a parent. A null parent (empty string) means it's
-// tied to the root of the tree (the LLNotifications class itself).
-// The default hierarchy looks like this:
-//
-// LLNotifications --+-- Expiration --+-- Mute --+-- Ignore --+-- Visible --+-- History
-//                                                                          +-- Alerts
-//                                                                          +-- Notifications
-//
-// In general, new channels that want to only see notifications that pass through 
-// all of the built-in tests should attach to the "Visible" channel
-//
-class LLNotificationChannelBase :
-	public LLEventTrackable
-{
-	LOG_CLASS(LLNotificationChannelBase);
-public:
-	LLNotificationChannelBase(LLNotificationFilter filter, LLNotificationComparator comp) : 
-		mFilter(filter), mItems(comp) 
-	{}
-	virtual ~LLNotificationChannelBase() {}
-	// you can also connect to a Channel, so you can be notified of
-	// changes to this channel
-	template <typename LISTENER>
-    LLBoundListener connectChanged(const LISTENER& slot)
-    {
-        // Examine slot to see if it binds an LLEventTrackable subclass, or a
-        // boost::shared_ptr to something, or a boost::weak_ptr to something.
-        // Call this->connectChangedImpl() to actually connect it.
-        return LLEventDetail::visit_and_connect(slot,
-                                  boost::bind(&LLNotificationChannelBase::connectChangedImpl,
-                                              this,
-                                              _1));
-    }
-    template <typename LISTENER>
-	LLBoundListener connectPassedFilter(const LISTENER& slot)
-    {
-        // see comments in connectChanged()
-        return LLEventDetail::visit_and_connect(slot,
-                                  boost::bind(&LLNotificationChannelBase::connectPassedFilterImpl,
-                                              this,
-                                              _1));
-    }
-    template <typename LISTENER>
-	LLBoundListener connectFailedFilter(const LISTENER& slot)
-    {
-        // see comments in connectChanged()
-        return LLEventDetail::visit_and_connect(slot,
-                                  boost::bind(&LLNotificationChannelBase::connectFailedFilterImpl,
-                                              this,
-                                              _1));
-    }
-
-	// use this when items change or to add a new one
-	bool updateItem(const LLSD& payload);
-	const LLNotificationFilter& getFilter() { return mFilter; }
-
-protected:
-    LLBoundListener connectChangedImpl(const LLEventListener& slot);
-    LLBoundListener connectPassedFilterImpl(const LLEventListener& slot);
-    LLBoundListener connectFailedFilterImpl(const LLEventListener& slot);
-
-	LLNotificationSet mItems;
-	LLStandardSignal mChanged;
-	LLStandardSignal mPassedFilter;
-	LLStandardSignal mFailedFilter;
-	
-	// these are action methods that subclasses can override to take action 
-	// on specific types of changes; the management of the mItems list is
-	// still handled by the generic handler.
-	virtual void onLoad(LLNotificationPtr p) {}
-	virtual void onAdd(LLNotificationPtr p) {}
-	virtual void onDelete(LLNotificationPtr p) {}
-	virtual void onChange(LLNotificationPtr p) {}
-
-	bool updateItem(const LLSD& payload, LLNotificationPtr pNotification);
-	LLNotificationFilter mFilter;
-};
-
-// The type of the pointers that we're going to manage in the NotificationQueue system
-// Because LLNotifications is a singleton, we don't actually expect to ever 
-// destroy it, but if it becomes necessary to do so, the shared_ptr model
-// will ensure that we don't leak resources.
-class LLNotificationChannel;
-typedef boost::shared_ptr<LLNotificationChannel> LLNotificationChannelPtr;
-
-// manages a list of notifications
-// Note that if this is ever copied around, we might find ourselves with multiple copies
-// of a queue with notifications being added to different nonequivalent copies. So we 
-// make it inherit from boost::noncopyable, and then create a map of shared_ptr to manage it.
-// 
-// NOTE: LLNotificationChannel is self-registering. The *correct* way to create one is to 
-// do something like:
-//		LLNotificationChannel::buildChannel("name", "parent"...);
-// This returns an LLNotificationChannelPtr, which you can store, or
-// you can then retrieve the channel by using the registry:
-//		LLNotifications::instance().getChannel("name")...
-//
-class LLNotificationChannel : 
-	boost::noncopyable, 
-	public LLNotificationChannelBase
-{
-	LOG_CLASS(LLNotificationChannel);
-
-public:  
-	virtual ~LLNotificationChannel() {}
-	typedef LLNotificationSet::iterator Iterator;
-    
-	std::string getName() const { return mName; }
-	std::string getParentChannelName() { return mParent; }
-    
-    bool isEmpty() const;
-    
-    Iterator begin();
-    Iterator end();
-
-    // Channels have a comparator to control sort order;
-	// the default sorts by arrival date
-    void setComparator(LLNotificationComparator comparator);
-	
-	std::string summarize();
-
-	// factory method for constructing these channels; since they're self-registering,
-	// we want to make sure that you can't use new to make them
-	static LLNotificationChannelPtr buildChannel(const std::string& name, const std::string& parent,
-						LLNotificationFilter filter=LLNotificationFilters::includeEverything, 
-						LLNotificationComparator comparator=LLNotificationComparators::orderByUUID());
-	
-protected:
-    // Notification Channels have a filter, which determines which notifications
-	// will be added to this channel. 
-	// Channel filters cannot change.
-	// Channels have a protected constructor so you can't make smart pointers that don't 
-	// come from our internal reference; call NotificationChannel::build(args)
-	LLNotificationChannel(const std::string& name, const std::string& parent,
-						  LLNotificationFilter filter, LLNotificationComparator comparator);
-
-private:
-	std::string mName;
-	std::string mParent;
-	LLNotificationComparator mComparator;
-};
-
-
-class LLNotificationsListener;
-
-class LLNotifications : 
-	public LLSingleton<LLNotifications>, 
-	public LLNotificationChannelBase
-{
-	LOG_CLASS(LLNotifications);
-
-	friend class LLSingleton<LLNotifications>;
-public:
-	// load notification descriptions from file; 
-	// OK to call more than once because it will reload
-	bool loadTemplates();  
-	LLXMLNodePtr checkForXMLTemplate(LLXMLNodePtr item);
-	
-	// Add a simple notification (from XUI)
-	void addFromCallback(const LLSD& name);
-	
-	// we provide a collection of simple add notification functions so that it's reasonable to create notifications in one line
-	LLNotificationPtr add(const std::string& name, 
-						const LLSD& substitutions = LLSD(), 
-						const LLSD& payload = LLSD());
-	LLNotificationPtr add(const std::string& name, 
-						const LLSD& substitutions, 
-						const LLSD& payload, 
-						const std::string& functor_name);
-	LLNotificationPtr add(const std::string& name, 
-						const LLSD& substitutions, 
-						const LLSD& payload, 
-						LLNotificationFunctorRegistry::ResponseFunctor functor);
-	LLNotificationPtr add(const LLNotification::Params& p);
-
-	void add(const LLNotificationPtr pNotif);
-	void cancel(LLNotificationPtr pNotif);
-	void update(const LLNotificationPtr pNotif);
-
-	LLNotificationPtr find(LLUUID uuid);
-	
-	typedef boost::function<void (LLNotificationPtr)> NotificationProcess;
-	
-	void forEachNotification(NotificationProcess process);
-
-	// This is all stuff for managing the templates
-	// take your template out
-	LLNotificationTemplatePtr getTemplate(const std::string& name);
-	
-	// get the whole collection
-	typedef std::vector<std::string> TemplateNames;
-	TemplateNames getTemplateNames() const;  // returns a list of notification names
-	
-	typedef std::map<std::string, LLNotificationTemplatePtr> TemplateMap;
-
-	TemplateMap::const_iterator templatesBegin() { return mTemplates.begin(); }
-	TemplateMap::const_iterator templatesEnd() { return mTemplates.end(); }
-
-	// test for existence
-	bool templateExists(const std::string& name);
-	// useful if you're reloading the file
-	void clearTemplates();   // erase all templates
-
-	void forceResponse(const LLNotification::Params& params, S32 option);
-
-	void createDefaultChannels();
-
-	typedef std::map<std::string, LLNotificationChannelPtr> ChannelMap;
-	ChannelMap mChannels;
-
-	void addChannel(LLNotificationChannelPtr pChan);
-	LLNotificationChannelPtr getChannel(const std::string& channelName);
-	
-	std::string getGlobalString(const std::string& key) const;
-
-	void setIgnoreAllNotifications(bool ignore);
-	bool getIgnoreAllNotifications();
-
-private:
-	// we're a singleton, so we don't have a public constructor
-	LLNotifications();
-	/*virtual*/ void initSingleton();
-	
-	void loadPersistentNotifications();
-
-	bool expirationFilter(LLNotificationPtr pNotification);
-	bool expirationHandler(const LLSD& payload);
-	bool uniqueFilter(LLNotificationPtr pNotification);
-	bool uniqueHandler(const LLSD& payload);
-	bool failedUniquenessTest(const LLSD& payload);
-	LLNotificationChannelPtr pHistoryChannel;
-	LLNotificationChannelPtr pExpirationChannel;
-	
-	// put your template in
-	bool addTemplate(const std::string& name, LLNotificationTemplatePtr theTemplate);
-	TemplateMap mTemplates;
-
-	std::string mFileName;
-	
-	typedef std::map<std::string, LLXMLNodePtr> XMLTemplateMap;
-	XMLTemplateMap mXmlTemplates;
-
-	LLNotificationMap mUniqueNotifications;
-	
-	typedef std::map<std::string, std::string> GlobalStringMap;
-	GlobalStringMap mGlobalStrings;
-
-	bool mIgnoreAllNotifications;
-
-    boost::scoped_ptr<LLNotificationsListener> mListener;
-};
-
-
-#endif//LL_LLNOTIFICATIONS_H
-
+/**
+* @file llnotifications.h
+* @brief Non-UI manager and support for keeping a prioritized list of notifications
+* @author Q (with assistance from Richard and Coco)
+*
+* $LicenseInfo:firstyear=2008&license=viewergpl$
+* 
+* Copyright (c) 2008-2009, 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_LLNOTIFICATIONS_H
+#define LL_LLNOTIFICATIONS_H
+
+/**
+ * This system is intended to provide a singleton mechanism for adding
+ * notifications to one of an arbitrary set of event channels.
+ * 
+ * Controlling JIRA: DEV-9061
+ *
+ * Every notification has (see code for full list):
+ *  - a textual name, which is used to look up its template in the XML files
+ *  - a payload, which is a block of LLSD
+ *  - a channel, which is normally extracted from the XML files but
+ *	  can be overridden.
+ *  - a timestamp, used to order the notifications
+ *  - expiration time -- if nonzero, specifies a time after which the
+ *    notification will no longer be valid.
+ *  - a callback name and a couple of status bits related to callbacks (see below)
+ * 
+ * There is a management class called LLNotifications, which is an LLSingleton.
+ * The class maintains a collection of all of the notifications received
+ * or processed during this session, and also manages the persistence
+ * of those notifications that must be persisted.
+ * 
+ * We also have Channels. A channel is a view on a collection of notifications;
+ * The collection is defined by a filter function that controls which
+ * notifications are in the channel, and its ordering is controlled by 
+ * a comparator. 
+ *
+ * There is a hierarchy of channels; notifications flow down from
+ * the management class (LLNotifications, which itself inherits from
+ * The channel base class) to the individual channels.
+ * Any change to notifications (add, delete, modify) is 
+ * automatically propagated through the channel hierarchy.
+ * 
+ * We provide methods for adding a new notification, for removing
+ * one, and for managing channels. Channels are relatively cheap to construct
+ * and maintain, so in general, human interfaces should use channels to
+ * select and manage their lists of notifications.
+ * 
+ * We also maintain a collection of templates that are loaded from the 
+ * XML file of template translations. The system supports substitution
+ * of named variables from the payload into the XML file.
+ * 
+ * By default, only the "unknown message" template is built into the system.
+ * It is not an error to add a notification that's not found in the 
+ * template system, but it is logged.
+ *
+ */
+
+#include <string>
+#include <list>
+#include <vector>
+#include <map>
+#include <set>
+#include <iomanip>
+#include <sstream>
+
+#include <boost/utility.hpp>
+#include <boost/shared_ptr.hpp>
+#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 "llui.h"
+#include "llmemory.h"
+#include "llnotificationslistener.h"
+
+class LLNotification;
+typedef boost::shared_ptr<LLNotification> LLNotificationPtr;
+
+	
+typedef enum e_notification_priority
+{
+	NOTIFICATION_PRIORITY_UNSPECIFIED,
+	NOTIFICATION_PRIORITY_LOW,
+	NOTIFICATION_PRIORITY_NORMAL,
+	NOTIFICATION_PRIORITY_HIGH,
+	NOTIFICATION_PRIORITY_CRITICAL
+} ENotificationPriority;
+
+typedef boost::function<void (const LLSD&, const LLSD&)> LLNotificationResponder;
+
+typedef LLFunctorRegistry<LLNotificationResponder> LLNotificationFunctorRegistry;
+typedef LLFunctorRegistration<LLNotificationResponder> LLNotificationFunctorRegistration;
+
+// context data that can be looked up via a notification's payload by the display logic
+// derive from this class to implement specific contexts
+class LLNotificationContext : public LLInstanceTracker<LLNotificationContext, LLUUID>
+{
+public:
+	LLNotificationContext() : LLInstanceTracker<LLNotificationContext, LLUUID>(LLUUID::generateNewID())
+	{
+	}
+
+	virtual ~LLNotificationContext() {}
+
+	LLSD asLLSD() const
+	{
+		return getKey();
+	}
+
+private:
+
+};
+
+// Contains notification form data, such as buttons and text fields along with
+// manipulator functions
+class LLNotificationForm
+{
+	LOG_CLASS(LLNotificationForm);
+
+public:
+	typedef enum e_ignore_type
+	{ 
+		IGNORE_NO,
+		IGNORE_WITH_DEFAULT_RESPONSE, 
+		IGNORE_WITH_LAST_RESPONSE, 
+		IGNORE_SHOW_AGAIN 
+	} EIgnoreType;
+
+	LLNotificationForm();
+	LLNotificationForm(const LLSD& sd);
+	LLNotificationForm(const std::string& name, const LLXMLNodePtr xml_node);
+
+	LLSD asLLSD() const;
+
+	S32 getNumElements() { return mFormData.size(); }
+	LLSD getElement(S32 index) { return mFormData.get(index); }
+	LLSD getElement(const std::string& element_name);
+	bool hasElement(const std::string& element_name);
+	void addElement(const std::string& type, const std::string& name, const LLSD& value = LLSD());
+	void formatElements(const LLSD& substitutions);
+	// appends form elements from another form serialized as LLSD
+	void append(const LLSD& sub_form);
+	std::string getDefaultOption();
+
+	EIgnoreType getIgnoreType() { return mIgnore; }
+	std::string getIgnoreMessage() { return mIgnoreMsg; }
+
+private:
+	LLSD	mFormData;
+	EIgnoreType mIgnore;
+	std::string mIgnoreMsg;
+};
+
+typedef boost::shared_ptr<LLNotificationForm> LLNotificationFormPtr;
+
+// This is the class of object read from the XML file (notifications.xml, 
+// from the appropriate local language directory).
+struct LLNotificationTemplate
+{
+	LLNotificationTemplate();
+    // the name of the notification -- the key used to identify it
+    // Ideally, the key should follow variable naming rules 
+    // (no spaces or punctuation).
+    std::string mName;
+    // The type of the notification
+    // used to control which queue it's stored in
+    std::string mType;
+    // The text used to display the notification. Replaceable parameters
+    // are enclosed in square brackets like this [].
+    std::string mMessage;
+	// The label for the notification; used for 
+	// certain classes of notification (those with a window and a window title). 
+	// Also used when a notification pops up underneath the current one.
+	// Replaceable parameters can be used in the label.
+	std::string mLabel;
+	// The name of the icon image. This should include an extension.
+	std::string mIcon;
+    // This is the Highlander bit -- "There Can Be Only One"
+    // An outstanding notification with this bit set
+    // is updated by an incoming notification with the same name,
+    // rather than creating a new entry in the queue.
+    // (used for things like progress indications, or repeating warnings
+    // like "the grid is going down in N minutes")
+    bool mUnique;
+    // if we want to be unique only if a certain part of the payload is constant
+    // specify the field names for the payload. The notification will only be
+    // combined if all of the fields named in the context are identical in the
+    // new and the old notification; otherwise, the notification will be
+    // duplicated. This is to support suppressing duplicate offers from the same
+    // sender but still differentiating different offers. Example: Invitation to
+    // conference chat.
+    std::vector<std::string> mUniqueContext;
+    // If this notification expires automatically, this value will be 
+    // nonzero, and indicates the number of seconds for which the notification
+    // will be valid (a teleport offer, for example, might be valid for 
+    // 300 seconds). 
+    U32 mExpireSeconds;
+    // if the offer expires, one of the options is chosen automatically
+    // based on its "value" parameter. This controls which one. 
+    // If expireSeconds is specified, expireOption should also be specified.
+    U32 mExpireOption;
+    // if the notification contains a url, it's stored here (and replaced 
+    // into the message where [_URL] is found)
+    std::string mURL;
+    // if there's a URL in the message, this controls which option visits
+    // that URL. Obsolete this and eliminate the buttons for affected
+    // messages when we allow clickable URLs in the UI
+    U32 mURLOption;
+	
+	U32 mURLOpenExternally;
+	//This is a flag that tells if the url needs to open externally dispite 
+	//what the user setting is.
+	
+	// does this notification persist across sessions? if so, it will be
+	// serialized to disk on first receipt and read on startup
+	bool mPersist;
+	// This is the name of the default functor, if present, to be
+	// used for the notification's callback. It is optional, and used only if 
+	// the notification is constructed without an identified functor.
+	std::string mDefaultFunctor;
+	// The form data associated with a given notification (buttons, text boxes, etc)
+    LLNotificationFormPtr mForm;
+	// default priority for notifications of this type
+	ENotificationPriority mPriority;
+	// UUID of the audio file to be played when this notification arrives
+	// this is loaded as a name, but looked up to get the UUID upon template load.
+	// If null, it wasn't specified.
+	LLUUID mSoundEffect;
+};
+
+// we want to keep a map of these by name, and it's best to manage them
+// with smart pointers
+typedef boost::shared_ptr<LLNotificationTemplate> LLNotificationTemplatePtr;
+
+/**
+ * @class LLNotification
+ * @brief The object that expresses the details of a notification
+ * 
+ * We make this noncopyable because
+ * we want to manage these through LLNotificationPtr, and only
+ * ever create one instance of any given notification.
+ * 
+ * The enable_shared_from_this flag ensures that if we construct
+ * a smart pointer from a notification, we'll always get the same
+ * shared pointer.
+ */
+class LLNotification  : 
+	boost::noncopyable,
+	public boost::enable_shared_from_this<LLNotification>
+{
+LOG_CLASS(LLNotification);
+friend class LLNotifications;
+
+public:
+	// parameter object used to instantiate a new notification
+	struct Params : public LLInitParam::Block<Params>
+	{
+		friend class LLNotification;
+	
+		Mandatory<std::string>					name;
+
+		// optional
+		Optional<LLSD>							substitutions;
+		Optional<LLSD>							payload;
+		Optional<ENotificationPriority>			priority;
+		Optional<LLSD>							form_elements;
+		Optional<LLDate>						timestamp;
+		Optional<LLNotificationContext*>		context;
+
+		struct Functor : public LLInitParam::Choice<Functor>
+		{
+			Alternative<std::string>										name;
+			Alternative<LLNotificationFunctorRegistry::ResponseFunctor>	function;
+
+			Functor()
+			:	name("functor_name"),
+				function("functor")
+			{}
+		};
+		Optional<Functor>						functor;
+
+		Params()
+		:	name("name"),
+			priority("priority", NOTIFICATION_PRIORITY_UNSPECIFIED),
+			timestamp("time_stamp")
+		{
+			timestamp = LLDate::now();
+		}
+
+		Params(const std::string& _name) 
+			:	name("name"),
+				priority("priority", NOTIFICATION_PRIORITY_UNSPECIFIED),
+				timestamp("time_stamp")
+		{
+			functor.name = _name;
+			name = _name;
+			timestamp = LLDate::now();
+		}
+	};
+
+private:
+	
+	LLUUID mId;
+	LLSD mPayload;
+	LLSD mSubstitutions;
+	LLDate mTimestamp;
+	LLDate mExpiresAt;
+	bool mCancelled;
+	bool mRespondedTo; 	// once the notification has been responded to, this becomes true
+	bool mIgnored;
+	ENotificationPriority mPriority;
+	LLNotificationFormPtr mForm;
+	
+	// a reference to the template
+	LLNotificationTemplatePtr mTemplatep;
+	
+	/*
+	 We want to be able to store and reload notifications so that they can survive
+	 a shutdown/restart of the client. So we can't simply pass in callbacks;
+	 we have to specify a callback mechanism that can be used by name rather than 
+	 by some arbitrary pointer -- and then people have to initialize callbacks 
+	 in some useful location. So we use LLNotificationFunctorRegistry to manage them.
+	 */
+	 std::string mResponseFunctorName;
+	
+	/*
+	 In cases where we want to specify an explict, non-persisted callback, 
+	 we store that in the callback registry under a dynamically generated
+	 key, and store the key in the notification, so we can still look it up
+	 using the same mechanism.
+	 */
+	bool mTemporaryResponder;
+
+	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) {}
+
+	void cancel();
+
+	bool payloadContainsAll(const std::vector<std::string>& required_fields) const;
+
+public:
+
+	// constructor from a saved notification
+	LLNotification(const LLSD& sd);
+
+	void setResponseFunctor(std::string const &responseFunctorName);
+
+	typedef enum e_response_template_type
+	{
+		WITHOUT_DEFAULT_BUTTON,
+		WITH_DEFAULT_BUTTON
+	} EResponseTemplateType;
+
+	// return response LLSD filled in with default form contents and (optionally) the default button selected
+	LLSD getResponseTemplate(EResponseTemplateType type = WITHOUT_DEFAULT_BUTTON);
+
+	// returns index of first button with value==TRUE
+	// usually this the button the user clicked on
+	// returns -1 if no button clicked (e.g. form has not been displayed)
+	static S32 getSelectedOption(const LLSD& notification, const LLSD& response);
+	// returns name of first button with value==TRUE
+	static std::string getSelectedOptionName(const LLSD& notification);
+
+	// after someone responds to a notification (usually by clicking a button,
+	// but sometimes by filling out a little form and THEN clicking a button),
+    // the result of the response (the name and value of the button clicked,
+	// plus any other data) should be packaged up as LLSD, then passed as a
+	// parameter to the notification's respond() method here. This will look up
+	// and call the appropriate responder.
+	//
+	// response is notification serialized as LLSD:
+	// ["name"] = notification name
+	// ["form"] = LLSD tree that includes form description and any prefilled form data
+	// ["response"] = form data filled in by user
+	// (including, but not limited to which button they clicked on)
+	// ["payload"] = transaction specific data, such as ["source_id"] (originator of notification),  
+	//				["item_id"] (attached inventory item), etc.
+	// ["substitutions"] = string substitutions used to generate notification message
+    // from the template
+	// ["time"] = time at which notification was generated;
+	// ["expiry"] = time at which notification expires;
+	// ["responseFunctor"] = name of registered functor that handles responses to notification;
+	LLSD asLLSD();
+
+	void respond(const LLSD& sd);
+
+	void setIgnored(bool ignore);
+
+	bool isCancelled() const
+	{
+		return mCancelled;
+	}
+
+	bool isRespondedTo() const
+	{
+		return mRespondedTo;
+	}
+
+	bool isIgnored() const
+	{
+		return mIgnored;
+	}
+
+	const std::string& getName() const
+	{
+		return mTemplatep->mName;
+	}
+	
+	const LLUUID& id() const
+	{
+		return mId;
+	}
+	
+	const LLSD& getPayload() const
+	{
+		return mPayload;
+	}
+
+	const LLSD& getSubstitutions() const
+	{
+		return mSubstitutions;
+	}
+
+	const LLDate& getDate() const
+	{
+		return mTimestamp;
+	}
+
+	std::string getType() const
+	{
+		return (mTemplatep ? mTemplatep->mType : "");
+	}
+
+	std::string getMessage() const;
+	std::string getLabel() const;
+
+	std::string getURL() const;
+//	{
+//		return (mTemplatep ? mTemplatep->mURL : "");
+//	}
+
+	S32 getURLOption() const
+	{
+		return (mTemplatep ? mTemplatep->mURLOption : -1);
+	}
+    
+	S32 getURLOpenExternally() const
+	{
+		return(mTemplatep? mTemplatep->mURLOpenExternally : -1);
+	}
+	
+	const LLNotificationFormPtr getForm();
+
+	const LLDate getExpiration() const
+	{
+		return mExpiresAt;
+	}
+
+	ENotificationPriority getPriority() const
+	{
+		return mPriority;
+	}
+
+	const LLUUID getID() const
+	{
+		return mId;
+	}
+	
+	// comparing two notifications normally means comparing them by UUID (so we can look them
+	// up quickly this way)
+	bool operator<(const LLNotification& rhs) const
+	{
+		return mId < rhs.mId;
+	}
+
+	bool operator==(const LLNotification& rhs) const
+	{
+		return mId == rhs.mId;
+	}
+
+	bool operator!=(const LLNotification& rhs) const
+	{
+		return !operator==(rhs);
+	}
+
+	bool isSameObjectAs(const LLNotification* rhs) const
+	{
+		return this == rhs;
+	}
+	
+	// this object has been updated, so tell all our clients
+	void update();
+
+	void updateFrom(LLNotificationPtr other);
+	
+	// A fuzzy equals comparator.
+	// true only if both notifications have the same template and 
+	//     1) flagged as unique (there can be only one of these) OR 
+	//     2) all required payload fields of each also exist in the other.
+	bool isEquivalentTo(LLNotificationPtr that) const;
+	
+	// if the current time is greater than the expiration, the notification is expired
+	bool isExpired() const
+	{
+		if (mExpiresAt.secondsSinceEpoch() == 0)
+		{
+			return false;
+		}
+		
+		LLDate rightnow = LLDate::now();
+		return rightnow > mExpiresAt;
+	}
+	
+	std::string summarize() const;
+
+	bool hasUniquenessConstraints() const { return (mTemplatep ? mTemplatep->mUnique : false);}
+
+	virtual ~LLNotification() {}
+};
+
+std::ostream& operator<<(std::ostream& s, const LLNotification& notification);
+
+namespace LLNotificationFilters
+{
+	// a sample filter
+	bool includeEverything(LLNotificationPtr p);
+
+	typedef enum e_comparison 
+	{ 
+		EQUAL, 
+		LESS, 
+		GREATER, 
+		LESS_EQUAL, 
+		GREATER_EQUAL 
+	} EComparison;
+
+	// generic filter functor that takes method or member variable reference
+	template<typename T>
+	struct filterBy
+	{
+		typedef boost::function<T (LLNotificationPtr)>	field_t;
+		typedef typename boost::remove_reference<T>::type		value_t;
+		
+		filterBy(field_t field, value_t value, EComparison comparison = EQUAL) 
+			:	mField(field), 
+				mFilterValue(value),
+				mComparison(comparison)
+		{
+		}		
+		
+		bool operator()(LLNotificationPtr p)
+		{
+			switch(mComparison)
+			{
+			case EQUAL:
+				return mField(p) == mFilterValue;
+			case LESS:
+				return mField(p) < mFilterValue;
+			case GREATER:
+				return mField(p) > mFilterValue;
+			case LESS_EQUAL:
+				return mField(p) <= mFilterValue;
+			case GREATER_EQUAL:
+				return mField(p) >= mFilterValue;
+			default:
+				return false;
+			}
+		}
+
+		field_t mField;
+		value_t	mFilterValue;
+		EComparison mComparison;
+	};
+};
+
+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
+	{
+		typedef boost::function<T (LLNotificationPtr)> field_t;
+		orderBy(field_t field, EDirection = ORDER_INCREASING) : mField(field) {}
+		bool operator()(LLNotificationPtr lhs, LLNotificationPtr rhs)
+		{
+			if (mDirection == ORDER_DECREASING)
+			{
+				return mField(lhs) > mField(rhs);
+			}
+			else
+			{
+				return mField(lhs) < mField(rhs);
+			}
+		}
+
+		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::multimap<std::string, LLNotificationPtr> LLNotificationMap;
+
+// ========================================================
+// Abstract base class (interface) for a channel; also used for the master container.
+// This lets us arrange channels into a call hierarchy.
+
+// We maintain a heirarchy of notification channels; events are always started at the top
+// and propagated through the hierarchy only if they pass a filter.
+// Any channel can be created with a parent. A null parent (empty string) means it's
+// tied to the root of the tree (the LLNotifications class itself).
+// The default hierarchy looks like this:
+//
+// LLNotifications --+-- Expiration --+-- Mute --+-- Ignore --+-- Visible --+-- History
+//                                                                          +-- Alerts
+//                                                                          +-- Notifications
+//
+// In general, new channels that want to only see notifications that pass through 
+// all of the built-in tests should attach to the "Visible" channel
+//
+class LLNotificationChannelBase :
+	public LLEventTrackable
+{
+	LOG_CLASS(LLNotificationChannelBase);
+public:
+	LLNotificationChannelBase(LLNotificationFilter filter, LLNotificationComparator comp) : 
+		mFilter(filter), mItems(comp) 
+	{}
+	virtual ~LLNotificationChannelBase() {}
+	// you can also connect to a Channel, so you can be notified of
+	// changes to this channel
+	template <typename LISTENER>
+    LLBoundListener connectChanged(const LISTENER& slot)
+    {
+        // Examine slot to see if it binds an LLEventTrackable subclass, or a
+        // boost::shared_ptr to something, or a boost::weak_ptr to something.
+        // Call this->connectChangedImpl() to actually connect it.
+        return LLEventDetail::visit_and_connect(slot,
+                                  boost::bind(&LLNotificationChannelBase::connectChangedImpl,
+                                              this,
+                                              _1));
+    }
+    template <typename LISTENER>
+	LLBoundListener connectPassedFilter(const LISTENER& slot)
+    {
+        // see comments in connectChanged()
+        return LLEventDetail::visit_and_connect(slot,
+                                  boost::bind(&LLNotificationChannelBase::connectPassedFilterImpl,
+                                              this,
+                                              _1));
+    }
+    template <typename LISTENER>
+	LLBoundListener connectFailedFilter(const LISTENER& slot)
+    {
+        // see comments in connectChanged()
+        return LLEventDetail::visit_and_connect(slot,
+                                  boost::bind(&LLNotificationChannelBase::connectFailedFilterImpl,
+                                              this,
+                                              _1));
+    }
+
+	// use this when items change or to add a new one
+	bool updateItem(const LLSD& payload);
+	const LLNotificationFilter& getFilter() { return mFilter; }
+
+protected:
+    LLBoundListener connectChangedImpl(const LLEventListener& slot);
+    LLBoundListener connectPassedFilterImpl(const LLEventListener& slot);
+    LLBoundListener connectFailedFilterImpl(const LLEventListener& slot);
+
+	LLNotificationSet mItems;
+	LLStandardSignal mChanged;
+	LLStandardSignal mPassedFilter;
+	LLStandardSignal mFailedFilter;
+	
+	// these are action methods that subclasses can override to take action 
+	// on specific types of changes; the management of the mItems list is
+	// still handled by the generic handler.
+	virtual void onLoad(LLNotificationPtr p) {}
+	virtual void onAdd(LLNotificationPtr p) {}
+	virtual void onDelete(LLNotificationPtr p) {}
+	virtual void onChange(LLNotificationPtr p) {}
+
+	bool updateItem(const LLSD& payload, LLNotificationPtr pNotification);
+	LLNotificationFilter mFilter;
+};
+
+// The type of the pointers that we're going to manage in the NotificationQueue system
+// Because LLNotifications is a singleton, we don't actually expect to ever 
+// destroy it, but if it becomes necessary to do so, the shared_ptr model
+// will ensure that we don't leak resources.
+class LLNotificationChannel;
+typedef boost::shared_ptr<LLNotificationChannel> LLNotificationChannelPtr;
+
+// manages a list of notifications
+// Note that if this is ever copied around, we might find ourselves with multiple copies
+// of a queue with notifications being added to different nonequivalent copies. So we 
+// make it inherit from boost::noncopyable, and then create a map of shared_ptr to manage it.
+// 
+// NOTE: LLNotificationChannel is self-registering. The *correct* way to create one is to 
+// do something like:
+//		LLNotificationChannel::buildChannel("name", "parent"...);
+// This returns an LLNotificationChannelPtr, which you can store, or
+// you can then retrieve the channel by using the registry:
+//		LLNotifications::instance().getChannel("name")...
+//
+class LLNotificationChannel : 
+	boost::noncopyable, 
+	public LLNotificationChannelBase
+{
+	LOG_CLASS(LLNotificationChannel);
+
+public:  
+	virtual ~LLNotificationChannel() {}
+	typedef LLNotificationSet::iterator Iterator;
+    
+	std::string getName() const { return mName; }
+	std::string getParentChannelName() { return mParent; }
+    
+    bool isEmpty() const;
+    
+    Iterator begin();
+    Iterator end();
+
+    // Channels have a comparator to control sort order;
+	// the default sorts by arrival date
+    void setComparator(LLNotificationComparator comparator);
+	
+	std::string summarize();
+
+	// factory method for constructing these channels; since they're self-registering,
+	// we want to make sure that you can't use new to make them
+	static LLNotificationChannelPtr buildChannel(const std::string& name, const std::string& parent,
+						LLNotificationFilter filter=LLNotificationFilters::includeEverything, 
+						LLNotificationComparator comparator=LLNotificationComparators::orderByUUID());
+	
+protected:
+    // Notification Channels have a filter, which determines which notifications
+	// will be added to this channel. 
+	// Channel filters cannot change.
+	// Channels have a protected constructor so you can't make smart pointers that don't 
+	// come from our internal reference; call NotificationChannel::build(args)
+	LLNotificationChannel(const std::string& name, const std::string& parent,
+						  LLNotificationFilter filter, LLNotificationComparator comparator);
+
+private:
+	std::string mName;
+	std::string mParent;
+	LLNotificationComparator mComparator;
+};
+
+
+class LLNotifications : 
+	public LLSingleton<LLNotifications>, 
+	public LLNotificationChannelBase
+{
+	LOG_CLASS(LLNotifications);
+
+	friend class LLSingleton<LLNotifications>;
+public:
+	// load notification descriptions from file; 
+	// OK to call more than once because it will reload
+	bool loadTemplates();  
+	LLXMLNodePtr checkForXMLTemplate(LLXMLNodePtr item);
+	
+	// Add a simple notification (from XUI)
+	void addFromCallback(const LLSD& name);
+	
+	// we provide a collection of simple add notification functions so that it's reasonable to create notifications in one line
+	LLNotificationPtr add(const std::string& name, 
+						const LLSD& substitutions = LLSD(), 
+						const LLSD& payload = LLSD());
+	LLNotificationPtr add(const std::string& name, 
+						const LLSD& substitutions, 
+						const LLSD& payload, 
+						const std::string& functor_name);
+	LLNotificationPtr add(const std::string& name, 
+						const LLSD& substitutions, 
+						const LLSD& payload, 
+						LLNotificationFunctorRegistry::ResponseFunctor functor);
+	LLNotificationPtr add(const LLNotification::Params& p);
+
+	void add(const LLNotificationPtr pNotif);
+	void cancel(LLNotificationPtr pNotif);
+	void update(const LLNotificationPtr pNotif);
+
+	LLNotificationPtr find(LLUUID uuid);
+	
+	typedef boost::function<void (LLNotificationPtr)> NotificationProcess;
+	
+	void forEachNotification(NotificationProcess process);
+
+	// This is all stuff for managing the templates
+	// take your template out
+	LLNotificationTemplatePtr getTemplate(const std::string& name);
+	
+	// get the whole collection
+	typedef std::vector<std::string> TemplateNames;
+	TemplateNames getTemplateNames() const;  // returns a list of notification names
+	
+	typedef std::map<std::string, LLNotificationTemplatePtr> TemplateMap;
+
+	TemplateMap::const_iterator templatesBegin() { return mTemplates.begin(); }
+	TemplateMap::const_iterator templatesEnd() { return mTemplates.end(); }
+
+	// test for existence
+	bool templateExists(const std::string& name);
+	// useful if you're reloading the file
+	void clearTemplates();   // erase all templates
+
+	void forceResponse(const LLNotification::Params& params, S32 option);
+
+	void createDefaultChannels();
+
+	typedef std::map<std::string, LLNotificationChannelPtr> ChannelMap;
+	ChannelMap mChannels;
+
+	void addChannel(LLNotificationChannelPtr pChan);
+	LLNotificationChannelPtr getChannel(const std::string& channelName);
+	
+	std::string getGlobalString(const std::string& key) const;
+
+	void setIgnoreAllNotifications(bool ignore);
+	bool getIgnoreAllNotifications();
+
+private:
+	// we're a singleton, so we don't have a public constructor
+	LLNotifications();
+	/*virtual*/ void initSingleton();
+	
+	void loadPersistentNotifications();
+
+	bool expirationFilter(LLNotificationPtr pNotification);
+	bool expirationHandler(const LLSD& payload);
+	bool uniqueFilter(LLNotificationPtr pNotification);
+	bool uniqueHandler(const LLSD& payload);
+	bool failedUniquenessTest(const LLSD& payload);
+	LLNotificationChannelPtr pHistoryChannel;
+	LLNotificationChannelPtr pExpirationChannel;
+	
+	// put your template in
+	bool addTemplate(const std::string& name, LLNotificationTemplatePtr theTemplate);
+	TemplateMap mTemplates;
+
+	std::string mFileName;
+	
+	typedef std::map<std::string, LLXMLNodePtr> XMLTemplateMap;
+	XMLTemplateMap mXmlTemplates;
+
+	LLNotificationMap mUniqueNotifications;
+	
+	typedef std::map<std::string, std::string> GlobalStringMap;
+	GlobalStringMap mGlobalStrings;
+
+	bool mIgnoreAllNotifications;
+
+    boost::scoped_ptr<LLNotificationsListener> mListener;
+};
+
+
+#endif//LL_LLNOTIFICATIONS_H
+
-- 
GitLab