diff options
Diffstat (limited to 'indra/llui/llnotifications.cpp')
-rw-r--r-- | indra/llui/llnotifications.cpp | 2678 |
1 files changed, 1343 insertions, 1335 deletions
diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp index 2fe9ee18e3..2fbae73b65 100644 --- a/indra/llui/llnotifications.cpp +++ b/indra/llui/llnotifications.cpp @@ -5,21 +5,21 @@ * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. -* +* * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. -* +* * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. -* +* * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* +* * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -45,248 +45,248 @@ #include <algorithm> #include <boost/regex.hpp> -#include <boost/foreach.hpp> const std::string NOTIFICATION_PERSIST_VERSION = "0.93"; void NotificationPriorityValues::declareValues() { - declare("low", NOTIFICATION_PRIORITY_LOW); - declare("normal", NOTIFICATION_PRIORITY_NORMAL); - declare("high", NOTIFICATION_PRIORITY_HIGH); - declare("critical", NOTIFICATION_PRIORITY_CRITICAL); + declare("low", NOTIFICATION_PRIORITY_LOW); + declare("normal", NOTIFICATION_PRIORITY_NORMAL); + declare("high", NOTIFICATION_PRIORITY_HIGH); + declare("critical", NOTIFICATION_PRIORITY_CRITICAL); } LLNotificationForm::FormElementBase::FormElementBase() -: name("name"), - enabled("enabled", true) +: name("name"), + enabled("enabled", true) {} LLNotificationForm::FormIgnore::FormIgnore() -: text("text"), - control("control"), - invert_control("invert_control", false), - save_option("save_option", false), - session_only("session_only", false), - checkbox_only("checkbox_only", false) +: text("text"), + control("control"), + invert_control("invert_control", false), + save_option("save_option", false), + session_only("session_only", false), + checkbox_only("checkbox_only", false) {} LLNotificationForm::FormButton::FormButton() -: index("index"), - text("text"), - ignore("ignore"), - is_default("default"), - width("width", 0), - type("type") +: index("index"), + text("text"), + ignore("ignore"), + is_default("default"), + width("width", 0), + type("type") { - // set type here so it gets serialized - type = "button"; + // set type here so it gets serialized + type = "button"; } LLNotificationForm::FormInput::FormInput() -: type("type"), - text("text"), - max_length_chars("max_length_chars"), - width("width", 0), - value("value") +: type("type"), + text("text"), + max_length_chars("max_length_chars"), + allow_emoji("allow_emoji"), + width("width", 0), + value("value") {} LLNotificationForm::FormElement::FormElement() -: button("button"), - input("input") +: button("button"), + input("input") {} LLNotificationForm::FormElements::FormElements() -: elements("") +: elements("") {} LLNotificationForm::Params::Params() -: name("name"), - ignore("ignore"), - form_elements("") +: name("name"), + ignore("ignore"), + form_elements("") {} bool filterIgnoredNotifications(LLNotificationPtr notification) { - LLNotificationFormPtr form = notification->getForm(); - // Check to see if the user wants to ignore this alert - return !notification->getForm()->getIgnored(); + LLNotificationFormPtr form = notification->getForm(); + // Check to see if the user wants to ignore this alert + return !notification->getForm()->getIgnored(); } bool handleIgnoredNotification(const LLSD& payload) { - if (payload["sigtype"].asString() == "add") - { - LLNotificationPtr pNotif = LLNotifications::instance().find(payload["id"].asUUID()); - if (!pNotif) return false; - - LLNotificationFormPtr form = pNotif->getForm(); - LLSD response; - switch(form->getIgnoreType()) - { - case LLNotificationForm::IGNORE_WITH_DEFAULT_RESPONSE: - case LLNotificationForm::IGNORE_WITH_DEFAULT_RESPONSE_SESSION_ONLY: - response = pNotif->getResponseTemplate(LLNotification::WITH_DEFAULT_BUTTON); - break; - case LLNotificationForm::IGNORE_WITH_LAST_RESPONSE: - response = LLUI::getInstance()->mSettingGroups["ignores"]->getLLSD("Default" + pNotif->getName()); - break; - case LLNotificationForm::IGNORE_SHOW_AGAIN: - break; - default: - return false; - } - pNotif->setIgnored(true); - pNotif->respond(response); - return true; // don't process this item any further - } - return false; + if (payload["sigtype"].asString() == "add") + { + LLNotificationPtr pNotif = LLNotifications::instance().find(payload["id"].asUUID()); + if (!pNotif) return false; + + LLNotificationFormPtr form = pNotif->getForm(); + LLSD response; + switch(form->getIgnoreType()) + { + case LLNotificationForm::IGNORE_WITH_DEFAULT_RESPONSE: + case LLNotificationForm::IGNORE_WITH_DEFAULT_RESPONSE_SESSION_ONLY: + response = pNotif->getResponseTemplate(LLNotification::WITH_DEFAULT_BUTTON); + break; + case LLNotificationForm::IGNORE_WITH_LAST_RESPONSE: + response = LLUI::getInstance()->mSettingGroups["ignores"]->getLLSD("Default" + pNotif->getName()); + break; + case LLNotificationForm::IGNORE_SHOW_AGAIN: + break; + default: + return false; + } + pNotif->setIgnored(true); + pNotif->respond(response); + return true; // don't process this item any further + } + return false; } bool defaultResponse(const LLSD& payload) { - if (payload["sigtype"].asString() == "add") - { - LLNotificationPtr pNotif = LLNotifications::instance().find(payload["id"].asUUID()); - if (pNotif) - { - // supply default response - pNotif->respond(pNotif->getResponseTemplate(LLNotification::WITH_DEFAULT_BUTTON)); - } - } - return false; + if (payload["sigtype"].asString() == "add") + { + LLNotificationPtr pNotif = LLNotifications::instance().find(payload["id"].asUUID()); + if (pNotif) + { + // supply default response + pNotif->respond(pNotif->getResponseTemplate(LLNotification::WITH_DEFAULT_BUTTON)); + } + } + return false; } bool visibilityRuleMached(const LLSD& payload) { - // This is needed because LLNotifications::isVisibleByRules may have cancelled the notification. - // Returning true here makes LLNotificationChannelBase::updateItem do an early out, which prevents things from happening in the wrong order. - return true; + // This is needed because LLNotifications::isVisibleByRules may have cancelled the notification. + // Returning true here makes LLNotificationChannelBase::updateItem do an early out, which prevents things from happening in the wrong order. + return true; } namespace LLNotificationFilters { - // a sample filter - bool includeEverything(LLNotificationPtr p) - { - return true; - } + // a sample filter + bool includeEverything(LLNotificationPtr p) + { + return true; + } }; LLNotificationForm::LLNotificationForm() -: mIgnore(IGNORE_NO) +: mIgnore(IGNORE_NO) { } LLNotificationForm::LLNotificationForm( const LLNotificationForm& other ) { - mFormData = other.mFormData; - mIgnore = other.mIgnore; - mIgnoreMsg = other.mIgnoreMsg; - mIgnoreSetting = other.mIgnoreSetting; - mInvertSetting = other.mInvertSetting; -} - -LLNotificationForm::LLNotificationForm(const std::string& name, const LLNotificationForm::Params& p) -: mIgnore(IGNORE_NO), - mInvertSetting(false) // ignore settings by default mean true=show, false=ignore -{ - if (p.ignore.isProvided()) - { - // For all cases but IGNORE_CHECKBOX_ONLY this is name for use in preferences - mIgnoreMsg = p.ignore.text; - - LLUI *ui_inst = LLUI::getInstance(); - if (p.ignore.checkbox_only) - { - mIgnore = IGNORE_CHECKBOX_ONLY; - } - else if (!p.ignore.save_option) - { - mIgnore = p.ignore.session_only ? IGNORE_WITH_DEFAULT_RESPONSE_SESSION_ONLY : IGNORE_WITH_DEFAULT_RESPONSE; - } - else - { - // remember last option chosen by user and automatically respond with that in the future - mIgnore = IGNORE_WITH_LAST_RESPONSE; - ui_inst->mSettingGroups["ignores"]->declareLLSD(std::string("Default") + name, "", std::string("Default response for notification " + name)); - } - - BOOL show_notification = TRUE; - if (p.ignore.control.isProvided()) - { - mIgnoreSetting = ui_inst->mSettingGroups["config"]->getControl(p.ignore.control); - mInvertSetting = p.ignore.invert_control; - } - else if (mIgnore > IGNORE_NO) - { - ui_inst->mSettingGroups["ignores"]->declareBOOL(name, show_notification, "Show notification with this name", LLControlVariable::PERSIST_NONDFT); - mIgnoreSetting = ui_inst->mSettingGroups["ignores"]->getControl(name); - } - } - - LLParamSDParser parser; - parser.writeSD(mFormData, p.form_elements); - - for (LLSD::array_iterator it = mFormData.beginArray(), end_it = mFormData.endArray(); - it != end_it; - ++it) - { - // lift contents of form element up a level, since element type is already encoded in "type" param - if (it->isMap() && it->beginMap() != it->endMap()) - { - *it = it->beginMap()->second; - } - } - - LL_DEBUGS("Notifications") << name << LL_ENDL; - LL_DEBUGS("Notifications") << ll_pretty_print_sd(mFormData) << LL_ENDL; + mFormData = other.mFormData; + mIgnore = other.mIgnore; + mIgnoreMsg = other.mIgnoreMsg; + mIgnoreSetting = other.mIgnoreSetting; + mInvertSetting = other.mInvertSetting; +} + +LLNotificationForm::LLNotificationForm(const std::string& name, const LLNotificationForm::Params& p) +: mIgnore(IGNORE_NO), + mInvertSetting(false) // ignore settings by default mean true=show, false=ignore +{ + if (p.ignore.isProvided()) + { + // For all cases but IGNORE_CHECKBOX_ONLY this is name for use in preferences + mIgnoreMsg = p.ignore.text; + + LLUI *ui_inst = LLUI::getInstance(); + if (p.ignore.checkbox_only) + { + mIgnore = IGNORE_CHECKBOX_ONLY; + } + else if (!p.ignore.save_option) + { + mIgnore = p.ignore.session_only ? IGNORE_WITH_DEFAULT_RESPONSE_SESSION_ONLY : IGNORE_WITH_DEFAULT_RESPONSE; + } + else + { + // remember last option chosen by user and automatically respond with that in the future + mIgnore = IGNORE_WITH_LAST_RESPONSE; + ui_inst->mSettingGroups["ignores"]->declareLLSD(std::string("Default") + name, "", std::string("Default response for notification " + name)); + } + + BOOL show_notification = TRUE; + if (p.ignore.control.isProvided()) + { + mIgnoreSetting = ui_inst->mSettingGroups["config"]->getControl(p.ignore.control); + mInvertSetting = p.ignore.invert_control; + } + else if (mIgnore > IGNORE_NO) + { + ui_inst->mSettingGroups["ignores"]->declareBOOL(name, show_notification, "Show notification with this name", LLControlVariable::PERSIST_NONDFT); + mIgnoreSetting = ui_inst->mSettingGroups["ignores"]->getControl(name); + } + } + + LLParamSDParser parser; + parser.writeSD(mFormData, p.form_elements); + + for (LLSD::array_iterator it = mFormData.beginArray(), end_it = mFormData.endArray(); + it != end_it; + ++it) + { + // lift contents of form element up a level, since element type is already encoded in "type" param + if (it->isMap() && it->beginMap() != it->endMap()) + { + *it = it->beginMap()->second; + } + } + + LL_DEBUGS("Notifications") << name << LL_ENDL; + LL_DEBUGS("Notifications") << ll_pretty_print_sd(mFormData) << LL_ENDL; } LLNotificationForm::LLNotificationForm(const LLSD& sd) - : mIgnore(IGNORE_NO) + : mIgnore(IGNORE_NO) { - if (sd.isArray()) - { - mFormData = sd; - } - else - { - LL_WARNS("Notifications") << "Invalid form data " << sd << LL_ENDL; - mFormData = LLSD::emptyArray(); - } + if (sd.isArray()) + { + mFormData = sd; + } + else + { + LL_WARNS("Notifications") << "Invalid form data " << sd << LL_ENDL; + mFormData = LLSD::emptyArray(); + } } LLSD LLNotificationForm::asLLSD() const -{ - return mFormData; +{ + return mFormData; } LLSD LLNotificationForm::getElement(const std::string& element_name) { - for (LLSD::array_const_iterator it = mFormData.beginArray(); - it != mFormData.endArray(); - ++it) - { - if ((*it)["name"].asString() == element_name) return (*it); - } - return LLSD(); + for (LLSD::array_const_iterator it = mFormData.beginArray(); + it != mFormData.endArray(); + ++it) + { + if ((*it)["name"].asString() == element_name) return (*it); + } + return LLSD(); } bool LLNotificationForm::hasElement(const std::string& element_name) const { - for (LLSD::array_const_iterator it = mFormData.beginArray(); - it != mFormData.endArray(); - ++it) - { - if ((*it)["name"].asString() == element_name) return true; - } - return false; + for (LLSD::array_const_iterator it = mFormData.beginArray(); + it != mFormData.endArray(); + ++it) + { + if ((*it)["name"].asString() == element_name) return true; + } + return false; } void LLNotificationForm::getElements(LLSD& elements, S32 offset) @@ -303,241 +303,241 @@ void LLNotificationForm::getElements(LLSD& elements, S32 offset) bool LLNotificationForm::getElementEnabled(const std::string& element_name) const { - for (LLSD::array_const_iterator it = mFormData.beginArray(); - it != mFormData.endArray(); - ++it) - { - if ((*it)["name"].asString() == element_name) - { - return (*it)["enabled"].asBoolean(); - } - } + for (LLSD::array_const_iterator it = mFormData.beginArray(); + it != mFormData.endArray(); + ++it) + { + if ((*it)["name"].asString() == element_name) + { + return (*it)["enabled"].asBoolean(); + } + } - return false; + return false; } void LLNotificationForm::setElementEnabled(const std::string& element_name, bool enabled) { - for (LLSD::array_iterator it = mFormData.beginArray(); - it != mFormData.endArray(); - ++it) - { - if ((*it)["name"].asString() == element_name) - { - (*it)["enabled"] = enabled; - } - } + for (LLSD::array_iterator it = mFormData.beginArray(); + it != mFormData.endArray(); + ++it) + { + if ((*it)["name"].asString() == element_name) + { + (*it)["enabled"] = enabled; + } + } } void LLNotificationForm::addElement(const std::string& type, const std::string& name, const LLSD& value, bool enabled) { - LLSD element; - element["type"] = type; - element["name"] = name; - element["text"] = name; - element["value"] = value; - element["index"] = LLSD::Integer(mFormData.size()); - element["enabled"] = enabled; - mFormData.append(element); + LLSD element; + element["type"] = type; + element["name"] = name; + element["text"] = name; + element["value"] = value; + element["index"] = LLSD::Integer(mFormData.size()); + element["enabled"] = enabled; + mFormData.append(element); } void LLNotificationForm::append(const LLSD& sub_form) { - if (sub_form.isArray()) - { - for (LLSD::array_const_iterator it = sub_form.beginArray(); - it != sub_form.endArray(); - ++it) - { - mFormData.append(*it); - } - } + if (sub_form.isArray()) + { + for (LLSD::array_const_iterator it = sub_form.beginArray(); + it != sub_form.endArray(); + ++it) + { + mFormData.append(*it); + } + } } void LLNotificationForm::formatElements(const LLSD& substitutions) { - for (LLSD::array_iterator it = mFormData.beginArray(); - it != mFormData.endArray(); - ++it) - { - // format "text" component of each form element - if ((*it).has("text")) - { - std::string text = (*it)["text"].asString(); - LLStringUtil::format(text, substitutions); - (*it)["text"] = text; - } - if ((*it)["type"].asString() == "text" && (*it).has("value")) - { - std::string value = (*it)["value"].asString(); - LLStringUtil::format(value, substitutions); - (*it)["value"] = value; - } - } + for (LLSD::array_iterator it = mFormData.beginArray(); + it != mFormData.endArray(); + ++it) + { + // format "text" component of each form element + if ((*it).has("text")) + { + std::string text = (*it)["text"].asString(); + LLStringUtil::format(text, substitutions); + (*it)["text"] = text; + } + if ((*it)["type"].asString() == "text" && (*it).has("value")) + { + std::string value = (*it)["value"].asString(); + LLStringUtil::format(value, substitutions); + (*it)["value"] = value; + } + } } std::string LLNotificationForm::getDefaultOption() { - for (LLSD::array_const_iterator it = mFormData.beginArray(); - it != mFormData.endArray(); - ++it) - { - if ((*it)["default"]) return (*it)["name"].asString(); - } - return ""; + for (LLSD::array_const_iterator it = mFormData.beginArray(); + it != mFormData.endArray(); + ++it) + { + if ((*it)["default"]) return (*it)["name"].asString(); + } + return ""; } -LLControlVariablePtr LLNotificationForm::getIgnoreSetting() -{ - return mIgnoreSetting; +LLControlVariablePtr LLNotificationForm::getIgnoreSetting() +{ + return mIgnoreSetting; } bool LLNotificationForm::getIgnored() { - bool show = true; - if (mIgnore > LLNotificationForm::IGNORE_NO - && mIgnoreSetting) - { - show = mIgnoreSetting->getValue().asBoolean(); - if (mInvertSetting) show = !show; - } - return !show; + bool show = true; + if (mIgnore > LLNotificationForm::IGNORE_NO + && mIgnoreSetting) + { + show = mIgnoreSetting->getValue().asBoolean(); + if (mInvertSetting) show = !show; + } + return !show; } void LLNotificationForm::setIgnored(bool ignored) { - if (mIgnoreSetting) - { - if (mInvertSetting) ignored = !ignored; - mIgnoreSetting->setValue(!ignored); - } + if (mIgnoreSetting) + { + if (mInvertSetting) ignored = !ignored; + mIgnoreSetting->setValue(!ignored); + } } LLNotificationTemplate::LLNotificationTemplate(const LLNotificationTemplate::Params& p) -: mName(p.name), - mType(p.type), - mMessage(p.value), - mFooter(p.footer.value), - mLabel(p.label), - mIcon(p.icon), - mURL(p.url.value), - mExpireSeconds(p.duration), - mExpireOption(p.expire_option), - mURLOption(p.url.option), - mURLTarget(p.url.target), - mForceUrlsExternal(p.force_urls_external), - mUnique(p.unique.isProvided()), - mCombineBehavior(p.unique.combine), - mPriority(p.priority), - mPersist(p.persist), - mDefaultFunctor(p.functor.isProvided() ? p.functor() : p.name()), - mLogToChat(p.log_to_chat), - mLogToIM(p.log_to_im), - mShowToast(p.show_toast), - mFadeToast(p.fade_toast), +: mName(p.name), + mType(p.type), + mMessage(p.value), + mFooter(p.footer.value), + mLabel(p.label), + mIcon(p.icon), + mURL(p.url.value), + mExpireSeconds(p.duration), + mExpireOption(p.expire_option), + mURLOption(p.url.option), + mURLTarget(p.url.target), + mForceUrlsExternal(p.force_urls_external), + mUnique(p.unique.isProvided()), + mCombineBehavior(p.unique.combine), + mPriority(p.priority), + mPersist(p.persist), + mDefaultFunctor(p.functor.isProvided() ? p.functor() : p.name()), + mLogToChat(p.log_to_chat), + mLogToIM(p.log_to_im), + mShowToast(p.show_toast), + mFadeToast(p.fade_toast), mSoundName("") { - if (p.sound.isProvided() - && LLUI::getInstance()->mSettingGroups["config"]->controlExists(p.sound)) - { - mSoundName = p.sound; - } + if (p.sound.isProvided() + && LLUI::getInstance()->mSettingGroups["config"]->controlExists(p.sound)) + { + mSoundName = p.sound; + } + + for (const LLNotificationTemplate::UniquenessContext& context : p.unique.contexts) + { + mUniqueContext.push_back(context.value); + } - BOOST_FOREACH(const LLNotificationTemplate::UniquenessContext& context, p.unique.contexts) - { - mUniqueContext.push_back(context.value); - } - - LL_DEBUGS("Notifications") << "notification \"" << mName << "\": tag count is " << p.tags.size() << LL_ENDL; - - BOOST_FOREACH(const LLNotificationTemplate::Tag& tag, p.tags) - { - LL_DEBUGS("Notifications") << " tag \"" << std::string(tag.value) << "\"" << LL_ENDL; - mTags.push_back(tag.value); - } + LL_DEBUGS("Notifications") << "notification \"" << mName << "\": tag count is " << p.tags.size() << LL_ENDL; - mForm = LLNotificationFormPtr(new LLNotificationForm(p.name, p.form_ref.form)); + for (const LLNotificationTemplate::Tag& tag : p.tags) + { + LL_DEBUGS("Notifications") << " tag \"" << std::string(tag.value) << "\"" << LL_ENDL; + mTags.push_back(tag.value); + } + + mForm = LLNotificationFormPtr(new LLNotificationForm(p.name, p.form_ref.form)); } LLNotificationVisibilityRule::LLNotificationVisibilityRule(const LLNotificationVisibilityRule::Rule &p) { - if (p.show.isChosen()) - { - mType = p.show.type; - mTag = p.show.tag; - mName = p.show.name; - mVisible = true; - } - else if (p.hide.isChosen()) - { - mType = p.hide.type; - mTag = p.hide.tag; - mName = p.hide.name; - mVisible = false; - } - else if (p.respond.isChosen()) - { - mType = p.respond.type; - mTag = p.respond.tag; - mName = p.respond.name; - mVisible = false; - mResponse = p.respond.response; - } -} - -LLNotification::LLNotification(const LLSDParamAdapter<Params>& p) : - mTimestamp(p.time_stamp), - mSubstitutions(p.substitutions), - mPayload(p.payload), - mExpiresAt(p.expiry), - mTemporaryResponder(false), - mRespondedTo(false), - mPriority(p.priority), - mCancelled(false), - mIgnored(false), - mResponderObj(NULL), - mId(p.id.isProvided() ? p.id : LLUUID::generateNewID()), - mOfferFromAgent(p.offer_from_agent), + if (p.show.isChosen()) + { + mType = p.show.type; + mTag = p.show.tag; + mName = p.show.name; + mVisible = true; + } + else if (p.hide.isChosen()) + { + mType = p.hide.type; + mTag = p.hide.tag; + mName = p.hide.name; + mVisible = false; + } + else if (p.respond.isChosen()) + { + mType = p.respond.type; + mTag = p.respond.tag; + mName = p.respond.name; + mVisible = false; + mResponse = p.respond.response; + } +} + +LLNotification::LLNotification(const LLSDParamAdapter<Params>& p) : + mTimestamp(p.time_stamp), + mSubstitutions(p.substitutions), + mPayload(p.payload), + mExpiresAt(p.expiry), + mTemporaryResponder(false), + mRespondedTo(false), + mPriority(p.priority), + mCancelled(false), + mIgnored(false), + mResponderObj(NULL), + mId(p.id.isProvided() ? p.id : LLUUID::generateNewID()), + mOfferFromAgent(p.offer_from_agent), mIsDND(p.is_dnd) { - if (p.functor.name.isChosen()) - { - mResponseFunctorName = p.functor.name; - } - else if (p.functor.function.isChosen()) - { - mResponseFunctorName = LLUUID::generateNewID().asString(); - LLNotificationFunctorRegistry::instance().registerFunctor(mResponseFunctorName, p.functor.function()); + if (p.functor.name.isChosen()) + { + mResponseFunctorName = p.functor.name; + } + else if (p.functor.function.isChosen()) + { + mResponseFunctorName = LLUUID::generateNewID().asString(); + LLNotificationFunctorRegistry::instance().registerFunctor(mResponseFunctorName, p.functor.function()); - mTemporaryResponder = true; - } - else if(p.functor.responder.isChosen()) - { - mResponder = p.functor.responder; - } + mTemporaryResponder = true; + } + else if(p.functor.responder.isChosen()) + { + mResponder = p.functor.responder; + } - if(p.responder.isProvided()) - { - mResponderObj = p.responder; - } + if(p.responder.isProvided()) + { + mResponderObj = p.responder; + } - init(p.name, p.form_elements); + init(p.name, p.form_elements); } LLSD LLNotification::asLLSD(bool excludeTemplateElements) -{ - LLParamSDParser parser; - - Params p; - p.id = mId; - p.name = mTemplatep->mName; - p.substitutions = mSubstitutions; - p.payload = mPayload; - p.time_stamp = mTimestamp; - p.expiry = mExpiresAt; - p.priority = mPriority; +{ + LLParamSDParser parser; + + Params p; + p.id = mId; + p.name = mTemplatep->mName; + p.substitutions = mSubstitutions; + p.payload = mPayload; + p.time_stamp = mTimestamp; + p.expiry = mExpiresAt; + p.priority = mPriority; LLNotificationFormPtr templateForm = mTemplatep->mForm; LLSD formElements = mForm->asLLSD(); @@ -561,202 +561,202 @@ LLSD LLNotification::asLLSD(bool excludeTemplateElements) p.functor.responder_sd = mResponder->asLLSD(); } - if(!mResponseFunctorName.empty()) - { - p.functor.name = mResponseFunctorName; - } + if(!mResponseFunctorName.empty()) + { + p.functor.name = mResponseFunctorName; + } - LLSD output; - parser.writeSD(output, p); - return output; + LLSD output; + parser.writeSD(output, p); + return output; } void LLNotification::update() { - LLNotifications::instance().update(shared_from_this()); + LLNotifications::instance().update(shared_from_this()); } void LLNotification::updateFrom(LLNotificationPtr other) { - // can only update from the same notification type - if (mTemplatep != other->mTemplatep) return; + // can only update from the same notification type + if (mTemplatep != other->mTemplatep) return; - // NOTE: do NOT change the ID, since it is the key to - // this given instance, just update all the metadata - //mId = other->mId; + // NOTE: do NOT change the ID, since it is the key to + // this given instance, just update all the metadata + //mId = other->mId; - mPayload = other->mPayload; - mSubstitutions = other->mSubstitutions; - mTimestamp = other->mTimestamp; - mExpiresAt = other->mExpiresAt; - mCancelled = other->mCancelled; - mIgnored = other->mIgnored; - mPriority = other->mPriority; - mForm = other->mForm; - mResponseFunctorName = other->mResponseFunctorName; - mRespondedTo = other->mRespondedTo; - mResponse = other->mResponse; - mTemporaryResponder = other->mTemporaryResponder; + mPayload = other->mPayload; + mSubstitutions = other->mSubstitutions; + mTimestamp = other->mTimestamp; + mExpiresAt = other->mExpiresAt; + mCancelled = other->mCancelled; + mIgnored = other->mIgnored; + mPriority = other->mPriority; + mForm = other->mForm; + mResponseFunctorName = other->mResponseFunctorName; + mRespondedTo = other->mRespondedTo; + mResponse = other->mResponse; + mTemporaryResponder = other->mTemporaryResponder; - update(); + update(); } const LLNotificationFormPtr LLNotification::getForm() { - return mForm; + return mForm; } void LLNotification::cancel() { - mCancelled = true; + mCancelled = true; } LLSD LLNotification::getResponseTemplate(EResponseTemplateType type) { - LLSD response = LLSD::emptyMap(); - for (S32 element_idx = 0; - element_idx < mForm->getNumElements(); - ++element_idx) - { - LLSD element = mForm->getElement(element_idx); - if (element.has("name")) - { - response[element["name"].asString()] = element["value"]; - } - - if ((type == WITH_DEFAULT_BUTTON) - && element["default"].asBoolean()) - { - response[element["name"].asString()] = true; - } - } - return response; + LLSD response = LLSD::emptyMap(); + for (S32 element_idx = 0; + element_idx < mForm->getNumElements(); + ++element_idx) + { + LLSD element = mForm->getElement(element_idx); + if (element.has("name")) + { + response[element["name"].asString()] = element["value"]; + } + + if ((type == WITH_DEFAULT_BUTTON) + && element["default"].asBoolean()) + { + response[element["name"].asString()] = true; + } + } + return response; } //static S32 LLNotification::getSelectedOption(const LLSD& notification, const LLSD& response) { - LLNotificationForm form(notification["form"]); + LLNotificationForm form(notification["form"]); - for (S32 element_idx = 0; - element_idx < form.getNumElements(); - ++element_idx) - { - LLSD element = form.getElement(element_idx); - - // only look at buttons - if (element["type"].asString() == "button" - && response[element["name"].asString()].asBoolean()) - { - return element["index"].asInteger(); - } - } + for (S32 element_idx = 0; + element_idx < form.getNumElements(); + ++element_idx) + { + LLSD element = form.getElement(element_idx); + + // only look at buttons + if (element["type"].asString() == "button" + && response[element["name"].asString()].asBoolean()) + { + return element["index"].asInteger(); + } + } - return -1; + return -1; } //static std::string LLNotification::getSelectedOptionName(const LLSD& response) { - for (LLSD::map_const_iterator response_it = response.beginMap(); - response_it != response.endMap(); - ++response_it) - { - if (response_it->second.isBoolean() && response_it->second.asBoolean()) - { - return response_it->first; - } - } - return ""; + for (LLSD::map_const_iterator response_it = response.beginMap(); + response_it != response.endMap(); + ++response_it) + { + if (response_it->second.isBoolean() && response_it->second.asBoolean()) + { + return response_it->first; + } + } + return ""; } void LLNotification::respond(const LLSD& response) { - // *TODO may remove mRespondedTo and use mResponce.isDefined() in isRespondedTo() - mRespondedTo = true; - mResponse = response; - - if(mResponder) - { - mResponder->handleRespond(asLLSD(), response); - } - else if (!mResponseFunctorName.empty()) - { - // look up the functor - LLNotificationFunctorRegistry::ResponseFunctor functor = - LLNotificationFunctorRegistry::instance().getFunctor(mResponseFunctorName); - // and then call it - functor(asLLSD(), response); - } - else if (mCombinedNotifications.empty()) - { - // no registered responder - return; - } - - if (mTemporaryResponder) - { - LLNotificationFunctorRegistry::instance().unregisterFunctor(mResponseFunctorName); - mResponseFunctorName = ""; - mTemporaryResponder = false; - } - - if (mForm->getIgnoreType() > LLNotificationForm::IGNORE_NO) - { - mForm->setIgnored(mIgnored); - if (mIgnored && mForm->getIgnoreType() == LLNotificationForm::IGNORE_WITH_LAST_RESPONSE) - { - LLUI::getInstance()->mSettingGroups["ignores"]->setLLSD("Default" + getName(), response); - } - } - - for (std::vector<LLNotificationPtr>::const_iterator it = mCombinedNotifications.begin(); it != mCombinedNotifications.end(); ++it) - { - if ((*it)) - { - (*it)->respond(response); - } - } - - update(); + // *TODO may remove mRespondedTo and use mResponce.isDefined() in isRespondedTo() + mRespondedTo = true; + mResponse = response; + + if(mResponder) + { + mResponder->handleRespond(asLLSD(), response); + } + else if (!mResponseFunctorName.empty()) + { + // look up the functor + LLNotificationFunctorRegistry::ResponseFunctor functor = + LLNotificationFunctorRegistry::instance().getFunctor(mResponseFunctorName); + // and then call it + functor(asLLSD(), response); + } + else if (mCombinedNotifications.empty()) + { + // no registered responder + return; + } + + if (mTemporaryResponder) + { + LLNotificationFunctorRegistry::instance().unregisterFunctor(mResponseFunctorName); + mResponseFunctorName = ""; + mTemporaryResponder = false; + } + + if (mForm->getIgnoreType() > LLNotificationForm::IGNORE_NO) + { + mForm->setIgnored(mIgnored); + if (mIgnored && mForm->getIgnoreType() == LLNotificationForm::IGNORE_WITH_LAST_RESPONSE) + { + LLUI::getInstance()->mSettingGroups["ignores"]->setLLSD("Default" + getName(), response); + } + } + + for (std::vector<LLNotificationPtr>::const_iterator it = mCombinedNotifications.begin(); it != mCombinedNotifications.end(); ++it) + { + if ((*it)) + { + (*it)->respond(response); + } + } + + update(); } void LLNotification::respondWithDefault() { - respond(getResponseTemplate(WITH_DEFAULT_BUTTON)); + respond(getResponseTemplate(WITH_DEFAULT_BUTTON)); } const std::string& LLNotification::getName() const { - return mTemplatep->mName; + return mTemplatep->mName; } const std::string& LLNotification::getIcon() const { - return mTemplatep->mIcon; + return mTemplatep->mIcon; } bool LLNotification::isPersistent() const { - return mTemplatep->mPersist; + return mTemplatep->mPersist; } std::string LLNotification::getType() const { - return (mTemplatep ? mTemplatep->mType : ""); + return (mTemplatep ? mTemplatep->mType : ""); } S32 LLNotification::getURLOption() const { - return (mTemplatep ? mTemplatep->mURLOption : -1); + return (mTemplatep ? mTemplatep->mURLOption : -1); } S32 LLNotification::getURLOpenExternally() const { - return(mTemplatep? mTemplatep->mURLTarget == "_external": -1); + return(mTemplatep? mTemplatep->mURLTarget == "_external": -1); } bool LLNotification::getForceUrlsExternal() const @@ -764,223 +764,223 @@ bool LLNotification::getForceUrlsExternal() const return (mTemplatep ? mTemplatep->mForceUrlsExternal : false); } -bool LLNotification::hasUniquenessConstraints() const -{ - return (mTemplatep ? mTemplatep->mUnique : false); +bool LLNotification::hasUniquenessConstraints() const +{ + return (mTemplatep ? mTemplatep->mUnique : false); } bool LLNotification::matchesTag(const std::string& tag) { - bool result = false; - - if(mTemplatep) - { - std::list<std::string>::iterator it; - for(it = mTemplatep->mTags.begin(); it != mTemplatep->mTags.end(); it++) - { - if((*it) == tag) - { - result = true; - break; - } - } - } - - return result; + bool result = false; + + if(mTemplatep) + { + std::list<std::string>::iterator it; + for(it = mTemplatep->mTags.begin(); it != mTemplatep->mTags.end(); it++) + { + if((*it) == tag) + { + result = true; + break; + } + } + } + + return result; } void LLNotification::setIgnored(bool ignore) { - mIgnored = ignore; + mIgnored = ignore; } void LLNotification::setResponseFunctor(std::string const &responseFunctorName) { - if (mTemporaryResponder) - // get rid of the old one - LLNotificationFunctorRegistry::instance().unregisterFunctor(mResponseFunctorName); - mResponseFunctorName = responseFunctorName; - mTemporaryResponder = false; + if (mTemporaryResponder) + // get rid of the old one + LLNotificationFunctorRegistry::instance().unregisterFunctor(mResponseFunctorName); + mResponseFunctorName = responseFunctorName; + mTemporaryResponder = false; } void LLNotification::setResponseFunctor(const LLNotificationFunctorRegistry::ResponseFunctor& cb) { - if(mTemporaryResponder) - { - LLNotificationFunctorRegistry::instance().unregisterFunctor(mResponseFunctorName); - } + if(mTemporaryResponder) + { + LLNotificationFunctorRegistry::instance().unregisterFunctor(mResponseFunctorName); + } - LLNotificationFunctorRegistry::instance().registerFunctor(mResponseFunctorName, cb); + LLNotificationFunctorRegistry::instance().registerFunctor(mResponseFunctorName, cb); } void LLNotification::setResponseFunctor(const LLNotificationResponderPtr& responder) { - mResponder = responder; + mResponder = responder; } bool LLNotification::isEquivalentTo(LLNotificationPtr that) const { - if (this->mTemplatep->mName != that->mTemplatep->mName) - { - return false; // must have the same template name or forget it - } - if (this->mTemplatep->mUnique) - { - const LLSD& these_substitutions = this->getSubstitutions(); - const LLSD& those_substitutions = that->getSubstitutions(); - const LLSD& this_payload = this->getPayload(); - const LLSD& that_payload = that->getPayload(); - - // highlander bit sez there can only be one of these - for (std::vector<std::string>::const_iterator it = mTemplatep->mUniqueContext.begin(), end_it = mTemplatep->mUniqueContext.end(); - it != end_it; - ++it) - { - // if templates differ in either substitution strings or payload with the given field name - // then they are considered inequivalent - // use of get() avoids converting the LLSD value to a map as the [] operator would - if (these_substitutions.get(*it).asString() != those_substitutions.get(*it).asString() - || this_payload.get(*it).asString() != that_payload.get(*it).asString()) - { - return false; - } - } - return true; - } - - return false; + if (this->mTemplatep->mName != that->mTemplatep->mName) + { + return false; // must have the same template name or forget it + } + if (this->mTemplatep->mUnique) + { + const LLSD& these_substitutions = this->getSubstitutions(); + const LLSD& those_substitutions = that->getSubstitutions(); + const LLSD& this_payload = this->getPayload(); + const LLSD& that_payload = that->getPayload(); + + // highlander bit sez there can only be one of these + for (std::vector<std::string>::const_iterator it = mTemplatep->mUniqueContext.begin(), end_it = mTemplatep->mUniqueContext.end(); + it != end_it; + ++it) + { + // if templates differ in either substitution strings or payload with the given field name + // then they are considered inequivalent + // use of get() avoids converting the LLSD value to a map as the [] operator would + if (these_substitutions.get(*it).asString() != those_substitutions.get(*it).asString() + || this_payload.get(*it).asString() != that_payload.get(*it).asString()) + { + return false; + } + } + return true; + } + + return false; } void LLNotification::init(const std::string& template_name, const LLSD& form_elements) { - mTemplatep = LLNotifications::instance().getTemplate(template_name); - if (!mTemplatep) return; - - // add default substitutions - const LLStringUtil::format_map_t& default_args = LLTrans::getDefaultArgs(); - for (LLStringUtil::format_map_t::const_iterator iter = default_args.begin(); - iter != default_args.end(); ++iter) - { - mSubstitutions[iter->first] = iter->second; - } - mSubstitutions["_URL"] = getURL(); - mSubstitutions["_NAME"] = template_name; - // TODO: something like this so that a missing alert is sensible: - //mSubstitutions["_ARGS"] = get_all_arguments_as_text(mSubstitutions); - - mForm = LLNotificationFormPtr(new LLNotificationForm(*mTemplatep->mForm)); + mTemplatep = LLNotifications::instance().getTemplate(template_name); + if (!mTemplatep) return; + + // add default substitutions + const LLStringUtil::format_map_t& default_args = LLTrans::getDefaultArgs(); + for (LLStringUtil::format_map_t::const_iterator iter = default_args.begin(); + iter != default_args.end(); ++iter) + { + mSubstitutions[iter->first] = iter->second; + } + mSubstitutions["_URL"] = getURL(); + mSubstitutions["_NAME"] = template_name; + // TODO: something like this so that a missing alert is sensible: + //mSubstitutions["_ARGS"] = get_all_arguments_as_text(mSubstitutions); + + mForm = LLNotificationFormPtr(new LLNotificationForm(*mTemplatep->mForm)); mForm->append(form_elements); - // apply substitution to form labels - mForm->formatElements(mSubstitutions); + // apply substitution to form labels + mForm->formatElements(mSubstitutions); - mIgnored = mForm->getIgnored(); + mIgnored = mForm->getIgnored(); - LLDate rightnow = LLDate::now(); - if (mTemplatep->mExpireSeconds) - { - mExpiresAt = LLDate(rightnow.secondsSinceEpoch() + mTemplatep->mExpireSeconds); - } + LLDate rightnow = LLDate::now(); + if (mTemplatep->mExpireSeconds) + { + mExpiresAt = LLDate(rightnow.secondsSinceEpoch() + mTemplatep->mExpireSeconds); + } - if (mPriority == NOTIFICATION_PRIORITY_UNSPECIFIED) - { - mPriority = mTemplatep->mPriority; - } + if (mPriority == NOTIFICATION_PRIORITY_UNSPECIFIED) + { + mPriority = mTemplatep->mPriority; + } } std::string LLNotification::summarize() const { - std::string s = "Notification("; - s += getName(); - s += ") : "; - s += mTemplatep ? mTemplatep->mMessage : ""; - // should also include timestamp and expiration time (but probably not payload) - return s; + std::string s = "Notification("; + s += getName(); + s += ") : "; + s += mTemplatep ? mTemplatep->mMessage : ""; + // should also include timestamp and expiration time (but probably not payload) + return s; } std::string LLNotification::getMessage() const { - // all our callers cache this result, so it gives us more flexibility - // to do the substitution at call time rather than attempting to - // cache it in the notification - if (!mTemplatep) - return std::string(); + // all our callers cache this result, so it gives us more flexibility + // to do the substitution at call time rather than attempting to + // cache it in the notification + if (!mTemplatep) + return std::string(); - std::string message = mTemplatep->mMessage; - LLStringUtil::format(message, mSubstitutions); - return message; + std::string message = mTemplatep->mMessage; + LLStringUtil::format(message, mSubstitutions); + return message; } std::string LLNotification::getFooter() const { - if (!mTemplatep) - return std::string(); + if (!mTemplatep) + return std::string(); - std::string footer = mTemplatep->mFooter; - LLStringUtil::format(footer, mSubstitutions); - return footer; + std::string footer = mTemplatep->mFooter; + LLStringUtil::format(footer, mSubstitutions); + return footer; } std::string LLNotification::getLabel() const { - std::string label = mTemplatep->mLabel; - LLStringUtil::format(label, mSubstitutions); - return (mTemplatep ? label : ""); + std::string label = mTemplatep->mLabel; + LLStringUtil::format(label, mSubstitutions); + return (mTemplatep ? label : ""); } std::string LLNotification::getURL() const { - if (!mTemplatep) - return std::string(); - std::string url = mTemplatep->mURL; - LLStringUtil::format(url, mSubstitutions); - return (mTemplatep ? url : ""); + if (!mTemplatep) + return std::string(); + std::string url = mTemplatep->mURL; + LLStringUtil::format(url, mSubstitutions); + return (mTemplatep ? url : ""); } bool LLNotification::canLogToChat() const { - return mTemplatep->mLogToChat; + return mTemplatep->mLogToChat; } bool LLNotification::canLogToIM() const { - return mTemplatep->mLogToIM; + return mTemplatep->mLogToIM; } bool LLNotification::canShowToast() const { - return mTemplatep->mShowToast; + return mTemplatep->mShowToast; } bool LLNotification::canFadeToast() const { - return mTemplatep->mFadeToast; + return mTemplatep->mFadeToast; } bool LLNotification::hasFormElements() const { - return mTemplatep->mForm->getNumElements() != 0; + return mTemplatep->mForm->getNumElements() != 0; } void LLNotification::playSound() -{ +{ make_ui_sound(mTemplatep->mSoundName.c_str()); } LLNotification::ECombineBehavior LLNotification::getCombineBehavior() const { - return mTemplatep->mCombineBehavior; + return mTemplatep->mCombineBehavior; } void LLNotification::updateForm( const LLNotificationFormPtr& form ) { - mForm = form; + mForm = form; } void LLNotification::repost() { - mRespondedTo = false; - LLNotifications::instance().update(shared_from_this()); + mRespondedTo = false; + LLNotifications::instance().update(shared_from_this()); } @@ -990,49 +990,50 @@ void LLNotification::repost() // --- LLBoundListener LLNotificationChannelBase::connectChangedImpl(const LLEventListener& slot) { - // when someone wants to connect to a channel, we first throw them - // all of the notifications that are already in the channel - // we use a special signal called "load" in case the channel wants to care - // only about new notifications - for (LLNotificationSet::iterator it = mItems.begin(); it != mItems.end(); ++it) - { - slot(LLSD().with("sigtype", "load").with("id", (*it)->id())); - } - // and then connect the signal so that all future notifications will also be - // forwarded. - return mChanged.connect(slot); + // when someone wants to connect to a channel, we first throw them + // all of the notifications that are already in the channel + // we use a special signal called "load" in case the channel wants to care + // only about new notifications + LLMutexLock lock(&mItemsMutex); + for (LLNotificationSet::iterator it = mItems.begin(); it != mItems.end(); ++it) + { + slot(LLSD().with("sigtype", "load").with("id", (*it)->id())); + } + // and then connect the signal so that all future notifications will also be + // forwarded. + return mChanged.connect(slot); } LLBoundListener LLNotificationChannelBase::connectAtFrontChangedImpl(const LLEventListener& slot) { - for (LLNotificationSet::iterator it = mItems.begin(); it != mItems.end(); ++it) - { - slot(LLSD().with("sigtype", "load").with("id", (*it)->id())); - } - return mChanged.connect(slot, boost::signals2::at_front); + for (LLNotificationSet::iterator it = mItems.begin(); it != mItems.end(); ++it) + { + slot(LLSD().with("sigtype", "load").with("id", (*it)->id())); + } + return mChanged.connect(slot, boost::signals2::at_front); } LLBoundListener LLNotificationChannelBase::connectPassedFilterImpl(const LLEventListener& slot) { - // these two filters only fire for notifications added after the current one, because - // they don't participate in the hierarchy. - return mPassedFilter.connect(slot); + // these two filters only fire for notifications added after the current one, because + // they don't participate in the hierarchy. + return mPassedFilter.connect(slot); } LLBoundListener LLNotificationChannelBase::connectFailedFilterImpl(const LLEventListener& slot) { - return mFailedFilter.connect(slot); + return mFailedFilter.connect(slot); } // external call, conforms to our standard signature bool LLNotificationChannelBase::updateItem(const LLSD& payload) -{ - // first check to see if it's in the master list - LLNotificationPtr pNotification = LLNotifications::instance().find(payload["id"]); - if (!pNotification) - return false; // not found - - return updateItem(payload, pNotification); +{ + // first check to see if it's in the master list + LLNotificationPtr pNotification = LLNotifications::instance().find(payload["id"]); + if (!pNotification) + return false; // not found + + return updateItem(payload, pNotification); } @@ -1041,187 +1042,192 @@ bool LLNotificationChannelBase::updateItem(const LLSD& payload) // internal call, for use in avoiding lookup bool LLNotificationChannelBase::updateItem(const LLSD& payload, LLNotificationPtr pNotification) -{ - std::string cmd = payload["sigtype"]; - LLNotificationSet::iterator foundItem = mItems.find(pNotification); - bool wasFound = (foundItem != mItems.end()); - bool passesFilter = mFilter ? mFilter(pNotification) : true; - - // first, we offer the result of the filter test to the simple - // signals for pass/fail. One of these is guaranteed to be called. - // If either signal returns true, the change processing is NOT performed - // (so don't return true unless you know what you're doing!) - bool abortProcessing = false; - if (passesFilter) - { - onFilterPass(pNotification); - abortProcessing = mPassedFilter(payload); - } - else - { - onFilterFail(pNotification); - abortProcessing = mFailedFilter(payload); - } - - if (abortProcessing) - { - return true; - } - - if (cmd == "load") - { - // should be no reason we'd ever get a load if we already have it - // if passes filter send a load message, else do nothing - assert(!wasFound); - if (passesFilter) - { - // not in our list, add it and say so - mItems.insert(pNotification); - onLoad(pNotification); - abortProcessing = mChanged(payload); - } - } - else if (cmd == "change") - { - // if it passes filter now and was found, we just send a change message - // if it passes filter now and wasn't found, we have to add it - // if it doesn't pass filter and wasn't found, we do nothing - // if it doesn't pass filter and was found, we need to delete it - if (passesFilter) - { - if (wasFound) - { - // it already existed, so this is a change - // since it changed in place, all we have to do is resend the signal - onChange(pNotification); - abortProcessing = mChanged(payload); - } - else - { - // not in our list, add it and say so - mItems.insert(pNotification); - onChange(pNotification); - // our payload is const, so make a copy before changing it - LLSD newpayload = payload; - newpayload["sigtype"] = "add"; - abortProcessing = mChanged(newpayload); - } - } - else - { - if (wasFound) - { - // it already existed, so this is a delete - mItems.erase(pNotification); - onChange(pNotification); - // our payload is const, so make a copy before changing it - LLSD newpayload = payload; - newpayload["sigtype"] = "delete"; - abortProcessing = mChanged(newpayload); - } - // didn't pass, not on our list, do nothing - } - } - else if (cmd == "add") - { - // should be no reason we'd ever get an add if we already have it - // if passes filter send an add message, else do nothing - assert(!wasFound); - if (passesFilter) - { - // not in our list, add it and say so - mItems.insert(pNotification); - onAdd(pNotification); - abortProcessing = mChanged(payload); - } - } - else if (cmd == "delete") - { - // if we have it in our list, pass on the delete, then delete it, else do nothing - if (wasFound) - { - onDelete(pNotification); - abortProcessing = mChanged(payload); - mItems.erase(pNotification); - } - } - return abortProcessing; +{ + std::string cmd = payload["sigtype"]; + LLNotificationSet::iterator foundItem = mItems.find(pNotification); + bool wasFound = (foundItem != mItems.end()); + bool passesFilter = mFilter ? mFilter(pNotification) : true; + + // first, we offer the result of the filter test to the simple + // signals for pass/fail. One of these is guaranteed to be called. + // If either signal returns true, the change processing is NOT performed + // (so don't return true unless you know what you're doing!) + bool abortProcessing = false; + if (passesFilter) + { + onFilterPass(pNotification); + abortProcessing = mPassedFilter(payload); + } + else + { + onFilterFail(pNotification); + abortProcessing = mFailedFilter(payload); + } + + if (abortProcessing) + { + return true; + } + + if (cmd == "load") + { + // should be no reason we'd ever get a load if we already have it + // if passes filter send a load message, else do nothing + assert(!wasFound); + if (passesFilter) + { + // not in our list, add it and say so + mItems.insert(pNotification); + onLoad(pNotification); + abortProcessing = mChanged(payload); + } + } + else if (cmd == "change") + { + // if it passes filter now and was found, we just send a change message + // if it passes filter now and wasn't found, we have to add it + // if it doesn't pass filter and wasn't found, we do nothing + // if it doesn't pass filter and was found, we need to delete it + if (passesFilter) + { + if (wasFound) + { + // it already existed, so this is a change + // since it changed in place, all we have to do is resend the signal + onChange(pNotification); + abortProcessing = mChanged(payload); + } + else + { + // not in our list, add it and say so + mItems.insert(pNotification); + onChange(pNotification); + // our payload is const, so make a copy before changing it + LLSD newpayload = payload; + newpayload["sigtype"] = "add"; + abortProcessing = mChanged(newpayload); + } + } + else + { + if (wasFound) + { + // it already existed, so this is a delete + mItems.erase(pNotification); + onChange(pNotification); + // our payload is const, so make a copy before changing it + LLSD newpayload = payload; + newpayload["sigtype"] = "delete"; + abortProcessing = mChanged(newpayload); + } + // didn't pass, not on our list, do nothing + } + } + else if (cmd == "add") + { + // should be no reason we'd ever get an add if we already have it + // if passes filter send an add message, else do nothing + assert(!wasFound); + if (passesFilter) + { + // not in our list, add it and say so + mItems.insert(pNotification); + onAdd(pNotification); + abortProcessing = mChanged(payload); + } + } + else if (cmd == "delete") + { + // if we have it in our list, pass on the delete, then delete it, else do nothing + if (wasFound) + { + onDelete(pNotification); + abortProcessing = mChanged(payload); + mItems.erase(pNotification); + } + } + return abortProcessing; } LLNotificationChannel::LLNotificationChannel(const Params& p) -: LLNotificationChannelBase(p.filter()), - LLInstanceTracker<LLNotificationChannel, std::string>(p.name.isProvided() ? p.name : LLUUID::generateNewID().asString()), - mName(p.name.isProvided() ? p.name : LLUUID::generateNewID().asString()) +: LLNotificationChannelBase(p.filter()), + LLInstanceTracker<LLNotificationChannel, std::string>(p.name.isProvided() ? p.name : LLUUID::generateNewID().asString()), + mName(p.name.isProvided() ? p.name : LLUUID::generateNewID().asString()) { - BOOST_FOREACH(const std::string& source, p.sources) + for (const std::string& source : p.sources) { - connectToChannel(source); - } + connectToChannel(source); + } } -LLNotificationChannel::LLNotificationChannel(const std::string& name, - const std::string& parent, - LLNotificationFilter filter) -: LLNotificationChannelBase(filter), - LLInstanceTracker<LLNotificationChannel, std::string>(name), - mName(name) +LLNotificationChannel::LLNotificationChannel(const std::string& name, + const std::string& parent, + LLNotificationFilter filter) +: LLNotificationChannelBase(filter), + LLInstanceTracker<LLNotificationChannel, std::string>(name), + mName(name) { - // bind to notification broadcast - connectToChannel(parent); + // bind to notification broadcast + connectToChannel(parent); } -bool LLNotificationChannel::isEmpty() const +LLNotificationChannel::~LLNotificationChannel() { - return mItems.empty(); + for (LLBoundListener &listener : mListeners) + { + listener.disconnect(); + } } -S32 LLNotificationChannel::size() const +bool LLNotificationChannel::isEmpty() const { - return mItems.size(); + return mItems.empty(); } -LLNotificationChannel::Iterator LLNotificationChannel::begin() +S32 LLNotificationChannel::size() const { - return mItems.begin(); + return mItems.size(); } -LLNotificationChannel::Iterator LLNotificationChannel::end() +size_t LLNotificationChannel::size() { - return mItems.end(); + return mItems.size(); } -size_t LLNotificationChannel::size() +void LLNotificationChannel::forEachNotification(NotificationProcess process) { - return mItems.size(); + LLMutexLock lock(&mItemsMutex); + std::for_each(mItems.begin(), mItems.end(), process); } std::string LLNotificationChannel::summarize() { - std::string s("Channel '"); - s += mName; - s += "'\n "; - for (LLNotificationChannel::Iterator it = begin(); it != end(); ++it) - { - s += (*it)->summarize(); - s += "\n "; - } - return s; + std::string s("Channel '"); + s += mName; + s += "'\n "; + LLMutexLock lock(&mItemsMutex); + for (LLNotificationChannel::Iterator it = mItems.begin(); it != mItems.end(); ++it) + { + s += (*it)->summarize(); + s += "\n "; + } + return s; } void LLNotificationChannel::connectToChannel( const std::string& channel_name ) { - if (channel_name.empty()) - { - LLNotifications::instance().connectChanged( - boost::bind(&LLNotificationChannelBase::updateItem, this, _1)); - } - else - { - mParents.push_back(channel_name); - LLNotificationChannelPtr p = LLNotifications::instance().getChannel(channel_name); - p->connectChanged(boost::bind(&LLNotificationChannelBase::updateItem, this, _1)); - } + if (channel_name.empty()) + { + mListeners.push_back(LLNotifications::instance().connectChanged( + boost::bind(&LLNotificationChannelBase::updateItem, this, _1))); + } + else + { + mParents.push_back(channel_name); + LLNotificationChannelPtr p = LLNotifications::instance().getChannel(channel_name); + mListeners.push_back(p->connectChanged(boost::bind(&LLNotificationChannelBase::updateItem, this, _1))); + } } // --- @@ -1229,18 +1235,18 @@ void LLNotificationChannel::connectToChannel( const std::string& channel_name ) // ========================================================= -// ============================================== =========== +// ============================================== =========== // LLNotifications implementation // --- -LLNotifications::LLNotifications() -: LLNotificationChannelBase(LLNotificationFilters::includeEverything), - mIgnoreAllNotifications(false) +LLNotifications::LLNotifications() +: LLNotificationChannelBase(LLNotificationFilters::includeEverything), + mIgnoreAllNotifications(false) { mListener.reset(new LLNotificationsListener(*this)); - LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Notification.Show", boost::bind(&LLNotifications::addFromCallback, this, _2)); + LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Notification.Show", boost::bind(&LLNotifications::addFromCallback, this, _2)); - // touch the instance tracker for notification channels, so that it will still be around in our destructor - LLInstanceTracker<LLNotificationChannel, std::string>::instanceCount(); + // touch the instance tracker for notification channels, so that it will still be around in our destructor + LLInstanceTracker<LLNotificationChannel, std::string>::instanceCount(); } void LLNotifications::clear() @@ -1251,152 +1257,152 @@ void LLNotifications::clear() // The expiration channel gets all notifications that are cancelled bool LLNotifications::expirationFilter(LLNotificationPtr pNotification) { - return pNotification->isCancelled() || pNotification->isRespondedTo(); + return pNotification->isCancelled() || pNotification->isRespondedTo(); } bool LLNotifications::expirationHandler(const LLSD& payload) { - if (payload["sigtype"].asString() != "delete") - { - // anything added to this channel actually should be deleted from the master - cancel(find(payload["id"])); - return true; // don't process this item any further - } - return false; + if (payload["sigtype"].asString() != "delete") + { + // anything added to this channel actually should be deleted from the master + cancel(find(payload["id"])); + return true; // don't process this item any further + } + return false; } bool LLNotifications::uniqueFilter(LLNotificationPtr pNotif) { - if (!pNotif->hasUniquenessConstraints()) - { - return true; - } - - // checks against existing unique notifications - for (LLNotificationMap::iterator existing_it = mUniqueNotifications.find(pNotif->getName()); - existing_it != mUniqueNotifications.end(); - ++existing_it) - { - LLNotificationPtr existing_notification = existing_it->second; - if (pNotif != existing_notification - && pNotif->isEquivalentTo(existing_notification)) - { - if (pNotif->getCombineBehavior() == LLNotification::CANCEL_OLD) - { - cancel(existing_notification); - return true; - } - else - { - return false; - } - } - } - - return true; + if (!pNotif->hasUniquenessConstraints()) + { + return true; + } + + // checks against existing unique notifications + for (LLNotificationMap::iterator existing_it = mUniqueNotifications.find(pNotif->getName()); + existing_it != mUniqueNotifications.end(); + ++existing_it) + { + LLNotificationPtr existing_notification = existing_it->second; + if (pNotif != existing_notification + && pNotif->isEquivalentTo(existing_notification)) + { + if (pNotif->getCombineBehavior() == LLNotification::CANCEL_OLD) + { + cancel(existing_notification); + return true; + } + else + { + return false; + } + } + } + + return true; } bool LLNotifications::uniqueHandler(const LLSD& payload) { - std::string cmd = payload["sigtype"]; + std::string cmd = payload["sigtype"]; - LLNotificationPtr pNotif = LLNotifications::instance().find(payload["id"].asUUID()); - if (pNotif && pNotif->hasUniquenessConstraints()) - { - if (cmd == "add") - { - // not a duplicate according to uniqueness criteria, so we keep it - // and store it for future uniqueness checks - mUniqueNotifications.insert(std::make_pair(pNotif->getName(), pNotif)); - } - else if (cmd == "delete") - { - mUniqueNotifications.erase(pNotif->getName()); - } - } + LLNotificationPtr pNotif = LLNotifications::instance().find(payload["id"].asUUID()); + if (pNotif && pNotif->hasUniquenessConstraints()) + { + if (cmd == "add") + { + // not a duplicate according to uniqueness criteria, so we keep it + // and store it for future uniqueness checks + mUniqueNotifications.insert(std::make_pair(pNotif->getName(), pNotif)); + } + else if (cmd == "delete") + { + mUniqueNotifications.erase(pNotif->getName()); + } + } - return false; + return false; } bool LLNotifications::failedUniquenessTest(const LLSD& payload) { - LLNotificationPtr pNotif = LLNotifications::instance().find(payload["id"].asUUID()); - - std::string cmd = payload["sigtype"]; - - if (!pNotif || cmd != "add") - { - return false; - } - - switch(pNotif->getCombineBehavior()) - { - case LLNotification::REPLACE_WITH_NEW: - // Update the existing unique notification with the data from this particular instance... - // This guarantees that duplicate notifications will be collapsed to the one - // most recently triggered - for (LLNotificationMap::iterator existing_it = mUniqueNotifications.find(pNotif->getName()); - existing_it != mUniqueNotifications.end(); - ++existing_it) - { - LLNotificationPtr existing_notification = existing_it->second; - if (pNotif != existing_notification - && pNotif->isEquivalentTo(existing_notification)) - { - // copy notification instance data over to oldest instance - // of this unique notification and update it - existing_notification->updateFrom(pNotif); - // then delete the new one - cancel(pNotif); - } - } - break; - case LLNotification::COMBINE_WITH_NEW: - // Add to the existing unique notification with the data from this particular instance... - // This guarantees that duplicate notifications will be collapsed to the one - // most recently triggered - for (LLNotificationMap::iterator existing_it = mUniqueNotifications.find(pNotif->getName()); - existing_it != mUniqueNotifications.end(); - ++existing_it) - { - LLNotificationPtr existing_notification = existing_it->second; - if (pNotif != existing_notification - && pNotif->isEquivalentTo(existing_notification)) - { - // copy the notifications from the newest instance into the oldest - existing_notification->mCombinedNotifications.push_back(pNotif); - existing_notification->mCombinedNotifications.insert(existing_notification->mCombinedNotifications.end(), - pNotif->mCombinedNotifications.begin(), pNotif->mCombinedNotifications.end()); - - // pop up again - existing_notification->update(); - } - } - break; - case LLNotification::KEEP_OLD: - break; - case LLNotification::CANCEL_OLD: - // already handled by filter logic - break; - default: - break; - } - - return false; + LLNotificationPtr pNotif = LLNotifications::instance().find(payload["id"].asUUID()); + + std::string cmd = payload["sigtype"]; + + if (!pNotif || cmd != "add") + { + return false; + } + + switch(pNotif->getCombineBehavior()) + { + case LLNotification::REPLACE_WITH_NEW: + // Update the existing unique notification with the data from this particular instance... + // This guarantees that duplicate notifications will be collapsed to the one + // most recently triggered + for (LLNotificationMap::iterator existing_it = mUniqueNotifications.find(pNotif->getName()); + existing_it != mUniqueNotifications.end(); + ++existing_it) + { + LLNotificationPtr existing_notification = existing_it->second; + if (pNotif != existing_notification + && pNotif->isEquivalentTo(existing_notification)) + { + // copy notification instance data over to oldest instance + // of this unique notification and update it + existing_notification->updateFrom(pNotif); + // then delete the new one + cancel(pNotif); + } + } + break; + case LLNotification::COMBINE_WITH_NEW: + // Add to the existing unique notification with the data from this particular instance... + // This guarantees that duplicate notifications will be collapsed to the one + // most recently triggered + for (LLNotificationMap::iterator existing_it = mUniqueNotifications.find(pNotif->getName()); + existing_it != mUniqueNotifications.end(); + ++existing_it) + { + LLNotificationPtr existing_notification = existing_it->second; + if (pNotif != existing_notification + && pNotif->isEquivalentTo(existing_notification)) + { + // copy the notifications from the newest instance into the oldest + existing_notification->mCombinedNotifications.push_back(pNotif); + existing_notification->mCombinedNotifications.insert(existing_notification->mCombinedNotifications.end(), + pNotif->mCombinedNotifications.begin(), pNotif->mCombinedNotifications.end()); + + // pop up again + existing_notification->update(); + } + } + break; + case LLNotification::KEEP_OLD: + break; + case LLNotification::CANCEL_OLD: + // already handled by filter logic + break; + default: + break; + } + + return false; } LLNotificationChannelPtr LLNotifications::getChannel(const std::string& channelName) { - return LLNotificationChannelPtr(LLNotificationChannel::getInstance(channelName).get()); + return LLNotificationChannelPtr(LLNotificationChannel::getInstance(channelName).get()); } // this function is called once at construction time, after the object is constructed. void LLNotifications::initSingleton() { - loadTemplates(); - loadVisibilityRules(); - createDefaultChannels(); + loadTemplates(); + loadVisibilityRules(); + createDefaultChannels(); } void LLNotifications::cleanupSingleton() @@ -1407,528 +1413,530 @@ void LLNotifications::cleanupSingleton() void LLNotifications::createDefaultChannels() { LL_INFOS("Notifications") << "Generating default notification channels" << LL_ENDL; - // now construct the various channels AFTER loading the notifications, - // because the history channel is going to rewrite the stored notifications file - mDefaultChannels.push_back(new LLNotificationChannel("Enabled", "", - !boost::bind(&LLNotifications::getIgnoreAllNotifications, this))); - mDefaultChannels.push_back(new LLNotificationChannel("Expiration", "Enabled", - boost::bind(&LLNotifications::expirationFilter, this, _1))); - mDefaultChannels.push_back(new LLNotificationChannel("Unexpired", "Enabled", - !boost::bind(&LLNotifications::expirationFilter, this, _1))); // use negated bind - mDefaultChannels.push_back(new LLNotificationChannel("Unique", "Unexpired", - boost::bind(&LLNotifications::uniqueFilter, this, _1))); - mDefaultChannels.push_back(new LLNotificationChannel("Ignore", "Unique", - filterIgnoredNotifications)); - mDefaultChannels.push_back(new LLNotificationChannel("VisibilityRules", "Ignore", - boost::bind(&LLNotifications::isVisibleByRules, this, _1))); - mDefaultChannels.push_back(new LLNotificationChannel("Visible", "VisibilityRules", - &LLNotificationFilters::includeEverything)); - mDefaultChannels.push_back(new LLPersistentNotificationChannel()); - - // connect action methods to these channels - getChannel("Enabled")->connectFailedFilter(&defaultResponse); - getChannel("Expiration")->connectChanged(boost::bind(&LLNotifications::expirationHandler, this, _1)); - // uniqueHandler slot should be added as first slot of the signal due to - // usage LLStopWhenHandled combiner in LLStandardSignal - getChannel("Unique")->connectAtFrontChanged(boost::bind(&LLNotifications::uniqueHandler, this, _1)); - getChannel("Unique")->connectFailedFilter(boost::bind(&LLNotifications::failedUniquenessTest, this, _1)); - getChannel("Ignore")->connectFailedFilter(&handleIgnoredNotification); - getChannel("VisibilityRules")->connectFailedFilter(&visibilityRuleMached); + // now construct the various channels AFTER loading the notifications, + // because the history channel is going to rewrite the stored notifications file + mDefaultChannels.push_back(new LLNotificationChannel("Enabled", "", + !boost::bind(&LLNotifications::getIgnoreAllNotifications, this))); + mDefaultChannels.push_back(new LLNotificationChannel("Expiration", "Enabled", + boost::bind(&LLNotifications::expirationFilter, this, _1))); + mDefaultChannels.push_back(new LLNotificationChannel("Unexpired", "Enabled", + !boost::bind(&LLNotifications::expirationFilter, this, _1))); // use negated bind + mDefaultChannels.push_back(new LLNotificationChannel("Unique", "Unexpired", + boost::bind(&LLNotifications::uniqueFilter, this, _1))); + mDefaultChannels.push_back(new LLNotificationChannel("Ignore", "Unique", + filterIgnoredNotifications)); + mDefaultChannels.push_back(new LLNotificationChannel("VisibilityRules", "Ignore", + boost::bind(&LLNotifications::isVisibleByRules, this, _1))); + mDefaultChannels.push_back(new LLNotificationChannel("Visible", "VisibilityRules", + &LLNotificationFilters::includeEverything)); + mDefaultChannels.push_back(new LLPersistentNotificationChannel()); + + // connect action methods to these channels + getChannel("Enabled")->connectFailedFilter(&defaultResponse); + getChannel("Expiration")->connectChanged(boost::bind(&LLNotifications::expirationHandler, this, _1)); + // uniqueHandler slot should be added as first slot of the signal due to + // usage LLStopWhenHandled combiner in LLStandardSignal + getChannel("Unique")->connectAtFrontChanged(boost::bind(&LLNotifications::uniqueHandler, this, _1)); + getChannel("Unique")->connectFailedFilter(boost::bind(&LLNotifications::failedUniquenessTest, this, _1)); + getChannel("Ignore")->connectFailedFilter(&handleIgnoredNotification); + getChannel("VisibilityRules")->connectFailedFilter(&visibilityRuleMached); } LLNotificationTemplatePtr LLNotifications::getTemplate(const std::string& name) { - if (mTemplates.count(name)) - { - return mTemplates[name]; - } - else - { - return mTemplates["MissingAlert"]; - } + if (mTemplates.count(name)) + { + return mTemplates[name]; + } + else + { + return mTemplates["MissingAlert"]; + } } bool LLNotifications::templateExists(const std::string& name) { - return (mTemplates.count(name) != 0); + return (mTemplates.count(name) != 0); } void LLNotifications::forceResponse(const LLNotification::Params& params, S32 option) { - LLNotificationPtr temp_notify(new LLNotification(params)); - LLSD response = temp_notify->getResponseTemplate(); - LLSD selected_item = temp_notify->getForm()->getElement(option); - - if (selected_item.isUndefined()) - { - LL_WARNS("Notifications") << "Invalid option" << option << " for notification " << (std::string)params.name << LL_ENDL; - return; - } - response[selected_item["name"].asString()] = true; + LLNotificationPtr temp_notify(new LLNotification(params)); + LLSD response = temp_notify->getResponseTemplate(); + LLSD selected_item = temp_notify->getForm()->getElement(option); + + if (selected_item.isUndefined()) + { + LL_WARNS("Notifications") << "Invalid option" << option << " for notification " << (std::string)params.name << LL_ENDL; + return; + } + response[selected_item["name"].asString()] = true; - temp_notify->respond(response); + temp_notify->respond(response); } LLNotifications::TemplateNames LLNotifications::getTemplateNames() const { - TemplateNames names; - for (TemplateMap::const_iterator it = mTemplates.begin(); it != mTemplates.end(); ++it) - { - names.push_back(it->first); - } - return names; + TemplateNames names; + for (TemplateMap::const_iterator it = mTemplates.begin(); it != mTemplates.end(); ++it) + { + names.push_back(it->first); + } + return names; } typedef std::map<std::string, std::string> StringMap; void replaceSubstitutionStrings(LLXMLNodePtr node, StringMap& replacements) { - // walk the list of attributes looking for replacements - for (LLXMLAttribList::iterator it=node->mAttributes.begin(); - it != node->mAttributes.end(); ++it) - { - std::string value = it->second->getValue(); - if (value[0] == '$') - { - value.erase(0, 1); // trim off the $ - std::string replacement; - StringMap::const_iterator found = replacements.find(value); - if (found != replacements.end()) - { - replacement = found->second; - LL_DEBUGS("Notifications") << "replaceSubstitutionStrings: value: \"" << value << "\" repl: \"" << replacement << "\"." << LL_ENDL; - it->second->setValue(replacement); - } - else - { - LL_WARNS("Notifications") << "replaceSubstitutionStrings FAILURE: could not find replacement \"" << value << "\"." << LL_ENDL; - } - } - } - - // now walk the list of children and call this recursively. - for (LLXMLNodePtr child = node->getFirstChild(); - child.notNull(); child = child->getNextSibling()) - { - replaceSubstitutionStrings(child, replacements); - } + // walk the list of attributes looking for replacements + for (LLXMLAttribList::iterator it=node->mAttributes.begin(); + it != node->mAttributes.end(); ++it) + { + std::string value = it->second->getValue(); + if (value[0] == '$') + { + value.erase(0, 1); // trim off the $ + std::string replacement; + StringMap::const_iterator found = replacements.find(value); + if (found != replacements.end()) + { + replacement = found->second; + LL_DEBUGS("Notifications") << "replaceSubstitutionStrings: value: \"" << value << "\" repl: \"" << replacement << "\"." << LL_ENDL; + it->second->setValue(replacement); + } + else + { + LL_WARNS("Notifications") << "replaceSubstitutionStrings FAILURE: could not find replacement \"" << value << "\"." << LL_ENDL; + } + } + } + + // now walk the list of children and call this recursively. + for (LLXMLNodePtr child = node->getFirstChild(); + child.notNull(); child = child->getNextSibling()) + { + replaceSubstitutionStrings(child, replacements); + } } void replaceFormText(LLNotificationForm::Params& form, const std::string& pattern, const std::string& replace) { - if (form.ignore.isProvided() && form.ignore.text() == pattern) - { - form.ignore.text = replace; - } + if (form.ignore.isProvided() && form.ignore.text() == pattern) + { + form.ignore.text = replace; + } - BOOST_FOREACH(LLNotificationForm::FormElement& element, form.form_elements.elements) - { - if (element.button.isChosen() && element.button.text() == pattern) - { - element.button.text = replace; - } - } + for (LLNotificationForm::FormElement& element : form.form_elements.elements) + { + if (element.button.isChosen() && element.button.text() == pattern) + { + element.button.text = replace; + } + } } void addPathIfExists(const std::string& new_path, std::vector<std::string>& paths) { - if (gDirUtilp->fileExists(new_path)) - { - paths.push_back(new_path); - } + if (gDirUtilp->fileExists(new_path)) + { + paths.push_back(new_path); + } } bool LLNotifications::loadTemplates() { - LL_INFOS("Notifications") << "Reading notifications template" << LL_ENDL; - // Passing findSkinnedFilenames(constraint=LLDir::ALL_SKINS) makes it - // output all relevant pathnames instead of just the ones from the most - // specific skin. - std::vector<std::string> search_paths = - gDirUtilp->findSkinnedFilenames(LLDir::XUI, "notifications.xml", LLDir::ALL_SKINS); + LL_INFOS("Notifications") << "Reading notifications template" << LL_ENDL; + // Passing findSkinnedFilenames(constraint=LLDir::ALL_SKINS) makes it + // output all relevant pathnames instead of just the ones from the most + // specific skin. + std::vector<std::string> search_paths = + gDirUtilp->findSkinnedFilenames(LLDir::XUI, "notifications.xml", LLDir::ALL_SKINS); + if (search_paths.empty()) + { + LLError::LLUserWarningMsg::show(LLTrans::getString("MBMissingFile")); + LL_ERRS() << "Problem finding notifications.xml" << LL_ENDL; + } - std::string base_filename = search_paths.front(); - LLXMLNodePtr root; - BOOL success = LLXMLNode::getLayeredXMLNode(root, search_paths); + std::string base_filename = search_paths.front(); + LLXMLNodePtr root; + BOOL success = LLXMLNode::getLayeredXMLNode(root, search_paths); - if (!success || root.isNull() || !root->hasName( "notifications" )) - { + if (!success || root.isNull() || !root->hasName( "notifications" )) + { LLError::LLUserWarningMsg::show(LLTrans::getString("MBMissingFile")); - LL_ERRS() << "Problem reading XML from UI Notifications file: " << base_filename << LL_ENDL; - return false; - } + LL_ERRS() << "Problem reading XML from UI Notifications file: " << base_filename << LL_ENDL; + return false; + } - LLNotificationTemplate::Notifications params; - LLXUIParser parser; - parser.readXUI(root, params, base_filename); + LLNotificationTemplate::Notifications params; + LLXUIParser parser; + parser.readXUI(root, params, base_filename); - if(!params.validateBlock()) - { + if(!params.validateBlock()) + { LLError::LLUserWarningMsg::show(LLTrans::getString("MBMissingFile")); - LL_ERRS() << "Problem reading XUI from UI Notifications file: " << base_filename << LL_ENDL; - return false; - } - - mTemplates.clear(); - - BOOST_FOREACH(LLNotificationTemplate::GlobalString& string, params.strings) - { - mGlobalStrings[string.name] = string.value; - } - - std::map<std::string, LLNotificationForm::Params> form_templates; - - BOOST_FOREACH(LLNotificationTemplate::Template& notification_template, params.templates) - { - form_templates[notification_template.name] = notification_template.form; - } - - BOOST_FOREACH(LLNotificationTemplate::Params& notification, params.notifications) - { - if (notification.form_ref.form_template.isChosen()) - { - // replace form contents from template - notification.form_ref.form = form_templates[notification.form_ref.form_template.name]; - if(notification.form_ref.form_template.yes_text.isProvided()) - { - replaceFormText(notification.form_ref.form, "$yestext", notification.form_ref.form_template.yes_text); - } - if(notification.form_ref.form_template.no_text.isProvided()) - { - replaceFormText(notification.form_ref.form, "$notext", notification.form_ref.form_template.no_text); - } - if(notification.form_ref.form_template.cancel_text.isProvided()) - { - replaceFormText(notification.form_ref.form, "$canceltext", notification.form_ref.form_template.cancel_text); - } - if(notification.form_ref.form_template.help_text.isProvided()) - { - replaceFormText(notification.form_ref.form, "$helptext", notification.form_ref.form_template.help_text); - } - if(notification.form_ref.form_template.ignore_text.isProvided()) - { - replaceFormText(notification.form_ref.form, "$ignoretext", notification.form_ref.form_template.ignore_text); - } - } - mTemplates[notification.name] = LLNotificationTemplatePtr(new LLNotificationTemplate(notification)); - } - - LL_INFOS("Notifications") << "...done" << LL_ENDL; - - return true; + LL_ERRS() << "Problem reading XUI from UI Notifications file: " << base_filename << LL_ENDL; + return false; + } + + mTemplates.clear(); + + for (const LLNotificationTemplate::GlobalString& string : params.strings) + { + mGlobalStrings[string.name] = string.value; + } + + std::map<std::string, LLNotificationForm::Params> form_templates; + + for (const LLNotificationTemplate::Template& notification_template : params.templates) + { + form_templates[notification_template.name] = notification_template.form; + } + + for (LLNotificationTemplate::Params& notification : params.notifications) + { + if (notification.form_ref.form_template.isChosen()) + { + // replace form contents from template + notification.form_ref.form = form_templates[notification.form_ref.form_template.name]; + if(notification.form_ref.form_template.yes_text.isProvided()) + { + replaceFormText(notification.form_ref.form, "$yestext", notification.form_ref.form_template.yes_text); + } + if(notification.form_ref.form_template.no_text.isProvided()) + { + replaceFormText(notification.form_ref.form, "$notext", notification.form_ref.form_template.no_text); + } + if(notification.form_ref.form_template.cancel_text.isProvided()) + { + replaceFormText(notification.form_ref.form, "$canceltext", notification.form_ref.form_template.cancel_text); + } + if(notification.form_ref.form_template.help_text.isProvided()) + { + replaceFormText(notification.form_ref.form, "$helptext", notification.form_ref.form_template.help_text); + } + if(notification.form_ref.form_template.ignore_text.isProvided()) + { + replaceFormText(notification.form_ref.form, "$ignoretext", notification.form_ref.form_template.ignore_text); + } + } + mTemplates[notification.name] = LLNotificationTemplatePtr(new LLNotificationTemplate(notification)); + } + + LL_INFOS("Notifications") << "...done" << LL_ENDL; + + return true; } bool LLNotifications::loadVisibilityRules() { - const std::string xml_filename = "notification_visibility.xml"; - // Note that here we're looking for the "en" version, the default - // language, rather than the most localized version of this file. - std::string full_filename = gDirUtilp->findSkinnedFilenameBaseLang(LLDir::XUI, xml_filename); + const std::string xml_filename = "notification_visibility.xml"; + // Note that here we're looking for the "en" version, the default + // language, rather than the most localized version of this file. + std::string full_filename = gDirUtilp->findSkinnedFilenameBaseLang(LLDir::XUI, xml_filename); - LLNotificationVisibilityRule::Rules params; - LLSimpleXUIParser parser; - parser.readXUI(full_filename, params); + LLNotificationVisibilityRule::Rules params; + LLSimpleXUIParser parser; + parser.readXUI(full_filename, params); - if(!params.validateBlock()) - { + if(!params.validateBlock()) + { LLError::LLUserWarningMsg::show(LLTrans::getString("MBMissingFile")); - LL_ERRS() << "Problem reading UI Notification Visibility Rules file: " << full_filename << LL_ENDL; - return false; - } + LL_ERRS() << "Problem reading UI Notification Visibility Rules file: " << full_filename << LL_ENDL; + return false; + } - mVisibilityRules.clear(); + mVisibilityRules.clear(); - BOOST_FOREACH(LLNotificationVisibilityRule::Rule& rule, params.rules) - { - mVisibilityRules.push_back(LLNotificationVisibilityRulePtr(new LLNotificationVisibilityRule(rule))); - } + for (const LLNotificationVisibilityRule::Rule& rule : params.rules) + { + mVisibilityRules.push_back(LLNotificationVisibilityRulePtr(new LLNotificationVisibilityRule(rule))); + } - return true; + return true; } // Add a simple notification (from XUI) void LLNotifications::addFromCallback(const LLSD& name) { - add(name.asString(), LLSD(), LLSD()); + add(name.asString(), LLSD(), LLSD()); } LLNotificationPtr LLNotifications::add(const std::string& name, const LLSD& substitutions, const LLSD& payload) { - LLNotification::Params::Functor functor_p; - functor_p.name = name; - return add(LLNotification::Params().name(name).substitutions(substitutions).payload(payload).functor(functor_p)); + LLNotification::Params::Functor functor_p; + functor_p.name = name; + return add(LLNotification::Params().name(name).substitutions(substitutions).payload(payload).functor(functor_p)); } LLNotificationPtr LLNotifications::add(const std::string& name, const LLSD& substitutions, const LLSD& payload, const std::string& functor_name) { - LLNotification::Params::Functor functor_p; - functor_p.name = functor_name; - return add(LLNotification::Params().name(name) - .substitutions(substitutions) - .payload(payload) - .functor(functor_p)); + LLNotification::Params::Functor functor_p; + functor_p.name = functor_name; + return add(LLNotification::Params().name(name) + .substitutions(substitutions) + .payload(payload) + .functor(functor_p)); } - + //virtual LLNotificationPtr LLNotifications::add(const std::string& name, const LLSD& substitutions, const LLSD& payload, LLNotificationFunctorRegistry::ResponseFunctor functor) { - LLNotification::Params::Functor functor_p; - functor_p.function = functor; - return add(LLNotification::Params().name(name) - .substitutions(substitutions) - .payload(payload) - .functor(functor_p)); + LLNotification::Params::Functor functor_p; + functor_p.function = functor; + return add(LLNotification::Params().name(name) + .substitutions(substitutions) + .payload(payload) + .functor(functor_p)); } // generalized add function that takes a parameter block object for more complex instantiations LLNotificationPtr LLNotifications::add(const LLNotification::Params& p) { - LLNotificationPtr pNotif(new LLNotification(p)); - add(pNotif); - return pNotif; + LLNotificationPtr pNotif(new LLNotification(p)); + add(pNotif); + return pNotif; } void LLNotifications::add(const LLNotificationPtr pNotif) { - if (pNotif == NULL) return; + if (pNotif == NULL) return; - // first see if we already have it -- if so, that's a problem - LLNotificationSet::iterator it=mItems.find(pNotif); - if (it != mItems.end()) - { - LL_ERRS() << "Notification added a second time to the master notification channel." << LL_ENDL; - } + // first see if we already have it -- if so, that's a problem + LLNotificationSet::iterator it=mItems.find(pNotif); + if (it != mItems.end()) + { + LL_ERRS() << "Notification added a second time to the master notification channel." << LL_ENDL; + } - updateItem(LLSD().with("sigtype", "add").with("id", pNotif->id()), pNotif); + updateItem(LLSD().with("sigtype", "add").with("id", pNotif->id()), pNotif); } void LLNotifications::load(const LLNotificationPtr pNotif) { - if (pNotif == NULL) return; + if (pNotif == NULL) return; - // first see if we already have it -- if so, that's a problem - LLNotificationSet::iterator it=mItems.find(pNotif); - if (it != mItems.end()) - { - LL_ERRS() << "Notification loaded a second time to the master notification channel." << LL_ENDL; - } + // first see if we already have it -- if so, that's a problem + LLNotificationSet::iterator it=mItems.find(pNotif); + if (it != mItems.end()) + { + LL_ERRS() << "Notification loaded a second time to the master notification channel." << LL_ENDL; + } - updateItem(LLSD().with("sigtype", "load").with("id", pNotif->id()), pNotif); + updateItem(LLSD().with("sigtype", "load").with("id", pNotif->id()), pNotif); } void LLNotifications::cancel(LLNotificationPtr pNotif) { - if (pNotif == NULL || pNotif->isCancelled()) return; + if (pNotif == NULL || pNotif->isCancelled()) return; - LLNotificationSet::iterator it=mItems.find(pNotif); - if (it != mItems.end()) - { - pNotif->cancel(); - updateItem(LLSD().with("sigtype", "delete").with("id", pNotif->id()), pNotif); - } + LLNotificationSet::iterator it=mItems.find(pNotif); + if (it != mItems.end()) + { + pNotif->cancel(); + updateItem(LLSD().with("sigtype", "delete").with("id", pNotif->id()), pNotif); + } } void LLNotifications::cancelByName(const std::string& name) { - std::vector<LLNotificationPtr> notifs_to_cancel; - for (LLNotificationSet::iterator it=mItems.begin(), end_it = mItems.end(); - it != end_it; - ++it) - { - LLNotificationPtr pNotif = *it; - if (pNotif->getName() == name) - { - notifs_to_cancel.push_back(pNotif); - } - } - - for (std::vector<LLNotificationPtr>::iterator it = notifs_to_cancel.begin(), end_it = notifs_to_cancel.end(); - it != end_it; - ++it) - { - LLNotificationPtr pNotif = *it; - pNotif->cancel(); - updateItem(LLSD().with("sigtype", "delete").with("id", pNotif->id()), pNotif); - } + LLMutexLock lock(&mItemsMutex); + std::vector<LLNotificationPtr> notifs_to_cancel; + for (LLNotificationSet::iterator it=mItems.begin(), end_it = mItems.end(); + it != end_it; + ++it) + { + LLNotificationPtr pNotif = *it; + if (pNotif->getName() == name) + { + notifs_to_cancel.push_back(pNotif); + } + } + + for (std::vector<LLNotificationPtr>::iterator it = notifs_to_cancel.begin(), end_it = notifs_to_cancel.end(); + it != end_it; + ++it) + { + LLNotificationPtr pNotif = *it; + pNotif->cancel(); + updateItem(LLSD().with("sigtype", "delete").with("id", pNotif->id()), pNotif); + } } void LLNotifications::cancelByOwner(const LLUUID ownerId) { - std::vector<LLNotificationPtr> notifs_to_cancel; - for (LLNotificationSet::iterator it = mItems.begin(), end_it = mItems.end(); - it != end_it; - ++it) - { - LLNotificationPtr pNotif = *it; - if (pNotif && pNotif->getPayload().get("owner_id").asUUID() == ownerId) - { - notifs_to_cancel.push_back(pNotif); - } - } - - for (std::vector<LLNotificationPtr>::iterator it = notifs_to_cancel.begin(), end_it = notifs_to_cancel.end(); - it != end_it; - ++it) - { - LLNotificationPtr pNotif = *it; - pNotif->cancel(); - updateItem(LLSD().with("sigtype", "delete").with("id", pNotif->id()), pNotif); - } + LLMutexLock lock(&mItemsMutex); + std::vector<LLNotificationPtr> notifs_to_cancel; + for (LLNotificationSet::iterator it = mItems.begin(), end_it = mItems.end(); + it != end_it; + ++it) + { + LLNotificationPtr pNotif = *it; + if (pNotif && pNotif->getPayload().get("owner_id").asUUID() == ownerId) + { + notifs_to_cancel.push_back(pNotif); + } + } + + for (std::vector<LLNotificationPtr>::iterator it = notifs_to_cancel.begin(), end_it = notifs_to_cancel.end(); + it != end_it; + ++it) + { + LLNotificationPtr pNotif = *it; + pNotif->cancel(); + updateItem(LLSD().with("sigtype", "delete").with("id", pNotif->id()), pNotif); + } } void LLNotifications::update(const LLNotificationPtr pNotif) { - LLNotificationSet::iterator it=mItems.find(pNotif); - if (it != mItems.end()) - { - updateItem(LLSD().with("sigtype", "change").with("id", pNotif->id()), pNotif); - } + LLNotificationSet::iterator it=mItems.find(pNotif); + if (it != mItems.end()) + { + updateItem(LLSD().with("sigtype", "change").with("id", pNotif->id()), pNotif); + } } LLNotificationPtr LLNotifications::find(LLUUID uuid) { - LLNotificationPtr target = LLNotificationPtr(new LLNotification(LLNotification::Params().id(uuid))); - LLNotificationSet::iterator it=mItems.find(target); - if (it == mItems.end()) - { - LL_DEBUGS("Notifications") << "Tried to dereference uuid '" << uuid << "' as a notification key but didn't find it." << LL_ENDL; - return LLNotificationPtr((LLNotification*)NULL); - } - else - { - return *it; - } -} - -void LLNotifications::forEachNotification(NotificationProcess process) -{ - std::for_each(mItems.begin(), mItems.end(), process); + LLNotificationPtr target = LLNotificationPtr(new LLNotification(LLNotification::Params().id(uuid))); + LLNotificationSet::iterator it=mItems.find(target); + if (it == mItems.end()) + { + LL_DEBUGS("Notifications") << "Tried to dereference uuid '" << uuid << "' as a notification key but didn't find it." << LL_ENDL; + return LLNotificationPtr((LLNotification*)NULL); + } + else + { + return *it; + } } std::string LLNotifications::getGlobalString(const std::string& key) const { - GlobalStringMap::const_iterator it = mGlobalStrings.find(key); - if (it != mGlobalStrings.end()) - { - return it->second; - } - else - { - // if we don't have the key as a global, return the key itself so that the error - // is self-diagnosing. - return key; - } + GlobalStringMap::const_iterator it = mGlobalStrings.find(key); + if (it != mGlobalStrings.end()) + { + return it->second; + } + else + { + // if we don't have the key as a global, return the key itself so that the error + // is self-diagnosing. + return key; + } } void LLNotifications::setIgnoreAllNotifications(bool setting) { - mIgnoreAllNotifications = setting; + mIgnoreAllNotifications = setting; } bool LLNotifications::getIgnoreAllNotifications() { - return mIgnoreAllNotifications; + return mIgnoreAllNotifications; } void LLNotifications::setIgnored(const std::string& name, bool ignored) { - LLNotificationTemplatePtr templatep = getTemplate(name); - templatep->mForm->setIgnored(ignored); + LLNotificationTemplatePtr templatep = getTemplate(name); + templatep->mForm->setIgnored(ignored); } bool LLNotifications::getIgnored(const std::string& name) { - LLNotificationTemplatePtr templatep = getTemplate(name); - return (mIgnoreAllNotifications) || ( (templatep->mForm->getIgnoreType() != LLNotificationForm::IGNORE_NO) && (templatep->mForm->getIgnored()) ); + LLNotificationTemplatePtr templatep = getTemplate(name); + return (mIgnoreAllNotifications) || ( (templatep->mForm->getIgnoreType() != LLNotificationForm::IGNORE_NO) && (templatep->mForm->getIgnored()) ); } - + bool LLNotifications::isVisibleByRules(LLNotificationPtr n) { - if(n->isRespondedTo()) - { - // This avoids infinite recursion in the case where the filter calls respond() - return true; - } - - VisibilityRuleList::iterator it; - - for(it = mVisibilityRules.begin(); it != mVisibilityRules.end(); it++) - { - // An empty type/tag/name string will match any notification, so only do the comparison when the string is non-empty in the rule. - LL_DEBUGS("Notifications") - << "notification \"" << n->getName() << "\" " - << "testing against " << ((*it)->mVisible?"show":"hide") << " rule, " - << "name = \"" << (*it)->mName << "\" " - << "tag = \"" << (*it)->mTag << "\" " - << "type = \"" << (*it)->mType << "\" " - << LL_ENDL; - - if(!(*it)->mType.empty()) - { - if((*it)->mType != n->getType()) - { - // Type doesn't match, so skip this rule. - continue; - } - } - - if(!(*it)->mTag.empty()) - { - // check this notification's tag(s) against it->mTag and continue if no match is found. - if(!n->matchesTag((*it)->mTag)) - { - // This rule's non-empty tag didn't match one of the notification's tags. Skip this rule. - continue; - } - } - - if(!(*it)->mName.empty()) - { - // check this notification's name against the notification's name and continue if no match is found. - if((*it)->mName != n->getName()) - { - // This rule's non-empty name didn't match the notification. Skip this rule. - continue; - } - } - - // If we got here, the rule matches. Don't evaluate subsequent rules. - if(!(*it)->mVisible) - { - // This notification is being hidden. - - if((*it)->mResponse.empty()) - { - // Response property is empty. Cancel this notification. - LL_DEBUGS("Notifications") << "cancelling notification " << n->getName() << LL_ENDL; - - cancel(n); - } - else - { - // Response property is not empty. Return the specified response. - LLSD response = n->getResponseTemplate(LLNotification::WITHOUT_DEFAULT_BUTTON); - // TODO: verify that the response template has an item with the correct name - response[(*it)->mResponse] = true; - - LL_DEBUGS("Notifications") << "responding to notification " << n->getName() << " with response = " << response << LL_ENDL; - - n->respond(response); - } - - return false; - } - - // If we got here, exit the loop and return true. - break; - } - - LL_DEBUGS("Notifications") << "allowing notification " << n->getName() << LL_ENDL; - - return true; -} - + if(n->isRespondedTo()) + { + // This avoids infinite recursion in the case where the filter calls respond() + return true; + } + + VisibilityRuleList::iterator it; + + for(it = mVisibilityRules.begin(); it != mVisibilityRules.end(); it++) + { + // An empty type/tag/name string will match any notification, so only do the comparison when the string is non-empty in the rule. + LL_DEBUGS("Notifications") + << "notification \"" << n->getName() << "\" " + << "testing against " << ((*it)->mVisible?"show":"hide") << " rule, " + << "name = \"" << (*it)->mName << "\" " + << "tag = \"" << (*it)->mTag << "\" " + << "type = \"" << (*it)->mType << "\" " + << LL_ENDL; + + if(!(*it)->mType.empty()) + { + if((*it)->mType != n->getType()) + { + // Type doesn't match, so skip this rule. + continue; + } + } + + if(!(*it)->mTag.empty()) + { + // check this notification's tag(s) against it->mTag and continue if no match is found. + if(!n->matchesTag((*it)->mTag)) + { + // This rule's non-empty tag didn't match one of the notification's tags. Skip this rule. + continue; + } + } + + if(!(*it)->mName.empty()) + { + // check this notification's name against the notification's name and continue if no match is found. + if((*it)->mName != n->getName()) + { + // This rule's non-empty name didn't match the notification. Skip this rule. + continue; + } + } + + // If we got here, the rule matches. Don't evaluate subsequent rules. + if(!(*it)->mVisible) + { + // This notification is being hidden. + + if((*it)->mResponse.empty()) + { + // Response property is empty. Cancel this notification. + LL_DEBUGS("Notifications") << "cancelling notification " << n->getName() << LL_ENDL; + + cancel(n); + } + else + { + // Response property is not empty. Return the specified response. + LLSD response = n->getResponseTemplate(LLNotification::WITHOUT_DEFAULT_BUTTON); + // TODO: verify that the response template has an item with the correct name + response[(*it)->mResponse] = true; + + LL_DEBUGS("Notifications") << "responding to notification " << n->getName() << " with response = " << response << LL_ENDL; + + n->respond(response); + } + + return false; + } + + // If we got here, exit the loop and return true. + break; + } + + LL_DEBUGS("Notifications") << "allowing notification " << n->getName() << LL_ENDL; + + return true; +} + // --- // END OF LLNotifications implementation @@ -1936,66 +1944,66 @@ bool LLNotifications::isVisibleByRules(LLNotificationPtr n) std::ostream& operator<<(std::ostream& s, const LLNotification& notification) { - s << notification.summarize(); - return s; + s << notification.summarize(); + return s; } void LLPostponedNotification::lookupName(const LLUUID& id, - bool is_group) + bool is_group) { - if (is_group) - { - gCacheName->getGroup(id, - boost::bind(&LLPostponedNotification::onGroupNameCache, - this, _1, _2, _3)); - } - else - { - fetchAvatarName(id); - } + if (is_group) + { + gCacheName->getGroup(id, + boost::bind(&LLPostponedNotification::onGroupNameCache, + this, _1, _2, _3)); + } + else + { + fetchAvatarName(id); + } } void LLPostponedNotification::onGroupNameCache(const LLUUID& id, - const std::string& full_name, - bool is_group) + const std::string& full_name, + bool is_group) { - finalizeName(full_name); + finalizeName(full_name); } void LLPostponedNotification::fetchAvatarName(const LLUUID& id) { - if (id.notNull()) - { - if (mAvatarNameCacheConnection.connected()) - { - mAvatarNameCacheConnection.disconnect(); - } + if (id.notNull()) + { + if (mAvatarNameCacheConnection.connected()) + { + mAvatarNameCacheConnection.disconnect(); + } - mAvatarNameCacheConnection = LLAvatarNameCache::get(id, boost::bind(&LLPostponedNotification::onAvatarNameCache, this, _1, _2)); - } + mAvatarNameCacheConnection = LLAvatarNameCache::get(id, boost::bind(&LLPostponedNotification::onAvatarNameCache, this, _1, _2)); + } } void LLPostponedNotification::onAvatarNameCache(const LLUUID& agent_id, - const LLAvatarName& av_name) + const LLAvatarName& av_name) { - mAvatarNameCacheConnection.disconnect(); + mAvatarNameCacheConnection.disconnect(); + + std::string name = av_name.getCompleteName(); - std::string name = av_name.getCompleteName(); + // from PE merge - we should figure out if this is the right thing to do + if (name.empty()) + { + LL_WARNS("Notifications") << "Empty name received for Id: " << agent_id << LL_ENDL; + name = SYSTEM_FROM; + } - // from PE merge - we should figure out if this is the right thing to do - if (name.empty()) - { - LL_WARNS("Notifications") << "Empty name received for Id: " << agent_id << LL_ENDL; - name = SYSTEM_FROM; - } - - finalizeName(name); + finalizeName(name); } void LLPostponedNotification::finalizeName(const std::string& name) { - mName = name; - modifyNotificationParams(); - LLNotifications::instance().add(mParams); - cleanup(); + mName = name; + modifyNotificationParams(); + LLNotifications::instance().add(mParams); + cleanup(); } |