llnotifications.h
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:31k
源码类别:

游戏引擎

开发平台:

C++ Builder

  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=viewergpl$
  7. * Copyright (c) 2008-2010, Linden Research, Inc.
  8. * Second Life Viewer Source Code
  9. * The source code in this file ("Source Code") is provided by Linden Lab
  10. * to you under the terms of the GNU General Public License, version 2.0
  11. * ("GPL"), unless you have obtained a separate licensing agreement
  12. * ("Other License"), formally executed by you and Linden Lab.  Terms of
  13. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  14. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  15. * There are special exceptions to the terms and conditions of the GPL as
  16. * it is applied to this Source Code. View the full text of the exception
  17. * in the file doc/FLOSS-exception.txt in this software distribution, or
  18. * online at
  19. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  20. * By copying, modifying or distributing this software, you acknowledge
  21. * that you have read and understood your obligations described above,
  22. * and agree to abide by those obligations.
  23. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  24. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  25. * COMPLETENESS OR PERFORMANCE.
  26. * $/LicenseInfo$
  27. */
  28. #ifndef LL_LLNOTIFICATIONS_H
  29. #define LL_LLNOTIFICATIONS_H
  30. /**
  31.  * This system is intended to provide a singleton mechanism for adding
  32.  * notifications to one of an arbitrary set of event channels.
  33.  * 
  34.  * Controlling JIRA: DEV-9061
  35.  *
  36.  * Every notification has (see code for full list):
  37.  *  - a textual name, which is used to look up its template in the XML files
  38.  *  - a payload, which is a block of LLSD
  39.  *  - a channel, which is normally extracted from the XML files but
  40.  *   can be overridden.
  41.  *  - a timestamp, used to order the notifications
  42.  *  - expiration time -- if nonzero, specifies a time after which the
  43.  *    notification will no longer be valid.
  44.  *  - a callback name and a couple of status bits related to callbacks (see below)
  45.  * 
  46.  * There is a management class called LLNotifications, which is an LLSingleton.
  47.  * The class maintains a collection of all of the notifications received
  48.  * or processed during this session, and also manages the persistence
  49.  * of those notifications that must be persisted.
  50.  * 
  51.  * We also have Channels. A channel is a view on a collection of notifications;
  52.  * The collection is defined by a filter function that controls which
  53.  * notifications are in the channel, and its ordering is controlled by 
  54.  * a comparator. 
  55.  *
  56.  * There is a hierarchy of channels; notifications flow down from
  57.  * the management class (LLNotifications, which itself inherits from
  58.  * The channel base class) to the individual channels.
  59.  * Any change to notifications (add, delete, modify) is 
  60.  * automatically propagated through the channel hierarchy.
  61.  * 
  62.  * We provide methods for adding a new notification, for removing
  63.  * one, and for managing channels. Channels are relatively cheap to construct
  64.  * and maintain, so in general, human interfaces should use channels to
  65.  * select and manage their lists of notifications.
  66.  * 
  67.  * We also maintain a collection of templates that are loaded from the 
  68.  * XML file of template translations. The system supports substitution
  69.  * of named variables from the payload into the XML file.
  70.  * 
  71.  * By default, only the "unknown message" template is built into the system.
  72.  * It is not an error to add a notification that's not found in the 
  73.  * template system, but it is logged.
  74.  *
  75.  */
  76. #include <string>
  77. #include <list>
  78. #include <vector>
  79. #include <map>
  80. #include <set>
  81. #include <iomanip>
  82. #include <sstream>
  83. #include <boost/utility.hpp>
  84. #include <boost/shared_ptr.hpp>
  85. #include <boost/enable_shared_from_this.hpp>
  86. #include <boost/type_traits.hpp>
  87. // we want to minimize external dependencies, but this one is important
  88. #include "llsd.h"
  89. // and we need this to manage the notification callbacks
  90. #include "llevents.h"
  91. #include "llfunctorregistry.h"
  92. #include "llpointer.h"
  93. #include "llinitparam.h"
  94. #include "llnotificationslistener.h"
  95. #include "llnotificationptr.h"
  96. typedef enum e_notification_priority
  97. {
  98. NOTIFICATION_PRIORITY_UNSPECIFIED,
  99. NOTIFICATION_PRIORITY_LOW,
  100. NOTIFICATION_PRIORITY_NORMAL,
  101. NOTIFICATION_PRIORITY_HIGH,
  102. NOTIFICATION_PRIORITY_CRITICAL
  103. } ENotificationPriority;
  104. typedef boost::function<void (const LLSD&, const LLSD&)> LLNotificationResponder;
  105. typedef LLFunctorRegistry<LLNotificationResponder> LLNotificationFunctorRegistry;
  106. typedef LLFunctorRegistration<LLNotificationResponder> LLNotificationFunctorRegistration;
  107. // context data that can be looked up via a notification's payload by the display logic
  108. // derive from this class to implement specific contexts
  109. class LLNotificationContext : public LLInstanceTracker<LLNotificationContext, LLUUID>
  110. {
  111. public:
  112. LLNotificationContext() : LLInstanceTracker<LLNotificationContext, LLUUID>(LLUUID::generateNewID())
  113. {
  114. }
  115. virtual ~LLNotificationContext() {}
  116. LLSD asLLSD() const
  117. {
  118. return getKey();
  119. }
  120. private:
  121. };
  122. // Contains notification form data, such as buttons and text fields along with
  123. // manipulator functions
  124. class LLNotificationForm
  125. {
  126. LOG_CLASS(LLNotificationForm);
  127. public:
  128. typedef enum e_ignore_type
  129. IGNORE_NO,
  130. IGNORE_WITH_DEFAULT_RESPONSE, 
  131. IGNORE_WITH_LAST_RESPONSE, 
  132. IGNORE_SHOW_AGAIN 
  133. } EIgnoreType;
  134. LLNotificationForm();
  135. LLNotificationForm(const LLSD& sd);
  136. LLNotificationForm(const std::string& name, 
  137. const LLPointer<class LLXMLNode> xml_node);
  138. LLSD asLLSD() const;
  139. S32 getNumElements() { return mFormData.size(); }
  140. LLSD getElement(S32 index) { return mFormData.get(index); }
  141. LLSD getElement(const std::string& element_name);
  142. bool hasElement(const std::string& element_name);
  143. void addElement(const std::string& type, const std::string& name, const LLSD& value = LLSD());
  144. void formatElements(const LLSD& substitutions);
  145. // appends form elements from another form serialized as LLSD
  146. void append(const LLSD& sub_form);
  147. std::string getDefaultOption();
  148. EIgnoreType getIgnoreType() { return mIgnore; }
  149. std::string getIgnoreMessage() { return mIgnoreMsg; }
  150. private:
  151. LLSD mFormData;
  152. EIgnoreType mIgnore;
  153. std::string mIgnoreMsg;
  154. };
  155. typedef boost::shared_ptr<LLNotificationForm> LLNotificationFormPtr;
  156. // This is the class of object read from the XML file (notifications.xml, 
  157. // from the appropriate local language directory).
  158. struct LLNotificationTemplate
  159. {
  160. LLNotificationTemplate();
  161.     // the name of the notification -- the key used to identify it
  162.     // Ideally, the key should follow variable naming rules 
  163.     // (no spaces or punctuation).
  164.     std::string mName;
  165.     // The type of the notification
  166.     // used to control which queue it's stored in
  167.     std::string mType;
  168.     // The text used to display the notification. Replaceable parameters
  169.     // are enclosed in square brackets like this [].
  170.     std::string mMessage;
  171. // The label for the notification; used for 
  172. // certain classes of notification (those with a window and a window title). 
  173. // Also used when a notification pops up underneath the current one.
  174. // Replaceable parameters can be used in the label.
  175. std::string mLabel;
  176. // The name of the icon image. This should include an extension.
  177. std::string mIcon;
  178.     // This is the Highlander bit -- "There Can Be Only One"
  179.     // An outstanding notification with this bit set
  180.     // is updated by an incoming notification with the same name,
  181.     // rather than creating a new entry in the queue.
  182.     // (used for things like progress indications, or repeating warnings
  183.     // like "the grid is going down in N minutes")
  184.     bool mUnique;
  185.     // if we want to be unique only if a certain part of the payload is constant
  186.     // specify the field names for the payload. The notification will only be
  187.     // combined if all of the fields named in the context are identical in the
  188.     // new and the old notification; otherwise, the notification will be
  189.     // duplicated. This is to support suppressing duplicate offers from the same
  190.     // sender but still differentiating different offers. Example: Invitation to
  191.     // conference chat.
  192.     std::vector<std::string> mUniqueContext;
  193.     // If this notification expires automatically, this value will be 
  194.     // nonzero, and indicates the number of seconds for which the notification
  195.     // will be valid (a teleport offer, for example, might be valid for 
  196.     // 300 seconds). 
  197.     U32 mExpireSeconds;
  198.     // if the offer expires, one of the options is chosen automatically
  199.     // based on its "value" parameter. This controls which one. 
  200.     // If expireSeconds is specified, expireOption should also be specified.
  201.     U32 mExpireOption;
  202.     // if the notification contains a url, it's stored here (and replaced 
  203.     // into the message where [_URL] is found)
  204.     std::string mURL;
  205.     // if there's a URL in the message, this controls which option visits
  206.     // that URL. Obsolete this and eliminate the buttons for affected
  207.     // messages when we allow clickable URLs in the UI
  208.     U32 mURLOption;
  209. U32 mURLOpenExternally;
  210. //This is a flag that tells if the url needs to open externally dispite 
  211. //what the user setting is.
  212. // does this notification persist across sessions? if so, it will be
  213. // serialized to disk on first receipt and read on startup
  214. bool mPersist;
  215. // This is the name of the default functor, if present, to be
  216. // used for the notification's callback. It is optional, and used only if 
  217. // the notification is constructed without an identified functor.
  218. std::string mDefaultFunctor;
  219. // The form data associated with a given notification (buttons, text boxes, etc)
  220.     LLNotificationFormPtr mForm;
  221. // default priority for notifications of this type
  222. ENotificationPriority mPriority;
  223. // UUID of the audio file to be played when this notification arrives
  224. // this is loaded as a name, but looked up to get the UUID upon template load.
  225. // If null, it wasn't specified.
  226. LLUUID mSoundEffect;
  227. };
  228. // we want to keep a map of these by name, and it's best to manage them
  229. // with smart pointers
  230. typedef boost::shared_ptr<LLNotificationTemplate> LLNotificationTemplatePtr;
  231. /**
  232.  * @class LLNotification
  233.  * @brief The object that expresses the details of a notification
  234.  * 
  235.  * We make this noncopyable because
  236.  * we want to manage these through LLNotificationPtr, and only
  237.  * ever create one instance of any given notification.
  238.  * 
  239.  * The enable_shared_from_this flag ensures that if we construct
  240.  * a smart pointer from a notification, we'll always get the same
  241.  * shared pointer.
  242.  */
  243. class LLNotification  : 
  244. boost::noncopyable,
  245. public boost::enable_shared_from_this<LLNotification>
  246. {
  247. LOG_CLASS(LLNotification);
  248. friend class LLNotifications;
  249. public:
  250. // parameter object used to instantiate a new notification
  251. struct Params : public LLInitParam::Block<Params>
  252. {
  253. friend class LLNotification;
  254. Mandatory<std::string> name;
  255. // optional
  256. Optional<LLSD> substitutions;
  257. Optional<LLSD> payload;
  258. Optional<ENotificationPriority> priority;
  259. Optional<LLSD> form_elements;
  260. Optional<LLDate> time_stamp;
  261. Optional<LLNotificationContext*> context;
  262. struct Functor : public LLInitParam::Choice<Functor>
  263. {
  264. Alternative<std::string> name;
  265. Alternative<LLNotificationFunctorRegistry::ResponseFunctor> function;
  266. Functor()
  267. : name("functor_name"),
  268. function("functor")
  269. {}
  270. };
  271. Optional<Functor> functor;
  272. Params()
  273. : name("name"),
  274. priority("priority", NOTIFICATION_PRIORITY_UNSPECIFIED),
  275. time_stamp("time_stamp"),
  276. payload("payload"),
  277. form_elements("form_elements")
  278. {
  279. time_stamp = LLDate::now();
  280. }
  281. Params(const std::string& _name) 
  282. : name("name"),
  283. priority("priority", NOTIFICATION_PRIORITY_UNSPECIFIED),
  284. time_stamp("time_stamp"),
  285. payload("payload"),
  286. form_elements("form_elements")
  287. {
  288. functor.name = _name;
  289. name = _name;
  290. time_stamp = LLDate::now();
  291. }
  292. };
  293. private:
  294. LLUUID mId;
  295. LLSD mPayload;
  296. LLSD mSubstitutions;
  297. LLDate mTimestamp;
  298. LLDate mExpiresAt;
  299. bool mCancelled;
  300. bool mRespondedTo;  // once the notification has been responded to, this becomes true
  301. bool mIgnored;
  302. ENotificationPriority mPriority;
  303. LLNotificationFormPtr mForm;
  304. // a reference to the template
  305. LLNotificationTemplatePtr mTemplatep;
  306. /*
  307.  We want to be able to store and reload notifications so that they can survive
  308.  a shutdown/restart of the client. So we can't simply pass in callbacks;
  309.  we have to specify a callback mechanism that can be used by name rather than 
  310.  by some arbitrary pointer -- and then people have to initialize callbacks 
  311.  in some useful location. So we use LLNotificationFunctorRegistry to manage them.
  312.  */
  313.  std::string mResponseFunctorName;
  314. /*
  315.  In cases where we want to specify an explict, non-persisted callback, 
  316.  we store that in the callback registry under a dynamically generated
  317.  key, and store the key in the notification, so we can still look it up
  318.  using the same mechanism.
  319.  */
  320. bool mTemporaryResponder;
  321. void init(const std::string& template_name, const LLSD& form_elements);
  322. LLNotification(const Params& p);
  323. // this is just for making it easy to look things up in a set organized by UUID -- DON'T USE IT
  324. // for anything real!
  325.  LLNotification(LLUUID uuid) : mId(uuid), mCancelled(false), mRespondedTo(false), mIgnored(false), mPriority(NOTIFICATION_PRIORITY_UNSPECIFIED), mTemporaryResponder(false) {}
  326. void cancel();
  327. bool payloadContainsAll(const std::vector<std::string>& required_fields) const;
  328. public:
  329. // constructor from a saved notification
  330. LLNotification(const LLSD& sd);
  331. void setResponseFunctor(std::string const &responseFunctorName);
  332. typedef enum e_response_template_type
  333. {
  334. WITHOUT_DEFAULT_BUTTON,
  335. WITH_DEFAULT_BUTTON
  336. } EResponseTemplateType;
  337. // return response LLSD filled in with default form contents and (optionally) the default button selected
  338. LLSD getResponseTemplate(EResponseTemplateType type = WITHOUT_DEFAULT_BUTTON);
  339. // returns index of first button with value==TRUE
  340. // usually this the button the user clicked on
  341. // returns -1 if no button clicked (e.g. form has not been displayed)
  342. static S32 getSelectedOption(const LLSD& notification, const LLSD& response);
  343. // returns name of first button with value==TRUE
  344. static std::string getSelectedOptionName(const LLSD& notification);
  345. // after someone responds to a notification (usually by clicking a button,
  346. // but sometimes by filling out a little form and THEN clicking a button),
  347.     // the result of the response (the name and value of the button clicked,
  348. // plus any other data) should be packaged up as LLSD, then passed as a
  349. // parameter to the notification's respond() method here. This will look up
  350. // and call the appropriate responder.
  351. //
  352. // response is notification serialized as LLSD:
  353. // ["name"] = notification name
  354. // ["form"] = LLSD tree that includes form description and any prefilled form data
  355. // ["response"] = form data filled in by user
  356. // (including, but not limited to which button they clicked on)
  357. // ["payload"] = transaction specific data, such as ["source_id"] (originator of notification),  
  358. // ["item_id"] (attached inventory item), etc.
  359. // ["substitutions"] = string substitutions used to generate notification message
  360.     // from the template
  361. // ["time"] = time at which notification was generated;
  362. // ["expiry"] = time at which notification expires;
  363. // ["responseFunctor"] = name of registered functor that handles responses to notification;
  364. LLSD asLLSD();
  365. void respond(const LLSD& sd);
  366. void setIgnored(bool ignore);
  367. bool isCancelled() const
  368. {
  369. return mCancelled;
  370. }
  371. bool isRespondedTo() const
  372. {
  373. return mRespondedTo;
  374. }
  375. bool isIgnored() const
  376. {
  377. return mIgnored;
  378. }
  379. const std::string& getName() const
  380. {
  381. return mTemplatep->mName;
  382. }
  383. const LLUUID& id() const
  384. {
  385. return mId;
  386. }
  387. const LLSD& getPayload() const
  388. {
  389. return mPayload;
  390. }
  391. const LLSD& getSubstitutions() const
  392. {
  393. return mSubstitutions;
  394. }
  395. const LLDate& getDate() const
  396. {
  397. return mTimestamp;
  398. }
  399. std::string getType() const
  400. {
  401. return (mTemplatep ? mTemplatep->mType : "");
  402. }
  403. std::string getMessage() const;
  404. std::string getLabel() const;
  405. std::string getURL() const;
  406. // {
  407. // return (mTemplatep ? mTemplatep->mURL : "");
  408. // }
  409. S32 getURLOption() const
  410. {
  411. return (mTemplatep ? mTemplatep->mURLOption : -1);
  412. }
  413.     
  414. S32 getURLOpenExternally() const
  415. {
  416. return(mTemplatep? mTemplatep->mURLOpenExternally : -1);
  417. }
  418. const LLNotificationFormPtr getForm();
  419. const LLDate getExpiration() const
  420. {
  421. return mExpiresAt;
  422. }
  423. ENotificationPriority getPriority() const
  424. {
  425. return mPriority;
  426. }
  427. const LLUUID getID() const
  428. {
  429. return mId;
  430. }
  431. // comparing two notifications normally means comparing them by UUID (so we can look them
  432. // up quickly this way)
  433. bool operator<(const LLNotification& rhs) const
  434. {
  435. return mId < rhs.mId;
  436. }
  437. bool operator==(const LLNotification& rhs) const
  438. {
  439. return mId == rhs.mId;
  440. }
  441. bool operator!=(const LLNotification& rhs) const
  442. {
  443. return !operator==(rhs);
  444. }
  445. bool isSameObjectAs(const LLNotification* rhs) const
  446. {
  447. return this == rhs;
  448. }
  449. // this object has been updated, so tell all our clients
  450. void update();
  451. void updateFrom(LLNotificationPtr other);
  452. // A fuzzy equals comparator.
  453. // true only if both notifications have the same template and 
  454. //     1) flagged as unique (there can be only one of these) OR 
  455. //     2) all required payload fields of each also exist in the other.
  456. bool isEquivalentTo(LLNotificationPtr that) const;
  457. // if the current time is greater than the expiration, the notification is expired
  458. bool isExpired() const
  459. {
  460. if (mExpiresAt.secondsSinceEpoch() == 0)
  461. {
  462. return false;
  463. }
  464. LLDate rightnow = LLDate::now();
  465. return rightnow > mExpiresAt;
  466. }
  467. std::string summarize() const;
  468. bool hasUniquenessConstraints() const { return (mTemplatep ? mTemplatep->mUnique : false);}
  469. virtual ~LLNotification() {}
  470. };
  471. std::ostream& operator<<(std::ostream& s, const LLNotification& notification);
  472. namespace LLNotificationFilters
  473. {
  474. // a sample filter
  475. bool includeEverything(LLNotificationPtr p);
  476. typedef enum e_comparison 
  477. EQUAL, 
  478. LESS, 
  479. GREATER, 
  480. LESS_EQUAL, 
  481. GREATER_EQUAL 
  482. } EComparison;
  483. // generic filter functor that takes method or member variable reference
  484. template<typename T>
  485. struct filterBy
  486. {
  487. typedef boost::function<T (LLNotificationPtr)> field_t;
  488. typedef typename boost::remove_reference<T>::type value_t;
  489. filterBy(field_t field, value_t value, EComparison comparison = EQUAL) 
  490. : mField(field), 
  491. mFilterValue(value),
  492. mComparison(comparison)
  493. {
  494. }
  495. bool operator()(LLNotificationPtr p)
  496. {
  497. switch(mComparison)
  498. {
  499. case EQUAL:
  500. return mField(p) == mFilterValue;
  501. case LESS:
  502. return mField(p) < mFilterValue;
  503. case GREATER:
  504. return mField(p) > mFilterValue;
  505. case LESS_EQUAL:
  506. return mField(p) <= mFilterValue;
  507. case GREATER_EQUAL:
  508. return mField(p) >= mFilterValue;
  509. default:
  510. return false;
  511. }
  512. }
  513. field_t mField;
  514. value_t mFilterValue;
  515. EComparison mComparison;
  516. };
  517. };
  518. namespace LLNotificationComparators
  519. {
  520. typedef enum e_direction { ORDER_DECREASING, ORDER_INCREASING } EDirection;
  521. // generic order functor that takes method or member variable reference
  522. template<typename T>
  523. struct orderBy
  524. {
  525. typedef boost::function<T (LLNotificationPtr)> field_t;
  526.          orderBy(field_t field, EDirection direction = ORDER_INCREASING) : mField(field), mDirection(direction) {}
  527. bool operator()(LLNotificationPtr lhs, LLNotificationPtr rhs)
  528. {
  529. if (mDirection == ORDER_DECREASING)
  530. {
  531. return mField(lhs) > mField(rhs);
  532. }
  533. else
  534. {
  535. return mField(lhs) < mField(rhs);
  536. }
  537. }
  538. field_t mField;
  539. EDirection mDirection;
  540. };
  541. struct orderByUUID : public orderBy<const LLUUID&>
  542. {
  543. orderByUUID(EDirection direction = ORDER_INCREASING) : orderBy<const LLUUID&>(&LLNotification::id, direction) {}
  544. };
  545. struct orderByDate : public orderBy<const LLDate&>
  546. {
  547. orderByDate(EDirection direction = ORDER_INCREASING) : orderBy<const LLDate&>(&LLNotification::getDate, direction) {}
  548. };
  549. };
  550. typedef boost::function<bool (LLNotificationPtr)> LLNotificationFilter;
  551. typedef boost::function<bool (LLNotificationPtr, LLNotificationPtr)> LLNotificationComparator;
  552. typedef std::set<LLNotificationPtr, LLNotificationComparator> LLNotificationSet;
  553. typedef std::multimap<std::string, LLNotificationPtr> LLNotificationMap;
  554. // ========================================================
  555. // Abstract base class (interface) for a channel; also used for the master container.
  556. // This lets us arrange channels into a call hierarchy.
  557. // We maintain a heirarchy of notification channels; events are always started at the top
  558. // and propagated through the hierarchy only if they pass a filter.
  559. // Any channel can be created with a parent. A null parent (empty string) means it's
  560. // tied to the root of the tree (the LLNotifications class itself).
  561. // The default hierarchy looks like this:
  562. //
  563. // LLNotifications --+-- Expiration --+-- Mute --+-- Ignore --+-- Visible --+-- History
  564. //                                                                          +-- Alerts
  565. //                                                                          +-- Notifications
  566. //
  567. // In general, new channels that want to only see notifications that pass through 
  568. // all of the built-in tests should attach to the "Visible" channel
  569. //
  570. class LLNotificationChannelBase :
  571. public LLEventTrackable
  572. {
  573. LOG_CLASS(LLNotificationChannelBase);
  574. public:
  575. LLNotificationChannelBase(LLNotificationFilter filter, LLNotificationComparator comp) : 
  576. mFilter(filter), mItems(comp) 
  577. {}
  578. virtual ~LLNotificationChannelBase() {}
  579. // you can also connect to a Channel, so you can be notified of
  580. // changes to this channel
  581. template <typename LISTENER>
  582.     LLBoundListener connectChanged(const LISTENER& slot)
  583.     {
  584.         // Examine slot to see if it binds an LLEventTrackable subclass, or a
  585.         // boost::shared_ptr to something, or a boost::weak_ptr to something.
  586.         // Call this->connectChangedImpl() to actually connect it.
  587.         return LLEventDetail::visit_and_connect(slot,
  588.                                   boost::bind(&LLNotificationChannelBase::connectChangedImpl,
  589.                                               this,
  590.                                               _1));
  591.     }
  592. template <typename LISTENER>
  593.     LLBoundListener connectAtFrontChanged(const LISTENER& slot)
  594.     {
  595.         return LLEventDetail::visit_and_connect(slot,
  596.                                   boost::bind(&LLNotificationChannelBase::connectAtFrontChangedImpl,
  597.                                               this,
  598.                                               _1));
  599.     }
  600.     template <typename LISTENER>
  601. LLBoundListener connectPassedFilter(const LISTENER& slot)
  602.     {
  603.         // see comments in connectChanged()
  604.         return LLEventDetail::visit_and_connect(slot,
  605.                                   boost::bind(&LLNotificationChannelBase::connectPassedFilterImpl,
  606.                                               this,
  607.                                               _1));
  608.     }
  609.     template <typename LISTENER>
  610. LLBoundListener connectFailedFilter(const LISTENER& slot)
  611.     {
  612.         // see comments in connectChanged()
  613.         return LLEventDetail::visit_and_connect(slot,
  614.                                   boost::bind(&LLNotificationChannelBase::connectFailedFilterImpl,
  615.                                               this,
  616.                                               _1));
  617.     }
  618. // use this when items change or to add a new one
  619. bool updateItem(const LLSD& payload);
  620. const LLNotificationFilter& getFilter() { return mFilter; }
  621. protected:
  622.     LLBoundListener connectChangedImpl(const LLEventListener& slot);
  623.     LLBoundListener connectAtFrontChangedImpl(const LLEventListener& slot);
  624.     LLBoundListener connectPassedFilterImpl(const LLEventListener& slot);
  625.     LLBoundListener connectFailedFilterImpl(const LLEventListener& slot);
  626. LLNotificationSet mItems;
  627. LLStandardSignal mChanged;
  628. LLStandardSignal mPassedFilter;
  629. LLStandardSignal mFailedFilter;
  630. // these are action methods that subclasses can override to take action 
  631. // on specific types of changes; the management of the mItems list is
  632. // still handled by the generic handler.
  633. virtual void onLoad(LLNotificationPtr p) {}
  634. virtual void onAdd(LLNotificationPtr p) {}
  635. virtual void onDelete(LLNotificationPtr p) {}
  636. virtual void onChange(LLNotificationPtr p) {}
  637. bool updateItem(const LLSD& payload, LLNotificationPtr pNotification);
  638. LLNotificationFilter mFilter;
  639. };
  640. // The type of the pointers that we're going to manage in the NotificationQueue system
  641. // Because LLNotifications is a singleton, we don't actually expect to ever 
  642. // destroy it, but if it becomes necessary to do so, the shared_ptr model
  643. // will ensure that we don't leak resources.
  644. class LLNotificationChannel;
  645. typedef boost::shared_ptr<LLNotificationChannel> LLNotificationChannelPtr;
  646. // manages a list of notifications
  647. // Note that if this is ever copied around, we might find ourselves with multiple copies
  648. // of a queue with notifications being added to different nonequivalent copies. So we 
  649. // make it inherit from boost::noncopyable, and then create a map of shared_ptr to manage it.
  650. // 
  651. // NOTE: LLNotificationChannel is self-registering. The *correct* way to create one is to 
  652. // do something like:
  653. // LLNotificationChannel::buildChannel("name", "parent"...);
  654. // This returns an LLNotificationChannelPtr, which you can store, or
  655. // you can then retrieve the channel by using the registry:
  656. // LLNotifications::instance().getChannel("name")...
  657. //
  658. class LLNotificationChannel : 
  659. boost::noncopyable, 
  660. public LLNotificationChannelBase
  661. {
  662. LOG_CLASS(LLNotificationChannel);
  663. public:  
  664. virtual ~LLNotificationChannel() {}
  665. typedef LLNotificationSet::iterator Iterator;
  666.     
  667. std::string getName() const { return mName; }
  668. std::string getParentChannelName() { return mParent; }
  669.     
  670.     bool isEmpty() const;
  671.     
  672.     Iterator begin();
  673.     Iterator end();
  674.     // Channels have a comparator to control sort order;
  675. // the default sorts by arrival date
  676.     void setComparator(LLNotificationComparator comparator);
  677. std::string summarize();
  678. // factory method for constructing these channels; since they're self-registering,
  679. // we want to make sure that you can't use new to make them
  680. static LLNotificationChannelPtr buildChannel(const std::string& name, const std::string& parent,
  681. LLNotificationFilter filter=LLNotificationFilters::includeEverything, 
  682. LLNotificationComparator comparator=LLNotificationComparators::orderByUUID());
  683. protected:
  684.     // Notification Channels have a filter, which determines which notifications
  685. // will be added to this channel. 
  686. // Channel filters cannot change.
  687. // Channels have a protected constructor so you can't make smart pointers that don't 
  688. // come from our internal reference; call NotificationChannel::build(args)
  689. LLNotificationChannel(const std::string& name, const std::string& parent,
  690.   LLNotificationFilter filter, LLNotificationComparator comparator);
  691. private:
  692. std::string mName;
  693. std::string mParent;
  694. LLNotificationComparator mComparator;
  695. };
  696. // An interface class to provide a clean linker seam to the LLNotifications class.
  697. // Extend this interface as needed for your use of LLNotifications.
  698. class LLNotificationsInterface
  699. {
  700. public:
  701. virtual LLNotificationPtr add(const std::string& name, 
  702. const LLSD& substitutions, 
  703. const LLSD& payload, 
  704. LLNotificationFunctorRegistry::ResponseFunctor functor) = 0;
  705. };
  706. class LLNotifications : 
  707. public LLNotificationsInterface,
  708. public LLSingleton<LLNotifications>, 
  709. public LLNotificationChannelBase
  710. {
  711. LOG_CLASS(LLNotifications);
  712. friend class LLSingleton<LLNotifications>;
  713. public:
  714. // load notification descriptions from file; 
  715. // OK to call more than once because it will reload
  716. bool loadTemplates();  
  717. LLPointer<class LLXMLNode> checkForXMLTemplate(LLPointer<class LLXMLNode> item);
  718. // Add a simple notification (from XUI)
  719. void addFromCallback(const LLSD& name);
  720. // *NOTE: To add simple notifications, #include "llnotificationsutil.h"
  721. // and use LLNotificationsUtil::add("MyNote") or add("MyNote", args)
  722. LLNotificationPtr add(const std::string& name, 
  723. const LLSD& substitutions,
  724. const LLSD& payload);
  725. LLNotificationPtr add(const std::string& name, 
  726. const LLSD& substitutions, 
  727. const LLSD& payload, 
  728. const std::string& functor_name);
  729. /* virtual */ LLNotificationPtr add(const std::string& name, 
  730. const LLSD& substitutions, 
  731. const LLSD& payload, 
  732. LLNotificationFunctorRegistry::ResponseFunctor functor);
  733. LLNotificationPtr add(const LLNotification::Params& p);
  734. void add(const LLNotificationPtr pNotif);
  735. void cancel(LLNotificationPtr pNotif);
  736. void update(const LLNotificationPtr pNotif);
  737. LLNotificationPtr find(LLUUID uuid);
  738. typedef boost::function<void (LLNotificationPtr)> NotificationProcess;
  739. void forEachNotification(NotificationProcess process);
  740. // This is all stuff for managing the templates
  741. // take your template out
  742. LLNotificationTemplatePtr getTemplate(const std::string& name);
  743. // get the whole collection
  744. typedef std::vector<std::string> TemplateNames;
  745. TemplateNames getTemplateNames() const;  // returns a list of notification names
  746. typedef std::map<std::string, LLNotificationTemplatePtr> TemplateMap;
  747. TemplateMap::const_iterator templatesBegin() { return mTemplates.begin(); }
  748. TemplateMap::const_iterator templatesEnd() { return mTemplates.end(); }
  749. // test for existence
  750. bool templateExists(const std::string& name);
  751. // useful if you're reloading the file
  752. void clearTemplates();   // erase all templates
  753. void forceResponse(const LLNotification::Params& params, S32 option);
  754. void createDefaultChannels();
  755. typedef std::map<std::string, LLNotificationChannelPtr> ChannelMap;
  756. ChannelMap mChannels;
  757. void addChannel(LLNotificationChannelPtr pChan);
  758. LLNotificationChannelPtr getChannel(const std::string& channelName);
  759. std::string getGlobalString(const std::string& key) const;
  760. void setIgnoreAllNotifications(bool ignore);
  761. bool getIgnoreAllNotifications();
  762. private:
  763. // we're a singleton, so we don't have a public constructor
  764. LLNotifications();
  765. /*virtual*/ void initSingleton();
  766. void loadPersistentNotifications();
  767. bool expirationFilter(LLNotificationPtr pNotification);
  768. bool expirationHandler(const LLSD& payload);
  769. bool uniqueFilter(LLNotificationPtr pNotification);
  770. bool uniqueHandler(const LLSD& payload);
  771. bool failedUniquenessTest(const LLSD& payload);
  772. LLNotificationChannelPtr pHistoryChannel;
  773. LLNotificationChannelPtr pExpirationChannel;
  774. // put your template in
  775. bool addTemplate(const std::string& name, LLNotificationTemplatePtr theTemplate);
  776. TemplateMap mTemplates;
  777. std::string mFileName;
  778. typedef std::map<std::string, LLPointer<class LLXMLNode> > XMLTemplateMap;
  779. XMLTemplateMap mXmlTemplates;
  780. LLNotificationMap mUniqueNotifications;
  781. typedef std::map<std::string, std::string> GlobalStringMap;
  782. GlobalStringMap mGlobalStrings;
  783. bool mIgnoreAllNotifications;
  784.     boost::scoped_ptr<LLNotificationsListener> mListener;
  785. };
  786. #endif//LL_LLNOTIFICATIONS_H