PageRenderTime 92ms CodeModel.GetById 25ms app.highlight 58ms RepoModel.GetById 2ms app.codeStats 0ms

/indra/llui/llnotifications.h

https://bitbucket.org/lindenlab/viewer-beta/
C++ Header | 1031 lines | 607 code | 184 blank | 240 comment | 9 complexity | 7aacab10e33f2b9d0285b60443b04ade MD5 | raw file
   1/**
   2* @file llnotifications.h
   3* @brief Non-UI manager and support for keeping a prioritized list of notifications
   4* @author Q (with assistance from Richard and Coco)
   5*
   6* $LicenseInfo:firstyear=2008&license=viewerlgpl$
   7* Second Life Viewer Source Code
   8* Copyright (C) 2010, Linden Research, Inc.
   9* 
  10* This library is free software; you can redistribute it and/or
  11* modify it under the terms of the GNU Lesser General Public
  12* License as published by the Free Software Foundation;
  13* version 2.1 of the License only.
  14* 
  15* This library is distributed in the hope that it will be useful,
  16* but WITHOUT ANY WARRANTY; without even the implied warranty of
  17* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  18* Lesser General Public License for more details.
  19* 
  20* You should have received a copy of the GNU Lesser General Public
  21* License along with this library; if not, write to the Free Software
  22* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  23* 
  24* Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  25* $/LicenseInfo$
  26*/
  27
  28#ifndef LL_LLNOTIFICATIONS_H
  29#define LL_LLNOTIFICATIONS_H
  30
  31/**
  32 * This system is intended to provide a singleton mechanism for adding
  33 * notifications to one of an arbitrary set of event channels.
  34 * 
  35 * Controlling JIRA: DEV-9061
  36 *
  37 * Every notification has (see code for full list):
  38 *  - a textual name, which is used to look up its template in the XML files
  39 *  - a payload, which is a block of LLSD
  40 *  - a channel, which is normally extracted from the XML files but
  41 *	  can be overridden.
  42 *  - a timestamp, used to order the notifications
  43 *  - expiration time -- if nonzero, specifies a time after which the
  44 *    notification will no longer be valid.
  45 *  - a callback name and a couple of status bits related to callbacks (see below)
  46 * 
  47 * There is a management class called LLNotifications, which is an LLSingleton.
  48 * The class maintains a collection of all of the notifications received
  49 * or processed during this session, and also manages the persistence
  50 * of those notifications that must be persisted.
  51 * 
  52 * We also have Channels. A channel is a view on a collection of notifications;
  53 * The collection is defined by a filter function that controls which
  54 * notifications are in the channel, and its ordering is controlled by 
  55 * a comparator. 
  56 *
  57 * There is a hierarchy of channels; notifications flow down from
  58 * the management class (LLNotifications, which itself inherits from
  59 * The channel base class) to the individual channels.
  60 * Any change to notifications (add, delete, modify) is 
  61 * automatically propagated through the channel hierarchy.
  62 * 
  63 * We provide methods for adding a new notification, for removing
  64 * one, and for managing channels. Channels are relatively cheap to construct
  65 * and maintain, so in general, human interfaces should use channels to
  66 * select and manage their lists of notifications.
  67 * 
  68 * We also maintain a collection of templates that are loaded from the 
  69 * XML file of template translations. The system supports substitution
  70 * of named variables from the payload into the XML file.
  71 * 
  72 * By default, only the "unknown message" template is built into the system.
  73 * It is not an error to add a notification that's not found in the 
  74 * template system, but it is logged.
  75 *
  76 */
  77
  78#include <string>
  79#include <list>
  80#include <vector>
  81#include <map>
  82#include <set>
  83#include <iomanip>
  84#include <sstream>
  85
  86#include <boost/utility.hpp>
  87#include <boost/shared_ptr.hpp>
  88#include <boost/enable_shared_from_this.hpp>
  89#include <boost/type_traits.hpp>
  90
  91// we want to minimize external dependencies, but this one is important
  92#include "llsd.h"
  93
  94// and we need this to manage the notification callbacks
  95#include "llevents.h"
  96#include "llfunctorregistry.h"
  97#include "llpointer.h"
  98#include "llinitparam.h"
  99#include "llnotificationslistener.h"
 100#include "llnotificationptr.h"
 101
 102class LLAvatarName;
 103typedef enum e_notification_priority
 104{
 105	NOTIFICATION_PRIORITY_UNSPECIFIED,
 106	NOTIFICATION_PRIORITY_LOW,
 107	NOTIFICATION_PRIORITY_NORMAL,
 108	NOTIFICATION_PRIORITY_HIGH,
 109	NOTIFICATION_PRIORITY_CRITICAL
 110} ENotificationPriority;
 111
 112struct NotificationPriorityValues : public LLInitParam::TypeValuesHelper<ENotificationPriority, NotificationPriorityValues>
 113{
 114	static void declareValues();
 115};
 116
 117class LLNotificationResponderInterface
 118{
 119public:
 120	LLNotificationResponderInterface(){};
 121	virtual ~LLNotificationResponderInterface(){};
 122
 123	virtual void handleRespond(const LLSD& notification, const LLSD& response) = 0;
 124
 125	virtual LLSD asLLSD() = 0;
 126
 127	virtual void fromLLSD(const LLSD& params) = 0;
 128};
 129
 130typedef boost::function<void (const LLSD&, const LLSD&)> LLNotificationResponder;
 131
 132typedef boost::shared_ptr<LLNotificationResponderInterface> LLNotificationResponderPtr;
 133
 134typedef LLFunctorRegistry<LLNotificationResponder> LLNotificationFunctorRegistry;
 135typedef LLFunctorRegistration<LLNotificationResponder> LLNotificationFunctorRegistration;
 136
 137// context data that can be looked up via a notification's payload by the display logic
 138// derive from this class to implement specific contexts
 139class LLNotificationContext : public LLInstanceTracker<LLNotificationContext, LLUUID>
 140{
 141public:
 142	LLNotificationContext() : LLInstanceTracker<LLNotificationContext, LLUUID>(LLUUID::generateNewID())
 143	{
 144	}
 145
 146	virtual ~LLNotificationContext() {}
 147
 148	LLSD asLLSD() const
 149	{
 150		return getKey();
 151	}
 152
 153private:
 154
 155};
 156
 157// Contains notification form data, such as buttons and text fields along with
 158// manipulator functions
 159class LLNotificationForm
 160{
 161	LOG_CLASS(LLNotificationForm);
 162
 163public:
 164	struct FormElementBase : public LLInitParam::Block<FormElementBase>
 165	{
 166		Optional<std::string>	name;
 167
 168		FormElementBase();
 169	};
 170
 171	struct FormIgnore : public LLInitParam::Block<FormIgnore, FormElementBase>
 172	{
 173		Optional<std::string>	text;
 174		Optional<bool>			save_option;
 175		Optional<std::string>	control;
 176		Optional<bool>			invert_control;
 177
 178		FormIgnore();
 179	};
 180
 181	struct FormButton : public LLInitParam::Block<FormButton, FormElementBase>
 182	{
 183		Mandatory<S32>			index;
 184		Mandatory<std::string>	text;
 185		Optional<std::string>	ignore;
 186		Optional<bool>			is_default;
 187
 188		Mandatory<std::string>	type;
 189
 190		FormButton();
 191	};
 192
 193	struct FormInput : public LLInitParam::Block<FormInput, FormElementBase>
 194	{
 195		Mandatory<std::string>	type;
 196		Optional<S32>			width;
 197		Optional<S32>			max_length_chars;
 198		Optional<std::string>	text;
 199
 200		Optional<std::string>	value;
 201		FormInput();
 202	};
 203
 204	struct FormElement : public LLInitParam::ChoiceBlock<FormElement>
 205	{
 206		Alternative<FormButton> button;
 207		Alternative<FormInput>	input;
 208
 209		FormElement();
 210	};
 211
 212	struct FormElements : public LLInitParam::Block<FormElements>
 213	{
 214		Multiple<FormElement> elements;
 215		FormElements();
 216	};
 217
 218	struct Params : public LLInitParam::Block<Params>
 219	{
 220		Optional<std::string>	name;
 221		Optional<FormIgnore>	ignore;
 222		Optional<FormElements>	form_elements;
 223
 224		Params();
 225	};
 226
 227	typedef enum e_ignore_type
 228	{ 
 229		IGNORE_NO,
 230		IGNORE_WITH_DEFAULT_RESPONSE, 
 231		IGNORE_WITH_LAST_RESPONSE, 
 232		IGNORE_SHOW_AGAIN 
 233	} EIgnoreType;
 234
 235	LLNotificationForm();
 236	LLNotificationForm(const LLSD& sd);
 237	LLNotificationForm(const std::string& name, const Params& p);
 238
 239	LLSD asLLSD() const;
 240
 241	S32 getNumElements() { return mFormData.size(); }
 242	LLSD getElement(S32 index) { return mFormData.get(index); }
 243	LLSD getElement(const std::string& element_name);
 244	bool hasElement(const std::string& element_name);
 245	void addElement(const std::string& type, const std::string& name, const LLSD& value = LLSD());
 246	void formatElements(const LLSD& substitutions);
 247	// appends form elements from another form serialized as LLSD
 248	void append(const LLSD& sub_form);
 249	std::string getDefaultOption();
 250	LLPointer<class LLControlVariable> getIgnoreSetting();
 251	bool getIgnored();
 252	void setIgnored(bool ignored);
 253
 254	EIgnoreType getIgnoreType() { return mIgnore; }
 255	std::string getIgnoreMessage() { return mIgnoreMsg; }
 256
 257private:
 258	LLSD								mFormData;
 259	EIgnoreType							mIgnore;
 260	std::string							mIgnoreMsg;
 261	LLPointer<class LLControlVariable>	mIgnoreSetting;
 262	bool								mInvertSetting;
 263};
 264
 265typedef boost::shared_ptr<LLNotificationForm> LLNotificationFormPtr;
 266
 267
 268struct LLNotificationTemplate;
 269
 270// we want to keep a map of these by name, and it's best to manage them
 271// with smart pointers
 272typedef boost::shared_ptr<LLNotificationTemplate> LLNotificationTemplatePtr;
 273
 274
 275struct LLNotificationVisibilityRule;
 276
 277typedef boost::shared_ptr<LLNotificationVisibilityRule> LLNotificationVisibilityRulePtr;
 278
 279/**
 280 * @class LLNotification
 281 * @brief The object that expresses the details of a notification
 282 * 
 283 * We make this noncopyable because
 284 * we want to manage these through LLNotificationPtr, and only
 285 * ever create one instance of any given notification.
 286 * 
 287 * The enable_shared_from_this flag ensures that if we construct
 288 * a smart pointer from a notification, we'll always get the same
 289 * shared pointer.
 290 */
 291class LLNotification  : 
 292	boost::noncopyable,
 293	public boost::enable_shared_from_this<LLNotification>
 294{
 295LOG_CLASS(LLNotification);
 296friend class LLNotifications;
 297
 298public:
 299	// parameter object used to instantiate a new notification
 300	struct Params : public LLInitParam::Block<Params>
 301	{
 302		friend class LLNotification;
 303	
 304		Mandatory<std::string>					name;
 305
 306		// optional
 307		Optional<LLSD>							substitutions;
 308		Optional<LLSD>							payload;
 309		Optional<ENotificationPriority, NotificationPriorityValues>	priority;
 310		Optional<LLSD>							form_elements;
 311		Optional<LLDate>						time_stamp;
 312		Optional<LLNotificationContext*>		context;
 313		Optional<void*>							responder;
 314
 315		struct Functor : public LLInitParam::ChoiceBlock<Functor>
 316		{
 317			Alternative<std::string>										name;
 318			Alternative<LLNotificationFunctorRegistry::ResponseFunctor>	function;
 319			Alternative<LLNotificationResponderPtr>						responder;
 320
 321			Functor()
 322			:	name("functor_name"),
 323				function("functor"),
 324				responder("responder")
 325			{}
 326		};
 327		Optional<Functor>						functor;
 328
 329		Params()
 330		:	name("name"),
 331			priority("priority", NOTIFICATION_PRIORITY_UNSPECIFIED),
 332			time_stamp("time_stamp"),
 333			payload("payload"),
 334			form_elements("form_elements")
 335		{
 336			time_stamp = LLDate::now();
 337			responder = NULL;
 338		}
 339
 340		Params(const std::string& _name) 
 341		:	name("name"),
 342			priority("priority", NOTIFICATION_PRIORITY_UNSPECIFIED),
 343			time_stamp("time_stamp"),
 344			payload("payload"),
 345			form_elements("form_elements")
 346		{
 347			functor.name = _name;
 348			name = _name;
 349			time_stamp = LLDate::now();
 350			responder = NULL;
 351		}
 352	};
 353
 354	LLNotificationResponderPtr getResponderPtr() { return mResponder; }
 355
 356private:
 357	
 358	LLUUID mId;
 359	LLSD mPayload;
 360	LLSD mSubstitutions;
 361	LLDate mTimestamp;
 362	LLDate mExpiresAt;
 363	bool mCancelled;
 364	bool mRespondedTo; 	// once the notification has been responded to, this becomes true
 365	LLSD mResponse;
 366	bool mIgnored;
 367	ENotificationPriority mPriority;
 368	LLNotificationFormPtr mForm;
 369	void* mResponderObj; // TODO - refactor/remove this field
 370	bool mIsReusable;
 371	LLNotificationResponderPtr mResponder;
 372
 373	// a reference to the template
 374	LLNotificationTemplatePtr mTemplatep;
 375
 376	/*
 377	 We want to be able to store and reload notifications so that they can survive
 378	 a shutdown/restart of the client. So we can't simply pass in callbacks;
 379	 we have to specify a callback mechanism that can be used by name rather than 
 380	 by some arbitrary pointer -- and then people have to initialize callbacks 
 381	 in some useful location. So we use LLNotificationFunctorRegistry to manage them.
 382	 */
 383	 std::string mResponseFunctorName;
 384	
 385	/*
 386	 In cases where we want to specify an explict, non-persisted callback, 
 387	 we store that in the callback registry under a dynamically generated
 388	 key, and store the key in the notification, so we can still look it up
 389	 using the same mechanism.
 390	 */
 391	bool mTemporaryResponder;
 392
 393	void init(const std::string& template_name, const LLSD& form_elements);
 394
 395	LLNotification(const Params& p);
 396
 397	// this is just for making it easy to look things up in a set organized by UUID -- DON'T USE IT
 398	// for anything real!
 399 LLNotification(LLUUID uuid) : mId(uuid), mCancelled(false), mRespondedTo(false), mIgnored(false), mPriority(NOTIFICATION_PRIORITY_UNSPECIFIED), mTemporaryResponder(false) {}
 400
 401	void cancel();
 402
 403public:
 404
 405	// constructor from a saved notification
 406	LLNotification(const LLSD& sd);
 407
 408	void setResponseFunctor(std::string const &responseFunctorName);
 409
 410	void setResponseFunctor(const LLNotificationFunctorRegistry::ResponseFunctor& cb);
 411
 412	void setResponseFunctor(const LLNotificationResponderPtr& responder);
 413
 414	typedef enum e_response_template_type
 415	{
 416		WITHOUT_DEFAULT_BUTTON,
 417		WITH_DEFAULT_BUTTON
 418	} EResponseTemplateType;
 419
 420	// return response LLSD filled in with default form contents and (optionally) the default button selected
 421	LLSD getResponseTemplate(EResponseTemplateType type = WITHOUT_DEFAULT_BUTTON);
 422
 423	// returns index of first button with value==TRUE
 424	// usually this the button the user clicked on
 425	// returns -1 if no button clicked (e.g. form has not been displayed)
 426	static S32 getSelectedOption(const LLSD& notification, const LLSD& response);
 427	// returns name of first button with value==TRUE
 428	static std::string getSelectedOptionName(const LLSD& notification);
 429
 430	// after someone responds to a notification (usually by clicking a button,
 431	// but sometimes by filling out a little form and THEN clicking a button),
 432    // the result of the response (the name and value of the button clicked,
 433	// plus any other data) should be packaged up as LLSD, then passed as a
 434	// parameter to the notification's respond() method here. This will look up
 435	// and call the appropriate responder.
 436	//
 437	// response is notification serialized as LLSD:
 438	// ["name"] = notification name
 439	// ["form"] = LLSD tree that includes form description and any prefilled form data
 440	// ["response"] = form data filled in by user
 441	// (including, but not limited to which button they clicked on)
 442	// ["payload"] = transaction specific data, such as ["source_id"] (originator of notification),  
 443	//				["item_id"] (attached inventory item), etc.
 444	// ["substitutions"] = string substitutions used to generate notification message
 445    // from the template
 446	// ["time"] = time at which notification was generated;
 447	// ["expiry"] = time at which notification expires;
 448	// ["responseFunctor"] = name of registered functor that handles responses to notification;
 449	LLSD asLLSD();
 450
 451	void respond(const LLSD& sd);
 452	void respondWithDefault();
 453
 454	void* getResponder() { return mResponderObj; }
 455
 456	void setResponder(void* responder) { mResponderObj = responder; }
 457
 458	void setIgnored(bool ignore);
 459
 460	bool isCancelled() const
 461	{
 462		return mCancelled;
 463	}
 464
 465	bool isRespondedTo() const
 466	{
 467		return mRespondedTo;
 468	}
 469
 470	bool isActive() const
 471	{
 472		return !isRespondedTo()
 473			&& !isCancelled()
 474			&& !isExpired();
 475	}
 476
 477	const LLSD& getResponse() { return mResponse; }
 478
 479	bool isIgnored() const
 480	{
 481		return mIgnored;
 482	}
 483
 484	const std::string& getName() const;
 485
 486	const std::string& getIcon() const;
 487
 488	bool isPersistent() const;
 489
 490	const LLUUID& id() const
 491	{
 492		return mId;
 493	}
 494	
 495	const LLSD& getPayload() const
 496	{
 497		return mPayload;
 498	}
 499
 500	const LLSD& getSubstitutions() const
 501	{
 502		return mSubstitutions;
 503	}
 504
 505	const LLDate& getDate() const
 506	{
 507		return mTimestamp;
 508	}
 509
 510	std::string getType() const;
 511	std::string getMessage() const;
 512	std::string getLabel() const;
 513	std::string getURL() const;
 514	S32 getURLOption() const;
 515    S32 getURLOpenExternally() const;
 516	
 517	const LLNotificationFormPtr getForm();
 518
 519	const LLDate getExpiration() const
 520	{
 521		return mExpiresAt;
 522	}
 523
 524	ENotificationPriority getPriority() const
 525	{
 526		return mPriority;
 527	}
 528
 529	const LLUUID getID() const
 530	{
 531		return mId;
 532	}
 533
 534	bool isReusable() { return mIsReusable; }
 535
 536	void setReusable(bool reusable) { mIsReusable = reusable; }
 537	
 538	// comparing two notifications normally means comparing them by UUID (so we can look them
 539	// up quickly this way)
 540	bool operator<(const LLNotification& rhs) const
 541	{
 542		return mId < rhs.mId;
 543	}
 544
 545	bool operator==(const LLNotification& rhs) const
 546	{
 547		return mId == rhs.mId;
 548	}
 549
 550	bool operator!=(const LLNotification& rhs) const
 551	{
 552		return !operator==(rhs);
 553	}
 554
 555	bool isSameObjectAs(const LLNotification* rhs) const
 556	{
 557		return this == rhs;
 558	}
 559	
 560	// this object has been updated, so tell all our clients
 561	void update();
 562
 563	void updateFrom(LLNotificationPtr other);
 564	
 565	// A fuzzy equals comparator.
 566	// true only if both notifications have the same template and 
 567	//     1) flagged as unique (there can be only one of these) OR 
 568	//     2) all required payload fields of each also exist in the other.
 569	bool isEquivalentTo(LLNotificationPtr that) const;
 570	
 571	// if the current time is greater than the expiration, the notification is expired
 572	bool isExpired() const
 573	{
 574		if (mExpiresAt.secondsSinceEpoch() == 0)
 575		{
 576			return false;
 577		}
 578		
 579		LLDate rightnow = LLDate::now();
 580		return rightnow > mExpiresAt;
 581	}
 582	
 583	std::string summarize() const;
 584
 585	bool hasUniquenessConstraints() const;
 586
 587	bool matchesTag(const std::string& tag);
 588
 589	virtual ~LLNotification() {}
 590};
 591
 592std::ostream& operator<<(std::ostream& s, const LLNotification& notification);
 593
 594namespace LLNotificationFilters
 595{
 596	// a sample filter
 597	bool includeEverything(LLNotificationPtr p);
 598
 599	typedef enum e_comparison 
 600	{ 
 601		EQUAL, 
 602		LESS, 
 603		GREATER, 
 604		LESS_EQUAL, 
 605		GREATER_EQUAL 
 606	} EComparison;
 607
 608	// generic filter functor that takes method or member variable reference
 609	template<typename T>
 610	struct filterBy
 611	{
 612		typedef boost::function<T (LLNotificationPtr)>	field_t;
 613		typedef typename boost::remove_reference<T>::type		value_t;
 614		
 615		filterBy(field_t field, value_t value, EComparison comparison = EQUAL) 
 616			:	mField(field), 
 617				mFilterValue(value),
 618				mComparison(comparison)
 619		{
 620		}		
 621		
 622		bool operator()(LLNotificationPtr p)
 623		{
 624			switch(mComparison)
 625			{
 626			case EQUAL:
 627				return mField(p) == mFilterValue;
 628			case LESS:
 629				return mField(p) < mFilterValue;
 630			case GREATER:
 631				return mField(p) > mFilterValue;
 632			case LESS_EQUAL:
 633				return mField(p) <= mFilterValue;
 634			case GREATER_EQUAL:
 635				return mField(p) >= mFilterValue;
 636			default:
 637				return false;
 638			}
 639		}
 640
 641		field_t mField;
 642		value_t	mFilterValue;
 643		EComparison mComparison;
 644	};
 645};
 646
 647namespace LLNotificationComparators
 648{
 649	typedef enum e_direction { ORDER_DECREASING, ORDER_INCREASING } EDirection;
 650
 651	// generic order functor that takes method or member variable reference
 652	template<typename T>
 653	struct orderBy
 654	{
 655		typedef boost::function<T (LLNotificationPtr)> field_t;
 656        	orderBy(field_t field, EDirection direction = ORDER_INCREASING) : mField(field), mDirection(direction) {}
 657		bool operator()(LLNotificationPtr lhs, LLNotificationPtr rhs)
 658		{
 659			if (mDirection == ORDER_DECREASING)
 660			{
 661				return mField(lhs) > mField(rhs);
 662			}
 663			else
 664			{
 665				return mField(lhs) < mField(rhs);
 666			}
 667		}
 668
 669		field_t mField;
 670		EDirection mDirection;
 671	};
 672
 673	struct orderByUUID : public orderBy<const LLUUID&>
 674	{
 675		orderByUUID(EDirection direction = ORDER_INCREASING) : orderBy<const LLUUID&>(&LLNotification::id, direction) {}
 676	};
 677
 678	struct orderByDate : public orderBy<const LLDate&>
 679	{
 680		orderByDate(EDirection direction = ORDER_INCREASING) : orderBy<const LLDate&>(&LLNotification::getDate, direction) {}
 681	};
 682};
 683
 684typedef boost::function<bool (LLNotificationPtr)> LLNotificationFilter;
 685typedef boost::function<bool (LLNotificationPtr, LLNotificationPtr)> LLNotificationComparator;
 686typedef std::set<LLNotificationPtr, LLNotificationComparator> LLNotificationSet;
 687typedef std::multimap<std::string, LLNotificationPtr> LLNotificationMap;
 688
 689// ========================================================
 690// Abstract base class (interface) for a channel; also used for the master container.
 691// This lets us arrange channels into a call hierarchy.
 692
 693// We maintain a heirarchy of notification channels; events are always started at the top
 694// and propagated through the hierarchy only if they pass a filter.
 695// Any channel can be created with a parent. A null parent (empty string) means it's
 696// tied to the root of the tree (the LLNotifications class itself).
 697// The default hierarchy looks like this:
 698//
 699// LLNotifications --+-- Expiration --+-- Mute --+-- Ignore --+-- Visible --+-- History
 700//                                                                          +-- Alerts
 701//                                                                          +-- Notifications
 702//
 703// In general, new channels that want to only see notifications that pass through 
 704// all of the built-in tests should attach to the "Visible" channel
 705//
 706class LLNotificationChannelBase :
 707	public LLEventTrackable
 708{
 709	LOG_CLASS(LLNotificationChannelBase);
 710public:
 711	LLNotificationChannelBase(LLNotificationFilter filter, LLNotificationComparator comp) : 
 712		mFilter(filter), mItems(comp) 
 713	{}
 714	virtual ~LLNotificationChannelBase() {}
 715	// you can also connect to a Channel, so you can be notified of
 716	// changes to this channel
 717	template <typename LISTENER>
 718    LLBoundListener connectChanged(const LISTENER& slot)
 719    {
 720        // Examine slot to see if it binds an LLEventTrackable subclass, or a
 721        // boost::shared_ptr to something, or a boost::weak_ptr to something.
 722        // Call this->connectChangedImpl() to actually connect it.
 723        return LLEventDetail::visit_and_connect(slot,
 724                                  boost::bind(&LLNotificationChannelBase::connectChangedImpl,
 725                                              this,
 726                                              _1));
 727    }
 728	template <typename LISTENER>
 729    LLBoundListener connectAtFrontChanged(const LISTENER& slot)
 730    {
 731        return LLEventDetail::visit_and_connect(slot,
 732                                  boost::bind(&LLNotificationChannelBase::connectAtFrontChangedImpl,
 733                                              this,
 734                                              _1));
 735    }
 736    template <typename LISTENER>
 737	LLBoundListener connectPassedFilter(const LISTENER& slot)
 738    {
 739        // see comments in connectChanged()
 740        return LLEventDetail::visit_and_connect(slot,
 741                                  boost::bind(&LLNotificationChannelBase::connectPassedFilterImpl,
 742                                              this,
 743                                              _1));
 744    }
 745    template <typename LISTENER>
 746	LLBoundListener connectFailedFilter(const LISTENER& slot)
 747    {
 748        // see comments in connectChanged()
 749        return LLEventDetail::visit_and_connect(slot,
 750                                  boost::bind(&LLNotificationChannelBase::connectFailedFilterImpl,
 751                                              this,
 752                                              _1));
 753    }
 754
 755	// use this when items change or to add a new one
 756	bool updateItem(const LLSD& payload);
 757	const LLNotificationFilter& getFilter() { return mFilter; }
 758
 759protected:
 760    LLBoundListener connectChangedImpl(const LLEventListener& slot);
 761    LLBoundListener connectAtFrontChangedImpl(const LLEventListener& slot);
 762    LLBoundListener connectPassedFilterImpl(const LLEventListener& slot);
 763    LLBoundListener connectFailedFilterImpl(const LLEventListener& slot);
 764
 765	LLNotificationSet mItems;
 766	LLStandardSignal mChanged;
 767	LLStandardSignal mPassedFilter;
 768	LLStandardSignal mFailedFilter;
 769	
 770	// these are action methods that subclasses can override to take action 
 771	// on specific types of changes; the management of the mItems list is
 772	// still handled by the generic handler.
 773	virtual void onLoad(LLNotificationPtr p) {}
 774	virtual void onAdd(LLNotificationPtr p) {}
 775	virtual void onDelete(LLNotificationPtr p) {}
 776	virtual void onChange(LLNotificationPtr p) {}
 777
 778	bool updateItem(const LLSD& payload, LLNotificationPtr pNotification);
 779	LLNotificationFilter mFilter;
 780};
 781
 782// The type of the pointers that we're going to manage in the NotificationQueue system
 783// Because LLNotifications is a singleton, we don't actually expect to ever 
 784// destroy it, but if it becomes necessary to do so, the shared_ptr model
 785// will ensure that we don't leak resources.
 786class LLNotificationChannel;
 787typedef boost::shared_ptr<LLNotificationChannel> LLNotificationChannelPtr;
 788
 789// manages a list of notifications
 790// Note that if this is ever copied around, we might find ourselves with multiple copies
 791// of a queue with notifications being added to different nonequivalent copies. So we 
 792// make it inherit from boost::noncopyable, and then create a map of shared_ptr to manage it.
 793// 
 794// NOTE: LLNotificationChannel is self-registering. The *correct* way to create one is to 
 795// do something like:
 796//		LLNotificationChannel::buildChannel("name", "parent"...);
 797// This returns an LLNotificationChannelPtr, which you can store, or
 798// you can then retrieve the channel by using the registry:
 799//		LLNotifications::instance().getChannel("name")...
 800//
 801class LLNotificationChannel : 
 802	boost::noncopyable, 
 803	public LLNotificationChannelBase
 804{
 805	LOG_CLASS(LLNotificationChannel);
 806
 807public:  
 808	virtual ~LLNotificationChannel() {}
 809	typedef LLNotificationSet::iterator Iterator;
 810    
 811	std::string getName() const { return mName; }
 812	std::string getParentChannelName() { return mParent; }
 813    
 814    bool isEmpty() const;
 815    
 816    Iterator begin();
 817    Iterator end();
 818
 819    // Channels have a comparator to control sort order;
 820	// the default sorts by arrival date
 821    void setComparator(LLNotificationComparator comparator);
 822	
 823	std::string summarize();
 824
 825	// factory method for constructing these channels; since they're self-registering,
 826	// we want to make sure that you can't use new to make them
 827	static LLNotificationChannelPtr buildChannel(const std::string& name, const std::string& parent,
 828						LLNotificationFilter filter=LLNotificationFilters::includeEverything, 
 829						LLNotificationComparator comparator=LLNotificationComparators::orderByUUID());
 830	
 831protected:
 832    // Notification Channels have a filter, which determines which notifications
 833	// will be added to this channel. 
 834	// Channel filters cannot change.
 835	// Channels have a protected constructor so you can't make smart pointers that don't 
 836	// come from our internal reference; call NotificationChannel::build(args)
 837	LLNotificationChannel(const std::string& name, const std::string& parent,
 838						  LLNotificationFilter filter, LLNotificationComparator comparator);
 839
 840private:
 841	std::string mName;
 842	std::string mParent;
 843	LLNotificationComparator mComparator;
 844};
 845
 846// An interface class to provide a clean linker seam to the LLNotifications class.
 847// Extend this interface as needed for your use of LLNotifications.
 848class LLNotificationsInterface
 849{
 850public:
 851	virtual LLNotificationPtr add(const std::string& name, 
 852						const LLSD& substitutions, 
 853						const LLSD& payload, 
 854						LLNotificationFunctorRegistry::ResponseFunctor functor) = 0;
 855};
 856
 857class LLNotifications : 
 858	public LLNotificationsInterface,
 859	public LLSingleton<LLNotifications>, 
 860	public LLNotificationChannelBase
 861{
 862	LOG_CLASS(LLNotifications);
 863
 864	friend class LLSingleton<LLNotifications>;
 865public:
 866	// load all notification descriptions from file
 867	// calling more than once will overwrite existing templates
 868	// but never delete a template
 869	bool loadTemplates();
 870
 871	// load visibility rules from file; 
 872	// OK to call more than once because it will reload
 873	bool loadVisibilityRules();  
 874	
 875	// Add a simple notification (from XUI)
 876	void addFromCallback(const LLSD& name);
 877	
 878	// *NOTE: To add simple notifications, #include "llnotificationsutil.h"
 879	// and use LLNotificationsUtil::add("MyNote") or add("MyNote", args)
 880	LLNotificationPtr add(const std::string& name, 
 881						const LLSD& substitutions,
 882						const LLSD& payload);
 883	LLNotificationPtr add(const std::string& name, 
 884						const LLSD& substitutions, 
 885						const LLSD& payload, 
 886						const std::string& functor_name);
 887	/* virtual */ LLNotificationPtr add(const std::string& name, 
 888						const LLSD& substitutions, 
 889						const LLSD& payload, 
 890						LLNotificationFunctorRegistry::ResponseFunctor functor);
 891	LLNotificationPtr add(const LLNotification::Params& p);
 892
 893	void add(const LLNotificationPtr pNotif);
 894	void cancel(LLNotificationPtr pNotif);
 895	void cancelByName(const std::string& name);
 896	void update(const LLNotificationPtr pNotif);
 897
 898	LLNotificationPtr find(LLUUID uuid);
 899	
 900	typedef boost::function<void (LLNotificationPtr)> NotificationProcess;
 901	
 902	void forEachNotification(NotificationProcess process);
 903
 904	// This is all stuff for managing the templates
 905	// take your template out
 906	LLNotificationTemplatePtr getTemplate(const std::string& name);
 907	
 908	// get the whole collection
 909	typedef std::vector<std::string> TemplateNames;
 910	TemplateNames getTemplateNames() const;  // returns a list of notification names
 911	
 912	typedef std::map<std::string, LLNotificationTemplatePtr> TemplateMap;
 913
 914	TemplateMap::const_iterator templatesBegin() { return mTemplates.begin(); }
 915	TemplateMap::const_iterator templatesEnd() { return mTemplates.end(); }
 916
 917	// test for existence
 918	bool templateExists(const std::string& name);
 919
 920	typedef std::list<LLNotificationVisibilityRulePtr> VisibilityRuleList;
 921	
 922	void forceResponse(const LLNotification::Params& params, S32 option);
 923
 924	void createDefaultChannels();
 925
 926	typedef std::map<std::string, LLNotificationChannelPtr> ChannelMap;
 927	ChannelMap mChannels;
 928
 929	void addChannel(LLNotificationChannelPtr pChan);
 930	LLNotificationChannelPtr getChannel(const std::string& channelName);
 931	
 932	std::string getGlobalString(const std::string& key) const;
 933
 934	void setIgnoreAllNotifications(bool ignore);
 935	bool getIgnoreAllNotifications();
 936
 937	bool isVisibleByRules(LLNotificationPtr pNotification);
 938	
 939private:
 940	// we're a singleton, so we don't have a public constructor
 941	LLNotifications();
 942	/*virtual*/ void initSingleton();
 943	
 944	void loadPersistentNotifications();
 945
 946	bool expirationFilter(LLNotificationPtr pNotification);
 947	bool expirationHandler(const LLSD& payload);
 948	bool uniqueFilter(LLNotificationPtr pNotification);
 949	bool uniqueHandler(const LLSD& payload);
 950	bool failedUniquenessTest(const LLSD& payload);
 951	LLNotificationChannelPtr pHistoryChannel;
 952	LLNotificationChannelPtr pExpirationChannel;
 953	
 954	TemplateMap mTemplates;
 955
 956	VisibilityRuleList mVisibilityRules;
 957
 958	std::string mFileName;
 959	
 960	LLNotificationMap mUniqueNotifications;
 961	
 962	typedef std::map<std::string, std::string> GlobalStringMap;
 963	GlobalStringMap mGlobalStrings;
 964
 965	bool mIgnoreAllNotifications;
 966
 967    boost::scoped_ptr<LLNotificationsListener> mListener;
 968};
 969
 970/**
 971 * Abstract class for postponed notifications.
 972 * Provides possibility to add notification after specified by id avatar or group will be
 973 * received from cache name. The object of this type automatically well be deleted
 974 * by cleanup method after respond will be received from cache name.
 975 *
 976 * To add custom postponed notification to the notification system client should:
 977 *  1 create class derived from LLPostponedNotification;
 978 *  2 call LLPostponedNotification::add method;
 979 */
 980class LLPostponedNotification
 981{
 982public:
 983	/**
 984	 * Performs hooking cache name callback which will add notification to notifications system.
 985	 * Type of added notification should be specified by template parameter T
 986	 * and non-private derived from LLPostponedNotification class,
 987	 * otherwise compilation error will occur.
 988	 */
 989	template<class T>
 990	static void add(const LLNotification::Params& params,
 991			const LLUUID& id, bool is_group)
 992	{
 993		// upcast T to the base type to restrict T derivation from LLPostponedNotification
 994		LLPostponedNotification* thiz = new T();
 995		thiz->mParams = params;
 996
 997		// Avoid header file dependency on llcachename.h
 998		lookupName(thiz, id, is_group);
 999	}
1000
1001private:
1002	static void lookupName(LLPostponedNotification* thiz, const LLUUID& id, bool is_group);
1003	// only used for groups
1004	void onGroupNameCache(const LLUUID& id, const std::string& full_name, bool is_group);
1005	// only used for avatars
1006	void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name);
1007	// used for both group and avatar names
1008	void finalizeName(const std::string& name);
1009
1010	void cleanup()
1011	{
1012		delete this;
1013	}
1014
1015protected:
1016	LLPostponedNotification() {}
1017	virtual ~LLPostponedNotification() {}
1018
1019	/**
1020	 * Abstract method provides possibility to modify notification parameters and
1021	 * will be called after cache name retrieve information about avatar or group
1022	 * and before notification will be added to the notification system.
1023	 */
1024	virtual void modifyNotificationParams() = 0;
1025
1026	LLNotification::Params mParams;
1027	std::string mName;
1028};
1029
1030#endif//LL_LLNOTIFICATIONS_H
1031