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