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

游戏引擎

开发平台:

C++ Builder

  1. /**
  2. * @file llnotifications.cpp
  3. * @brief Non-UI queue manager for keeping a prioritized list of notifications
  4. *
  5. * $LicenseInfo:firstyear=2008&license=viewergpl$
  6. * Copyright (c) 2008-2010, Linden Research, Inc.
  7. * Second Life Viewer Source Code
  8. * The source code in this file ("Source Code") is provided by Linden Lab
  9. * to you under the terms of the GNU General Public License, version 2.0
  10. * ("GPL"), unless you have obtained a separate licensing agreement
  11. * ("Other License"), formally executed by you and Linden Lab.  Terms of
  12. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  13. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  14. * There are special exceptions to the terms and conditions of the GPL as
  15. * it is applied to this Source Code. View the full text of the exception
  16. * in the file doc/FLOSS-exception.txt in this software distribution, or
  17. * online at
  18. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  19. * By copying, modifying or distributing this software, you acknowledge
  20. * that you have read and understood your obligations described above,
  21. * and agree to abide by those obligations.
  22. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  23. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  24. * COMPLETENESS OR PERFORMANCE.
  25. * $/LicenseInfo$
  26. */
  27. #include "linden_common.h"
  28. #include "llnotifications.h"
  29. #include "llxmlnode.h"
  30. #include "lluictrl.h"
  31. #include "lluictrlfactory.h"
  32. #include "lldir.h"
  33. #include "llsdserialize.h"
  34. #include "lltrans.h"
  35. #include "llnotificationslistener.h"
  36. #include <algorithm>
  37. #include <boost/regex.hpp>
  38. const std::string NOTIFICATION_PERSIST_VERSION = "0.93";
  39. // local channel for notification history
  40. class LLNotificationHistoryChannel : public LLNotificationChannel
  41. {
  42. LOG_CLASS(LLNotificationHistoryChannel);
  43. public:
  44. LLNotificationHistoryChannel(const std::string& filename) : 
  45. LLNotificationChannel("History", "Visible", &historyFilter, LLNotificationComparators::orderByUUID()),
  46. mFileName(filename)
  47. {
  48. connectChanged(boost::bind(&LLNotificationHistoryChannel::historyHandler, this, _1));
  49. loadPersistentNotifications();
  50. }
  51. private:
  52. bool historyHandler(const LLSD& payload)
  53. {
  54. // we ignore "load" messages, but rewrite the persistence file on any other
  55. std::string sigtype = payload["sigtype"];
  56. if (sigtype != "load")
  57. {
  58. savePersistentNotifications();
  59. }
  60. return false;
  61. }
  62. // The history channel gets all notifications except those that have been cancelled
  63. static bool historyFilter(LLNotificationPtr pNotification)
  64. {
  65. return !pNotification->isCancelled();
  66. }
  67. void savePersistentNotifications()
  68. {
  69. /* NOTE: As of 2009-11-09 the reload of notifications on startup does not
  70. work, and has not worked for months.  Skip saving notifications until the
  71. read can be fixed, because this hits the disk once per notification and
  72. causes log spam.  James
  73. llinfos << "Saving open notifications to " << mFileName << llendl;
  74. llofstream notify_file(mFileName.c_str());
  75. if (!notify_file.is_open()) 
  76. {
  77. llwarns << "Failed to open " << mFileName << llendl;
  78. return;
  79. }
  80. LLSD output;
  81. output["version"] = NOTIFICATION_PERSIST_VERSION;
  82. LLSD& data = output["data"];
  83. for (LLNotificationSet::iterator it = mItems.begin(); it != mItems.end(); ++it)
  84. {
  85. if (!LLNotifications::instance().templateExists((*it)->getName())) continue;
  86. // only store notifications flagged as persisting
  87. LLNotificationTemplatePtr templatep = LLNotifications::instance().getTemplate((*it)->getName());
  88. if (!templatep->mPersist) continue;
  89. data.append((*it)->asLLSD());
  90. }
  91. LLPointer<LLSDFormatter> formatter = new LLSDXMLFormatter();
  92. formatter->format(output, notify_file, LLSDFormatter::OPTIONS_PRETTY);
  93. */
  94. }
  95. void loadPersistentNotifications()
  96. {
  97. llinfos << "Loading open notifications from " << mFileName << llendl;
  98. llifstream notify_file(mFileName.c_str());
  99. if (!notify_file.is_open()) 
  100. {
  101. llwarns << "Failed to open " << mFileName << llendl;
  102. return;
  103. }
  104. LLSD input;
  105. LLPointer<LLSDParser> parser = new LLSDXMLParser();
  106. if (parser->parse(notify_file, input, LLSDSerialize::SIZE_UNLIMITED) < 0)
  107. {
  108. llwarns << "Failed to parse open notifications" << llendl;
  109. return;
  110. }
  111. if (input.isUndefined()) return;
  112. std::string version = input["version"];
  113. if (version != NOTIFICATION_PERSIST_VERSION)
  114. {
  115. llwarns << "Bad open notifications version: " << version << llendl;
  116. return;
  117. }
  118. LLSD& data = input["data"];
  119. if (data.isUndefined()) return;
  120. LLNotifications& instance = LLNotifications::instance();
  121. for (LLSD::array_const_iterator notification_it = data.beginArray();
  122. notification_it != data.endArray();
  123. ++notification_it)
  124. {
  125. instance.add(LLNotificationPtr(new LLNotification(*notification_it)));
  126. }
  127. }
  128. //virtual
  129. void onDelete(LLNotificationPtr pNotification)
  130. {
  131. // we want to keep deleted notifications in our log
  132. mItems.insert(pNotification);
  133. return;
  134. }
  135. private:
  136. std::string mFileName;
  137. };
  138. bool filterIgnoredNotifications(LLNotificationPtr notification)
  139. {
  140. // filter everything if we are to ignore ALL
  141. if(LLNotifications::instance().getIgnoreAllNotifications())
  142. {
  143. return false;
  144. }
  145. LLNotificationFormPtr form = notification->getForm();
  146. // Check to see if the user wants to ignore this alert
  147. if (form->getIgnoreType() != LLNotificationForm::IGNORE_NO)
  148. {
  149. return LLUI::sSettingGroups["ignores"]->getBOOL(notification->getName());
  150. }
  151. return true;
  152. }
  153. bool handleIgnoredNotification(const LLSD& payload)
  154. {
  155. if (payload["sigtype"].asString() == "add")
  156. {
  157. LLNotificationPtr pNotif = LLNotifications::instance().find(payload["id"].asUUID());
  158. if (!pNotif) return false;
  159. LLNotificationFormPtr form = pNotif->getForm();
  160. LLSD response;
  161. switch(form->getIgnoreType())
  162. {
  163. case LLNotificationForm::IGNORE_WITH_DEFAULT_RESPONSE:
  164. response = pNotif->getResponseTemplate(LLNotification::WITH_DEFAULT_BUTTON);
  165. break;
  166. case LLNotificationForm::IGNORE_WITH_LAST_RESPONSE:
  167. response = LLUI::sSettingGroups["ignores"]->getLLSD("Default" + pNotif->getName());
  168. break;
  169. case LLNotificationForm::IGNORE_SHOW_AGAIN:
  170. break;
  171. default:
  172. return false;
  173. }
  174. pNotif->setIgnored(true);
  175. pNotif->respond(response);
  176. return true;  // don't process this item any further
  177. }
  178. return false;
  179. }
  180. namespace LLNotificationFilters
  181. {
  182. // a sample filter
  183. bool includeEverything(LLNotificationPtr p)
  184. {
  185. return true;
  186. }
  187. };
  188. LLNotificationForm::LLNotificationForm()
  189. : mFormData(LLSD::emptyArray()),
  190. mIgnore(IGNORE_NO)
  191. {
  192. }
  193. LLNotificationForm::LLNotificationForm(const std::string& name, const LLXMLNodePtr xml_node) 
  194. : mFormData(LLSD::emptyArray()),
  195. mIgnore(IGNORE_NO)
  196. {
  197. if (!xml_node->hasName("form"))
  198. {
  199. llwarns << "Bad xml node for form: " << xml_node->getName() << llendl;
  200. }
  201. LLXMLNodePtr child = xml_node->getFirstChild();
  202. while(child)
  203. {
  204. child = LLNotifications::instance().checkForXMLTemplate(child);
  205. LLSD item_entry;
  206. std::string element_name = child->getName()->mString;
  207. if (element_name == "ignore" )
  208. {
  209. bool save_option = false;
  210. child->getAttribute_bool("save_option", save_option);
  211. if (!save_option)
  212. {
  213. mIgnore = IGNORE_WITH_DEFAULT_RESPONSE;
  214. }
  215. else
  216. {
  217. // remember last option chosen by user and automatically respond with that in the future
  218. mIgnore = IGNORE_WITH_LAST_RESPONSE;
  219. LLUI::sSettingGroups["ignores"]->declareLLSD(std::string("Default") + name, "", std::string("Default response for notification " + name));
  220. }
  221. child->getAttributeString("text", mIgnoreMsg);
  222. BOOL show_notification = TRUE;
  223. LLUI::sSettingGroups["ignores"]->declareBOOL(name, show_notification, "Ignore notification with this name", TRUE);
  224. }
  225. else
  226. {
  227. // flatten xml form entry into single LLSD map with type==name
  228. item_entry["type"] = element_name;
  229. const LLXMLAttribList::iterator attrib_end = child->mAttributes.end();
  230. for(LLXMLAttribList::iterator attrib_it = child->mAttributes.begin();
  231. attrib_it != attrib_end;
  232. ++attrib_it)
  233. {
  234. item_entry[std::string(attrib_it->second->getName()->mString)] = attrib_it->second->getValue();
  235. }
  236. item_entry["value"] = child->getTextContents();
  237. mFormData.append(item_entry);
  238. }
  239. child = child->getNextSibling();
  240. }
  241. }
  242. LLNotificationForm::LLNotificationForm(const LLSD& sd)
  243. : mIgnore(IGNORE_NO)
  244. {
  245. if (sd.isArray())
  246. {
  247. mFormData = sd;
  248. }
  249. else
  250. {
  251. llwarns << "Invalid form data " << sd << llendl;
  252. mFormData = LLSD::emptyArray();
  253. }
  254. }
  255. LLSD LLNotificationForm::asLLSD() const
  256. return mFormData; 
  257. }
  258. LLSD LLNotificationForm::getElement(const std::string& element_name)
  259. {
  260. for (LLSD::array_const_iterator it = mFormData.beginArray();
  261. it != mFormData.endArray();
  262. ++it)
  263. {
  264. if ((*it)["name"].asString() == element_name) return (*it);
  265. }
  266. return LLSD();
  267. }
  268. bool LLNotificationForm::hasElement(const std::string& element_name)
  269. {
  270. for (LLSD::array_const_iterator it = mFormData.beginArray();
  271. it != mFormData.endArray();
  272. ++it)
  273. {
  274. if ((*it)["name"].asString() == element_name) return true;
  275. }
  276. return false;
  277. }
  278. void LLNotificationForm::addElement(const std::string& type, const std::string& name, const LLSD& value)
  279. {
  280. LLSD element;
  281. element["type"] = type;
  282. element["name"] = name;
  283. element["text"] = name;
  284. element["value"] = value;
  285. element["index"] = mFormData.size();
  286. mFormData.append(element);
  287. }
  288. void LLNotificationForm::append(const LLSD& sub_form)
  289. {
  290. if (sub_form.isArray())
  291. {
  292. for (LLSD::array_const_iterator it = sub_form.beginArray();
  293. it != sub_form.endArray();
  294. ++it)
  295. {
  296. mFormData.append(*it);
  297. }
  298. }
  299. }
  300. void LLNotificationForm::formatElements(const LLSD& substitutions)
  301. {
  302. for (LLSD::array_iterator it = mFormData.beginArray();
  303. it != mFormData.endArray();
  304. ++it)
  305. {
  306. // format "text" component of each form element
  307. if ((*it).has("text"))
  308. {
  309. std::string text = (*it)["text"].asString();
  310. LLStringUtil::format(text, substitutions);
  311. (*it)["text"] = text;
  312. }
  313. if ((*it)["type"].asString() == "text" && (*it).has("value"))
  314. {
  315. std::string value = (*it)["value"].asString();
  316. LLStringUtil::format(value, substitutions);
  317. (*it)["value"] = value;
  318. }
  319. }
  320. }
  321. std::string LLNotificationForm::getDefaultOption()
  322. {
  323. for (LLSD::array_const_iterator it = mFormData.beginArray();
  324. it != mFormData.endArray();
  325. ++it)
  326. {
  327. if ((*it)["default"]) return (*it)["name"].asString();
  328. }
  329. return "";
  330. }
  331. LLNotificationTemplate::LLNotificationTemplate() :
  332. mExpireSeconds(0),
  333. mExpireOption(-1),
  334. mURLOption(-1),
  335. mURLOpenExternally(-1),
  336. mPersist(false),
  337. mUnique(false),
  338. mPriority(NOTIFICATION_PRIORITY_NORMAL)
  339. {
  340. mForm = LLNotificationFormPtr(new LLNotificationForm()); 
  341. }
  342. LLNotification::LLNotification(const LLNotification::Params& p) : 
  343. mTimestamp(p.time_stamp), 
  344. mSubstitutions(p.substitutions),
  345. mPayload(p.payload),
  346. mExpiresAt(0),
  347. mTemporaryResponder(false),
  348. mRespondedTo(false),
  349. mPriority(p.priority),
  350. mCancelled(false),
  351. mIgnored(false)
  352. {
  353. if (p.functor.name.isChosen())
  354. {
  355. mResponseFunctorName = p.functor.name;
  356. }
  357. else if (p.functor.function.isChosen())
  358. {
  359. mResponseFunctorName = LLUUID::generateNewID().asString();
  360. LLNotificationFunctorRegistry::instance().registerFunctor(mResponseFunctorName, p.functor.function());
  361. mTemporaryResponder = true;
  362. }
  363. mId.generate();
  364. init(p.name, p.form_elements);
  365. }
  366. LLNotification::LLNotification(const LLSD& sd) :
  367. mTemporaryResponder(false),
  368. mRespondedTo(false),
  369. mCancelled(false),
  370. mIgnored(false)
  371. mId.generate();
  372. mSubstitutions = sd["substitutions"];
  373. mPayload = sd["payload"]; 
  374. mTimestamp = sd["time"]; 
  375. mExpiresAt = sd["expiry"];
  376. mPriority = (ENotificationPriority)sd["priority"].asInteger();
  377. mResponseFunctorName = sd["responseFunctor"].asString();
  378. std::string templatename = sd["name"].asString();
  379. init(templatename, LLSD());
  380. // replace form with serialized version
  381. mForm = LLNotificationFormPtr(new LLNotificationForm(sd["form"]));
  382. }
  383. LLSD LLNotification::asLLSD()
  384. {
  385. LLSD output;
  386. output["name"] = mTemplatep->mName;
  387. output["form"] = getForm()->asLLSD();
  388. output["substitutions"] = mSubstitutions;
  389. output["payload"] = mPayload;
  390. output["time"] = mTimestamp;
  391. output["expiry"] = mExpiresAt;
  392. output["priority"] = (S32)mPriority;
  393. output["responseFunctor"] = mResponseFunctorName;
  394. return output;
  395. }
  396. void LLNotification::update()
  397. {
  398. LLNotifications::instance().update(shared_from_this());
  399. }
  400. void LLNotification::updateFrom(LLNotificationPtr other)
  401. {
  402. // can only update from the same notification type
  403. if (mTemplatep != other->mTemplatep) return;
  404. // NOTE: do NOT change the ID, since it is the key to
  405. // this given instance, just update all the metadata
  406. //mId = other->mId;
  407. mPayload = other->mPayload;
  408. mSubstitutions = other->mSubstitutions;
  409. mTimestamp = other->mTimestamp;
  410. mExpiresAt = other->mExpiresAt;
  411. mCancelled = other->mCancelled;
  412. mIgnored = other->mIgnored;
  413. mPriority = other->mPriority;
  414. mForm = other->mForm;
  415. mResponseFunctorName = other->mResponseFunctorName;
  416. mRespondedTo = other->mRespondedTo;
  417. mTemporaryResponder = other->mTemporaryResponder;
  418. update();
  419. }
  420. const LLNotificationFormPtr LLNotification::getForm()
  421. {
  422. return mForm;
  423. }
  424. void LLNotification::cancel()
  425. {
  426. mCancelled = true;
  427. }
  428. LLSD LLNotification::getResponseTemplate(EResponseTemplateType type)
  429. {
  430. LLSD response = LLSD::emptyMap();
  431. for (S32 element_idx = 0;
  432. element_idx < mForm->getNumElements();
  433. ++element_idx)
  434. {
  435. LLSD element = mForm->getElement(element_idx);
  436. if (element.has("name"))
  437. {
  438. response[element["name"].asString()] = element["value"];
  439. }
  440. if ((type == WITH_DEFAULT_BUTTON) 
  441. && element["default"].asBoolean())
  442. {
  443. response[element["name"].asString()] = true;
  444. }
  445. }
  446. return response;
  447. }
  448. //static
  449. S32 LLNotification::getSelectedOption(const LLSD& notification, const LLSD& response)
  450. {
  451. LLNotificationForm form(notification["form"]);
  452. for (S32 element_idx = 0;
  453. element_idx < form.getNumElements();
  454. ++element_idx)
  455. {
  456. LLSD element = form.getElement(element_idx);
  457. // only look at buttons
  458. if (element["type"].asString() == "button" 
  459. && response[element["name"].asString()].asBoolean())
  460. {
  461. return element["index"].asInteger();
  462. }
  463. }
  464. return -1;
  465. }
  466. //static
  467. std::string LLNotification::getSelectedOptionName(const LLSD& response)
  468. {
  469. for (LLSD::map_const_iterator response_it = response.beginMap();
  470. response_it != response.endMap();
  471. ++response_it)
  472. {
  473. if (response_it->second.isBoolean() && response_it->second.asBoolean())
  474. {
  475. return response_it->first;
  476. }
  477. }
  478. return "";
  479. }
  480. void LLNotification::respond(const LLSD& response)
  481. {
  482. mRespondedTo = true;
  483. // look up the functor
  484. LLNotificationFunctorRegistry::ResponseFunctor functor = 
  485. LLNotificationFunctorRegistry::instance().getFunctor(mResponseFunctorName);
  486. // and then call it
  487. functor(asLLSD(), response);
  488. if (mTemporaryResponder)
  489. {
  490. LLNotificationFunctorRegistry::instance().unregisterFunctor(mResponseFunctorName);
  491. mResponseFunctorName = "";
  492. mTemporaryResponder = false;
  493. }
  494. if (mForm->getIgnoreType() != LLNotificationForm::IGNORE_NO)
  495. {
  496. BOOL show_notification = mIgnored ? FALSE : TRUE;
  497. LLUI::sSettingGroups["ignores"]->setBOOL(getName(), show_notification);
  498. if (mIgnored && mForm->getIgnoreType() == LLNotificationForm::IGNORE_WITH_LAST_RESPONSE)
  499. {
  500. LLUI::sSettingGroups["ignores"]->setLLSD("Default" + getName(), response);
  501. }
  502. }
  503. update();
  504. }
  505. void LLNotification::setIgnored(bool ignore)
  506. {
  507. mIgnored = ignore;
  508. }
  509. void LLNotification::setResponseFunctor(std::string const &responseFunctorName)
  510. {
  511. if (mTemporaryResponder)
  512. // get rid of the old one
  513. LLNotificationFunctorRegistry::instance().unregisterFunctor(mResponseFunctorName);
  514. mResponseFunctorName = responseFunctorName;
  515. mTemporaryResponder = false;
  516. }
  517. bool LLNotification::payloadContainsAll(const std::vector<std::string>& required_fields) const
  518. {
  519. for(std::vector<std::string>::const_iterator required_fields_it = required_fields.begin(); 
  520. required_fields_it != required_fields.end();
  521. required_fields_it++)
  522. {
  523. std::string required_field_name = *required_fields_it;
  524. if( ! getPayload().has(required_field_name))
  525. {
  526. return false; // a required field was not found
  527. }
  528. }
  529. return true; // all required fields were found
  530. }
  531. bool LLNotification::isEquivalentTo(LLNotificationPtr that) const
  532. {
  533. if (this->mTemplatep->mName != that->mTemplatep->mName) 
  534. {
  535. return false; // must have the same template name or forget it
  536. }
  537. if (this->mTemplatep->mUnique)
  538. {
  539. // highlander bit sez there can only be one of these
  540. return
  541. this->payloadContainsAll(that->mTemplatep->mUniqueContext) &&
  542. that->payloadContainsAll(this->mTemplatep->mUniqueContext);
  543. }
  544. return false; 
  545. }
  546. void LLNotification::init(const std::string& template_name, const LLSD& form_elements)
  547. {
  548. mTemplatep = LLNotifications::instance().getTemplate(template_name);
  549. if (!mTemplatep) return;
  550. // add default substitutions
  551. const LLStringUtil::format_map_t& default_args = LLTrans::getDefaultArgs();
  552. for (LLStringUtil::format_map_t::const_iterator iter = default_args.begin();
  553.  iter != default_args.end(); ++iter)
  554. {
  555. mSubstitutions[iter->first] = iter->second;
  556. }
  557. mSubstitutions["_URL"] = getURL();
  558. mSubstitutions["_NAME"] = template_name;
  559. // TODO: something like this so that a missing alert is sensible:
  560. //mSubstitutions["_ARGS"] = get_all_arguments_as_text(mSubstitutions);
  561. mForm = LLNotificationFormPtr(new LLNotificationForm(*mTemplatep->mForm));
  562. mForm->append(form_elements);
  563. // apply substitution to form labels
  564. mForm->formatElements(mSubstitutions);
  565. LLDate rightnow = LLDate::now();
  566. if (mTemplatep->mExpireSeconds)
  567. {
  568. mExpiresAt = LLDate(rightnow.secondsSinceEpoch() + mTemplatep->mExpireSeconds);
  569. }
  570. if (mPriority == NOTIFICATION_PRIORITY_UNSPECIFIED)
  571. {
  572. mPriority = mTemplatep->mPriority;
  573. }
  574. }
  575. std::string LLNotification::summarize() const
  576. {
  577. std::string s = "Notification(";
  578. s += getName();
  579. s += ") : ";
  580. s += mTemplatep ? mTemplatep->mMessage : "";
  581. // should also include timestamp and expiration time (but probably not payload)
  582. return s;
  583. }
  584. std::string LLNotification::getMessage() const
  585. {
  586. // all our callers cache this result, so it gives us more flexibility
  587. // to do the substitution at call time rather than attempting to 
  588. // cache it in the notification
  589. if (!mTemplatep)
  590. return std::string();
  591. std::string message = mTemplatep->mMessage;
  592. LLStringUtil::format(message, mSubstitutions);
  593. return message;
  594. }
  595. std::string LLNotification::getLabel() const
  596. {
  597. std::string label = mTemplatep->mLabel;
  598. LLStringUtil::format(label, mSubstitutions);
  599. return (mTemplatep ? label : "");
  600. }
  601. std::string LLNotification::getURL() const
  602. {
  603. if (!mTemplatep)
  604. return std::string();
  605. std::string url = mTemplatep->mURL;
  606. LLStringUtil::format(url, mSubstitutions);
  607. return (mTemplatep ? url : "");
  608. }
  609. // =========================================================
  610. // LLNotificationChannel implementation
  611. // ---
  612. LLBoundListener LLNotificationChannelBase::connectChangedImpl(const LLEventListener& slot)
  613. {
  614. // when someone wants to connect to a channel, we first throw them
  615. // all of the notifications that are already in the channel
  616. // we use a special signal called "load" in case the channel wants to care
  617. // only about new notifications
  618. for (LLNotificationSet::iterator it = mItems.begin(); it != mItems.end(); ++it)
  619. {
  620. slot(LLSD().with("sigtype", "load").with("id", (*it)->id()));
  621. }
  622. // and then connect the signal so that all future notifications will also be
  623. // forwarded.
  624. return mChanged.connect(slot);
  625. }
  626. LLBoundListener LLNotificationChannelBase::connectAtFrontChangedImpl(const LLEventListener& slot)
  627. {
  628. for (LLNotificationSet::iterator it = mItems.begin(); it != mItems.end(); ++it)
  629. {
  630. slot(LLSD().with("sigtype", "load").with("id", (*it)->id()));
  631. }
  632. return mChanged.connect(slot, boost::signals2::at_front);
  633. }
  634. LLBoundListener LLNotificationChannelBase::connectPassedFilterImpl(const LLEventListener& slot)
  635. {
  636. // these two filters only fire for notifications added after the current one, because
  637. // they don't participate in the hierarchy.
  638. return mPassedFilter.connect(slot);
  639. }
  640. LLBoundListener LLNotificationChannelBase::connectFailedFilterImpl(const LLEventListener& slot)
  641. {
  642. return mFailedFilter.connect(slot);
  643. }
  644. // external call, conforms to our standard signature
  645. bool LLNotificationChannelBase::updateItem(const LLSD& payload)
  646. {
  647. // first check to see if it's in the master list
  648. LLNotificationPtr pNotification  = LLNotifications::instance().find(payload["id"]);
  649. if (!pNotification)
  650. return false; // not found
  651. return updateItem(payload, pNotification);
  652. }
  653. //FIX QUIT NOT WORKING
  654. // internal call, for use in avoiding lookup
  655. bool LLNotificationChannelBase::updateItem(const LLSD& payload, LLNotificationPtr pNotification)
  656. {
  657. std::string cmd = payload["sigtype"];
  658. LLNotificationSet::iterator foundItem = mItems.find(pNotification);
  659. bool wasFound = (foundItem != mItems.end());
  660. bool passesFilter = mFilter(pNotification);
  661. // first, we offer the result of the filter test to the simple
  662. // signals for pass/fail. One of these is guaranteed to be called.
  663. // If either signal returns true, the change processing is NOT performed
  664. // (so don't return true unless you know what you're doing!)
  665. bool abortProcessing = false;
  666. if (passesFilter)
  667. {
  668. abortProcessing = mPassedFilter(payload);
  669. }
  670. else
  671. {
  672. abortProcessing = mFailedFilter(payload);
  673. }
  674. if (abortProcessing)
  675. {
  676. return true;
  677. }
  678. if (cmd == "load")
  679. {
  680. // should be no reason we'd ever get a load if we already have it
  681. // if passes filter send a load message, else do nothing
  682. assert(!wasFound);
  683. if (passesFilter)
  684. {
  685. // not in our list, add it and say so
  686. mItems.insert(pNotification);
  687. abortProcessing = mChanged(payload);
  688. onLoad(pNotification);
  689. }
  690. }
  691. else if (cmd == "change")
  692. {
  693. // if it passes filter now and was found, we just send a change message
  694. // if it passes filter now and wasn't found, we have to add it
  695. // if it doesn't pass filter and wasn't found, we do nothing
  696. // if it doesn't pass filter and was found, we need to delete it
  697. if (passesFilter)
  698. {
  699. if (wasFound)
  700. {
  701. // it already existed, so this is a change
  702. // since it changed in place, all we have to do is resend the signal
  703. abortProcessing = mChanged(payload);
  704. onChange(pNotification);
  705. }
  706. else
  707. {
  708. // not in our list, add it and say so
  709. mItems.insert(pNotification);
  710. // our payload is const, so make a copy before changing it
  711. LLSD newpayload = payload;
  712. newpayload["sigtype"] = "add";
  713. abortProcessing = mChanged(newpayload);
  714. onChange(pNotification);
  715. }
  716. }
  717. else
  718. {
  719. if (wasFound)
  720. {
  721. // it already existed, so this is a delete
  722. mItems.erase(pNotification);
  723. // our payload is const, so make a copy before changing it
  724. LLSD newpayload = payload;
  725. newpayload["sigtype"] = "delete";
  726. abortProcessing = mChanged(newpayload);
  727. onChange(pNotification);
  728. }
  729. // didn't pass, not on our list, do nothing
  730. }
  731. }
  732. else if (cmd == "add")
  733. {
  734. // should be no reason we'd ever get an add if we already have it
  735. // if passes filter send an add message, else do nothing
  736. assert(!wasFound);
  737. if (passesFilter)
  738. {
  739. // not in our list, add it and say so
  740. mItems.insert(pNotification);
  741. abortProcessing = mChanged(payload);
  742. onAdd(pNotification);
  743. }
  744. }
  745. else if (cmd == "delete")
  746. {
  747. // if we have it in our list, pass on the delete, then delete it, else do nothing
  748. if (wasFound)
  749. {
  750. abortProcessing = mChanged(payload);
  751. mItems.erase(pNotification);
  752. onDelete(pNotification);
  753. }
  754. }
  755. return abortProcessing;
  756. }
  757. /* static */
  758. LLNotificationChannelPtr LLNotificationChannel::buildChannel(const std::string& name, 
  759.  const std::string& parent,
  760.  LLNotificationFilter filter, 
  761.  LLNotificationComparator comparator)
  762. {
  763. // note: this is not a leak; notifications are self-registering.
  764. // This factory helps to prevent excess deletions by making sure all smart
  765. // pointers to notification channels come from the same source
  766. new LLNotificationChannel(name, parent, filter, comparator);
  767. return LLNotifications::instance().getChannel(name);
  768. }
  769. LLNotificationChannel::LLNotificationChannel(const std::string& name, 
  770.  const std::string& parent,
  771.  LLNotificationFilter filter, 
  772.  LLNotificationComparator comparator) : 
  773. LLNotificationChannelBase(filter, comparator),
  774. mName(name),
  775. mParent(parent)
  776. {
  777. // store myself in the channel map
  778. LLNotifications::instance().addChannel(LLNotificationChannelPtr(this));
  779. // bind to notification broadcast
  780. if (parent.empty())
  781. {
  782. LLNotifications::instance().connectChanged(
  783. boost::bind(&LLNotificationChannelBase::updateItem, this, _1));
  784. }
  785. else
  786. {
  787. LLNotificationChannelPtr p = LLNotifications::instance().getChannel(parent);
  788. p->connectChanged(boost::bind(&LLNotificationChannelBase::updateItem, this, _1));
  789. }
  790. }
  791. void LLNotificationChannel::setComparator(LLNotificationComparator comparator) 
  792. mComparator = comparator; 
  793. LLNotificationSet s2(mComparator);
  794. s2.insert(mItems.begin(), mItems.end());
  795. mItems.swap(s2);
  796. // notify clients that we've been resorted
  797. mChanged(LLSD().with("sigtype", "sort")); 
  798. }
  799. bool LLNotificationChannel::isEmpty() const
  800. {
  801. return mItems.empty();
  802. }
  803. LLNotificationChannel::Iterator LLNotificationChannel::begin()
  804. {
  805. return mItems.begin();
  806. }
  807. LLNotificationChannel::Iterator LLNotificationChannel::end()
  808. {
  809. return mItems.end();
  810. }
  811. std::string LLNotificationChannel::summarize()
  812. {
  813. std::string s("Channel '");
  814. s += mName;
  815. s += "'n  ";
  816. for (LLNotificationChannel::Iterator it = begin(); it != end(); ++it)
  817. {
  818. s += (*it)->summarize();
  819. s += "n  ";
  820. }
  821. return s;
  822. }
  823. // ---
  824. // END OF LLNotificationChannel implementation
  825. // =========================================================
  826. // =========================================================
  827. // LLNotifications implementation
  828. // ---
  829. LLNotifications::LLNotifications() : LLNotificationChannelBase(LLNotificationFilters::includeEverything,
  830.    LLNotificationComparators::orderByUUID()),
  831. mIgnoreAllNotifications(false)
  832. {
  833. LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Notification.Show", boost::bind(&LLNotifications::addFromCallback, this, _2));
  834.     mListener.reset(new LLNotificationsListener(*this));
  835. }
  836. // The expiration channel gets all notifications that are cancelled
  837. bool LLNotifications::expirationFilter(LLNotificationPtr pNotification)
  838. {
  839. return pNotification->isCancelled() || pNotification->isRespondedTo();
  840. }
  841. bool LLNotifications::expirationHandler(const LLSD& payload)
  842. {
  843. if (payload["sigtype"].asString() != "delete")
  844. {
  845. // anything added to this channel actually should be deleted from the master
  846. cancel(find(payload["id"]));
  847. return true; // don't process this item any further
  848. }
  849. return false;
  850. }
  851. bool LLNotifications::uniqueFilter(LLNotificationPtr pNotif)
  852. {
  853. if (!pNotif->hasUniquenessConstraints())
  854. {
  855. return true;
  856. }
  857. // checks against existing unique notifications
  858. for (LLNotificationMap::iterator existing_it = mUniqueNotifications.find(pNotif->getName());
  859. existing_it != mUniqueNotifications.end();
  860. ++existing_it)
  861. {
  862. LLNotificationPtr existing_notification = existing_it->second;
  863. if (pNotif != existing_notification 
  864. && pNotif->isEquivalentTo(existing_notification))
  865. {
  866. return false;
  867. }
  868. }
  869. return true;
  870. }
  871. bool LLNotifications::uniqueHandler(const LLSD& payload)
  872. {
  873. LLNotificationPtr pNotif = LLNotifications::instance().find(payload["id"].asUUID());
  874. if (pNotif && pNotif->hasUniquenessConstraints()) 
  875. {
  876. if (payload["sigtype"].asString() == "add")
  877. {
  878. // not a duplicate according to uniqueness criteria, so we keep it
  879. // and store it for future uniqueness checks
  880. mUniqueNotifications.insert(std::make_pair(pNotif->getName(), pNotif));
  881. }
  882. else if (payload["sigtype"].asString() == "delete")
  883. {
  884. mUniqueNotifications.erase(pNotif->getName());
  885. }
  886. }
  887. return false;
  888. }
  889. bool LLNotifications::failedUniquenessTest(const LLSD& payload)
  890. {
  891. LLNotificationPtr pNotif = LLNotifications::instance().find(payload["id"].asUUID());
  892. if (!pNotif || !pNotif->hasUniquenessConstraints())
  893. {
  894. return false;
  895. }
  896. // checks against existing unique notifications
  897. for (LLNotificationMap::iterator existing_it = mUniqueNotifications.find(pNotif->getName());
  898. existing_it != mUniqueNotifications.end();
  899. ++existing_it)
  900. {
  901. LLNotificationPtr existing_notification = existing_it->second;
  902. if (pNotif != existing_notification 
  903. && pNotif->isEquivalentTo(existing_notification))
  904. {
  905. // copy notification instance data over to oldest instance
  906. // of this unique notification and update it
  907. existing_notification->updateFrom(pNotif);
  908. // then delete the new one
  909. pNotif->cancel();
  910. }
  911. }
  912. return false;
  913. }
  914. void LLNotifications::addChannel(LLNotificationChannelPtr pChan)
  915. {
  916. mChannels[pChan->getName()] = pChan;
  917. }
  918. LLNotificationChannelPtr LLNotifications::getChannel(const std::string& channelName)
  919. {
  920. ChannelMap::iterator p = mChannels.find(channelName);
  921. if(p == mChannels.end())
  922. {
  923. llerrs << "Did not find channel named " << channelName << llendl;
  924. return LLNotificationChannelPtr();
  925. }
  926. return p->second;
  927. }
  928. // this function is called once at construction time, after the object is constructed.
  929. void LLNotifications::initSingleton()
  930. {
  931. loadTemplates();
  932. createDefaultChannels();
  933. }
  934. void LLNotifications::createDefaultChannels()
  935. {
  936. // now construct the various channels AFTER loading the notifications,
  937. // because the history channel is going to rewrite the stored notifications file
  938. LLNotificationChannel::buildChannel("Expiration", "",
  939. boost::bind(&LLNotifications::expirationFilter, this, _1));
  940. LLNotificationChannel::buildChannel("Unexpired", "",
  941. !boost::bind(&LLNotifications::expirationFilter, this, _1)); // use negated bind
  942. LLNotificationChannel::buildChannel("Unique", "Unexpired",
  943. boost::bind(&LLNotifications::uniqueFilter, this, _1));
  944. LLNotificationChannel::buildChannel("Ignore", "Unique",
  945. filterIgnoredNotifications);
  946. LLNotificationChannel::buildChannel("Visible", "Ignore",
  947. &LLNotificationFilters::includeEverything);
  948. // create special history channel
  949. //std::string notifications_log_file = gDirUtilp->getExpandedFilename ( LL_PATH_PER_SL_ACCOUNT, "open_notifications.xml" );
  950. // use ^^^ when done debugging notifications serialization
  951. std::string notifications_log_file = gDirUtilp->getExpandedFilename ( LL_PATH_USER_SETTINGS, "open_notifications.xml" );
  952. // this isn't a leak, don't worry about the empty "new"
  953. new LLNotificationHistoryChannel(notifications_log_file);
  954. // connect action methods to these channels
  955. LLNotifications::instance().getChannel("Expiration")->
  956.         connectChanged(boost::bind(&LLNotifications::expirationHandler, this, _1));
  957. // uniqueHandler slot should be added as first slot of the signal due to
  958. // usage LLStopWhenHandled combiner in LLStandardSignal
  959. LLNotifications::instance().getChannel("Unique")->
  960.         connectAtFrontChanged(boost::bind(&LLNotifications::uniqueHandler, this, _1));
  961. // failedUniquenessTest slot isn't necessary
  962. // LLNotifications::instance().getChannel("Unique")->
  963. //        connectFailedFilter(boost::bind(&LLNotifications::failedUniquenessTest, this, _1));
  964. LLNotifications::instance().getChannel("Ignore")->
  965. connectFailedFilter(&handleIgnoredNotification);
  966. }
  967. bool LLNotifications::addTemplate(const std::string &name, 
  968.   LLNotificationTemplatePtr theTemplate)
  969. {
  970. if (mTemplates.count(name))
  971. {
  972. llwarns << "LLNotifications -- attempted to add template '" << name << "' twice." << llendl;
  973. return false;
  974. }
  975. mTemplates[name] = theTemplate;
  976. return true;
  977. }
  978. LLNotificationTemplatePtr LLNotifications::getTemplate(const std::string& name)
  979. {
  980. if (mTemplates.count(name))
  981. {
  982. return mTemplates[name];
  983. }
  984. else
  985. {
  986. return mTemplates["MissingAlert"];
  987. }
  988. }
  989. bool LLNotifications::templateExists(const std::string& name)
  990. {
  991. return (mTemplates.count(name) != 0);
  992. }
  993. void LLNotifications::clearTemplates()
  994. {
  995. mTemplates.clear();
  996. }
  997. void LLNotifications::forceResponse(const LLNotification::Params& params, S32 option)
  998. {
  999. LLNotificationPtr temp_notify(new LLNotification(params));
  1000. LLSD response = temp_notify->getResponseTemplate();
  1001. LLSD selected_item = temp_notify->getForm()->getElement(option);
  1002. if (selected_item.isUndefined())
  1003. {
  1004. llwarns << "Invalid option" << option << " for notification " << (std::string)params.name << llendl;
  1005. return;
  1006. }
  1007. response[selected_item["name"].asString()] = true;
  1008. temp_notify->respond(response);
  1009. }
  1010. LLNotifications::TemplateNames LLNotifications::getTemplateNames() const
  1011. {
  1012. TemplateNames names;
  1013. for (TemplateMap::const_iterator it = mTemplates.begin(); it != mTemplates.end(); ++it)
  1014. {
  1015. names.push_back(it->first);
  1016. }
  1017. return names;
  1018. }
  1019. typedef std::map<std::string, std::string> StringMap;
  1020. void replaceSubstitutionStrings(LLXMLNodePtr node, StringMap& replacements)
  1021. {
  1022. //llwarns << "replaceSubstitutionStrings" << llendl;
  1023. // walk the list of attributes looking for replacements
  1024. for (LLXMLAttribList::iterator it=node->mAttributes.begin();
  1025.  it != node->mAttributes.end(); ++it)
  1026. {
  1027. std::string value = it->second->getValue();
  1028. if (value[0] == '$')
  1029. {
  1030. value.erase(0, 1); // trim off the $
  1031. std::string replacement;
  1032. StringMap::const_iterator found = replacements.find(value);
  1033. if (found != replacements.end())
  1034. {
  1035. replacement = found->second;
  1036. //llwarns << "replaceSubstituionStrings: value: " << value << " repl: " << replacement << llendl;
  1037. it->second->setValue(replacement);
  1038. }
  1039. else
  1040. {
  1041. llwarns << "replaceSubstituionStrings FAILURE: value: " << value << " repl: " << replacement << llendl;
  1042. }
  1043. }
  1044. }
  1045. // now walk the list of children and call this recursively.
  1046. for (LLXMLNodePtr child = node->getFirstChild(); 
  1047.  child.notNull(); child = child->getNextSibling())
  1048. {
  1049. replaceSubstitutionStrings(child, replacements);
  1050. }
  1051. }
  1052. // private to this file
  1053. // returns true if the template request was invalid and there's nothing else we
  1054. // can do with this node, false if you should keep processing (it may have
  1055. // replaced the contents of the node referred to)
  1056. LLXMLNodePtr LLNotifications::checkForXMLTemplate(LLXMLNodePtr item)
  1057. {
  1058. if (item->hasName("usetemplate"))
  1059. {
  1060. std::string replacementName;
  1061. if (item->getAttributeString("name", replacementName))
  1062. {
  1063. StringMap replacements;
  1064. for (LLXMLAttribList::const_iterator it=item->mAttributes.begin(); 
  1065.  it != item->mAttributes.end(); ++it)
  1066. {
  1067. replacements[it->second->getName()->mString] = it->second->getValue();
  1068. }
  1069. if (mXmlTemplates.count(replacementName))
  1070. {
  1071. item=LLXMLNode::replaceNode(item, mXmlTemplates[replacementName]);
  1072. // walk the nodes looking for $(substitution) here and replace
  1073. replaceSubstitutionStrings(item, replacements);
  1074. }
  1075. else
  1076. {
  1077. llwarns << "XML template lookup failure on '" << replacementName << "' " << llendl;
  1078. }
  1079. }
  1080. }
  1081. return item;
  1082. }
  1083. bool LLNotifications::loadTemplates()
  1084. {
  1085. const std::string xml_filename = "notifications.xml";
  1086. LLXMLNodePtr root;
  1087. BOOL success  = LLUICtrlFactory::getLayeredXMLNode(xml_filename, root);
  1088. if (!success || root.isNull() || !root->hasName( "notifications" ))
  1089. {
  1090. llerrs << "Problem reading UI Notifications file: " << xml_filename << llendl;
  1091. return false;
  1092. }
  1093. clearTemplates();
  1094. for (LLXMLNodePtr item = root->getFirstChild();
  1095.  item.notNull(); item = item->getNextSibling())
  1096. {
  1097. // we do this FIRST so that item can be changed if we 
  1098. // encounter a usetemplate -- we just replace the
  1099. // current xml node and keep processing
  1100. item = checkForXMLTemplate(item);
  1101. if (item->hasName("global"))
  1102. {
  1103. std::string global_name;
  1104. if (item->getAttributeString("name", global_name))
  1105. {
  1106. mGlobalStrings[global_name] = item->getTextContents();
  1107. }
  1108. continue;
  1109. }
  1110. if (item->hasName("template"))
  1111. {
  1112. // store an xml template; templates must have a single node (can contain
  1113. // other nodes)
  1114. std::string name;
  1115. item->getAttributeString("name", name);
  1116. LLXMLNodePtr ptr = item->getFirstChild();
  1117. mXmlTemplates[name] = ptr;
  1118. continue;
  1119. }
  1120. if (!item->hasName("notification"))
  1121. {
  1122.             llwarns << "Unexpected entity " << item->getName()->mString << 
  1123.                        " found in " << xml_filename << llendl;
  1124. continue;
  1125. }
  1126. // now we know we have a notification entry, so let's build it
  1127. LLNotificationTemplatePtr pTemplate(new LLNotificationTemplate());
  1128. if (!item->getAttributeString("name", pTemplate->mName))
  1129. {
  1130. llwarns << "Unable to parse notification with no name" << llendl;
  1131. continue;
  1132. }
  1133. //llinfos << "Parsing " << pTemplate->mName << llendl;
  1134. pTemplate->mMessage = item->getTextContents();
  1135. pTemplate->mDefaultFunctor = pTemplate->mName;
  1136. item->getAttributeString("type", pTemplate->mType);
  1137. item->getAttributeString("icon", pTemplate->mIcon);
  1138. item->getAttributeString("label", pTemplate->mLabel);
  1139. item->getAttributeU32("duration", pTemplate->mExpireSeconds);
  1140. item->getAttributeU32("expireOption", pTemplate->mExpireOption);
  1141. std::string priority;
  1142. item->getAttributeString("priority", priority);
  1143. pTemplate->mPriority = NOTIFICATION_PRIORITY_NORMAL;
  1144. if (!priority.empty())
  1145. {
  1146. if (priority == "low")      pTemplate->mPriority = NOTIFICATION_PRIORITY_LOW;
  1147. if (priority == "normal")   pTemplate->mPriority = NOTIFICATION_PRIORITY_NORMAL;
  1148. if (priority == "high")     pTemplate->mPriority = NOTIFICATION_PRIORITY_HIGH;
  1149. if (priority == "critical") pTemplate->mPriority = NOTIFICATION_PRIORITY_CRITICAL;
  1150. }
  1151. item->getAttributeString("functor", pTemplate->mDefaultFunctor);
  1152. BOOL persist = false;
  1153. item->getAttributeBOOL("persist", persist);
  1154. pTemplate->mPersist = persist;
  1155. std::string sound;
  1156. item->getAttributeString("sound", sound);
  1157. if (!sound.empty())
  1158. {
  1159. // test for bad sound effect name / missing effect
  1160. if (LLUI::sSettingGroups["config"]->controlExists(sound))
  1161. {
  1162. pTemplate->mSoundEffect = 
  1163. LLUUID(LLUI::sSettingGroups["config"]->getString(sound));
  1164. }
  1165. else
  1166. {
  1167. llwarns << "Unknown sound effect control name " << sound
  1168. << llendl;
  1169. }
  1170. }
  1171. for (LLXMLNodePtr child = item->getFirstChild();
  1172.  !child.isNull(); child = child->getNextSibling())
  1173. {
  1174. child = checkForXMLTemplate(child);
  1175. // <url>
  1176. if (child->hasName("url"))
  1177. {
  1178. pTemplate->mURL = child->getTextContents();
  1179. child->getAttributeU32("option", pTemplate->mURLOption);
  1180. child->getAttributeU32("openexternally", pTemplate->mURLOpenExternally);
  1181. }
  1182.             if (child->hasName("unique"))
  1183.             {
  1184.                 pTemplate->mUnique = true;
  1185.                 for (LLXMLNodePtr formitem = child->getFirstChild();
  1186.                      !formitem.isNull(); formitem = formitem->getNextSibling())
  1187.                 {
  1188.                     if (formitem->hasName("context"))
  1189.                     {
  1190.                         std::string key;
  1191.                         formitem->getAttributeString("key", key);
  1192.                         pTemplate->mUniqueContext.push_back(key);
  1193.                         //llwarns << "adding " << key << " to unique context" << llendl;
  1194.                     }
  1195.                     else
  1196.                     {
  1197.                         llwarns << "'unique' has unrecognized subelement " 
  1198.                         << formitem->getName()->mString << llendl;
  1199.                     }
  1200.                 }
  1201.             }
  1202.             
  1203. // <form>
  1204. if (child->hasName("form"))
  1205. {
  1206.                 pTemplate->mForm = LLNotificationFormPtr(new LLNotificationForm(pTemplate->mName, child));
  1207. }
  1208. }
  1209. addTemplate(pTemplate->mName, pTemplate);
  1210. }
  1211. //std::ostringstream ostream;
  1212. //root->writeToOstream(ostream, "n  ");
  1213. //llwarns << ostream.str() << llendl;
  1214. return true;
  1215. }
  1216. // Add a simple notification (from XUI)
  1217. void LLNotifications::addFromCallback(const LLSD& name)
  1218. {
  1219. add(LLNotification::Params().name(name.asString()));
  1220. }
  1221. LLNotificationPtr LLNotifications::add(const std::string& name, 
  1222.    const LLSD& substitutions, 
  1223.    const LLSD& payload)
  1224. {
  1225. LLNotification::Params::Functor functor_p;
  1226. functor_p.name = name;
  1227. return add(LLNotification::Params().name(name).substitutions(substitutions).payload(payload).functor(functor_p));
  1228. }
  1229. LLNotificationPtr LLNotifications::add(const std::string& name, 
  1230.    const LLSD& substitutions, 
  1231.    const LLSD& payload, 
  1232.    const std::string& functor_name)
  1233. {
  1234. LLNotification::Params::Functor functor_p;
  1235. functor_p.name = functor_name;
  1236. return add(LLNotification::Params().name(name).substitutions(substitutions).payload(payload).functor(functor_p));
  1237. }
  1238.   
  1239. //virtual
  1240. LLNotificationPtr LLNotifications::add(const std::string& name, 
  1241. const LLSD& substitutions, 
  1242. const LLSD& payload, 
  1243. LLNotificationFunctorRegistry::ResponseFunctor functor)
  1244. {
  1245. LLNotification::Params::Functor functor_p;
  1246. functor_p.function = functor;
  1247. return add(LLNotification::Params().name(name).substitutions(substitutions).payload(payload).functor(functor_p));
  1248. }
  1249. // generalized add function that takes a parameter block object for more complex instantiations
  1250. LLNotificationPtr LLNotifications::add(const LLNotification::Params& p)
  1251. {
  1252. LLNotificationPtr pNotif(new LLNotification(p));
  1253. add(pNotif);
  1254. return pNotif;
  1255. }
  1256. void LLNotifications::add(const LLNotificationPtr pNotif)
  1257. {
  1258. // first see if we already have it -- if so, that's a problem
  1259. LLNotificationSet::iterator it=mItems.find(pNotif);
  1260. if (it != mItems.end())
  1261. {
  1262. llerrs << "Notification added a second time to the master notification channel." << llendl;
  1263. }
  1264. updateItem(LLSD().with("sigtype", "add").with("id", pNotif->id()), pNotif);
  1265. }
  1266. void LLNotifications::cancel(LLNotificationPtr pNotif)
  1267. {
  1268. LLNotificationSet::iterator it=mItems.find(pNotif);
  1269. if (it == mItems.end())
  1270. {
  1271. llerrs << "Attempted to delete nonexistent notification " << pNotif->getName() << llendl;
  1272. }
  1273. pNotif->cancel();
  1274. updateItem(LLSD().with("sigtype", "delete").with("id", pNotif->id()), pNotif);
  1275. }
  1276. void LLNotifications::update(const LLNotificationPtr pNotif)
  1277. {
  1278. LLNotificationSet::iterator it=mItems.find(pNotif);
  1279. if (it != mItems.end())
  1280. {
  1281. updateItem(LLSD().with("sigtype", "change").with("id", pNotif->id()), pNotif);
  1282. }
  1283. }
  1284. LLNotificationPtr LLNotifications::find(LLUUID uuid)
  1285. {
  1286. LLNotificationPtr target = LLNotificationPtr(new LLNotification(uuid));
  1287. LLNotificationSet::iterator it=mItems.find(target);
  1288. if (it == mItems.end())
  1289. {
  1290. llwarns << "Tried to dereference uuid '" << uuid << "' as a notification key but didn't find it." << llendl;
  1291. return LLNotificationPtr((LLNotification*)NULL);
  1292. }
  1293. else
  1294. {
  1295. return *it;
  1296. }
  1297. }
  1298. void LLNotifications::forEachNotification(NotificationProcess process)
  1299. {
  1300. std::for_each(mItems.begin(), mItems.end(), process);
  1301. }
  1302. std::string LLNotifications::getGlobalString(const std::string& key) const
  1303. {
  1304. GlobalStringMap::const_iterator it = mGlobalStrings.find(key);
  1305. if (it != mGlobalStrings.end())
  1306. {
  1307. return it->second;
  1308. }
  1309. else
  1310. {
  1311. // if we don't have the key as a global, return the key itself so that the error
  1312. // is self-diagnosing.
  1313. return key;
  1314. }
  1315. }
  1316. void LLNotifications::setIgnoreAllNotifications(bool setting)
  1317. {
  1318. mIgnoreAllNotifications = setting; 
  1319. }
  1320. bool LLNotifications::getIgnoreAllNotifications()
  1321. {
  1322. return mIgnoreAllNotifications; 
  1323. }
  1324. // ---
  1325. // END OF LLNotifications implementation
  1326. // =========================================================
  1327. std::ostream& operator<<(std::ostream& s, const LLNotification& notification)
  1328. {
  1329. s << notification.summarize();
  1330. return s;
  1331. }