diff options
Diffstat (limited to 'indra')
33 files changed, 1001 insertions, 459 deletions
diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index 8e78a5fefd..e98201ea63 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -158,6 +158,7 @@ set(llui_HEADER_FILES llnotifications.h llnotificationslistener.h llnotificationsutil.h + llnotificationtemplate.h llpanel.h llprogressbar.h llradiogroup.h diff --git a/indra/llui/llcheckboxctrl.cpp b/indra/llui/llcheckboxctrl.cpp index cbc8f12472..bbd8db2645 100644 --- a/indra/llui/llcheckboxctrl.cpp +++ b/indra/llui/llcheckboxctrl.cpp @@ -50,9 +50,7 @@ template class LLCheckBoxCtrl* LLView::getChild<class LLCheckBoxCtrl>( const std::string& name, BOOL recurse) const; LLCheckBoxCtrl::Params::Params() -: text_enabled_color("text_enabled_color"), - text_disabled_color("text_disabled_color"), - initial_value("initial_value", false), +: initial_value("initial_value", false), label_text("label_text"), check_button("check_button"), radio_style("radio_style") @@ -61,8 +59,8 @@ LLCheckBoxCtrl::Params::Params() LLCheckBoxCtrl::LLCheckBoxCtrl(const LLCheckBoxCtrl::Params& p) : LLUICtrl(p), - mTextEnabledColor(p.text_enabled_color()), - mTextDisabledColor(p.text_disabled_color()), + mTextEnabledColor(p.label_text.text_color()), + mTextDisabledColor(p.label_text.text_readonly_color()), mFont(p.font()) { mViewModel->setValue(LLSD(p.initial_value)); @@ -89,7 +87,6 @@ LLCheckBoxCtrl::LLCheckBoxCtrl(const LLCheckBoxCtrl::Params& p) { tbparams.font(p.font); } - tbparams.text_color( p.enabled() ? p.text_enabled_color() : p.text_disabled_color() ); mLabel = LLUICtrlFactory::create<LLTextBox> (tbparams); addChild(mLabel); diff --git a/indra/llui/llcheckboxctrl.h b/indra/llui/llcheckboxctrl.h index 0147088280..67d8091a97 100644 --- a/indra/llui/llcheckboxctrl.h +++ b/indra/llui/llcheckboxctrl.h @@ -52,8 +52,6 @@ public: struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> { - Optional<LLUIColor> text_enabled_color; - Optional<LLUIColor> text_disabled_color; Optional<bool> initial_value; // override LLUICtrl initial_value Optional<LLTextBox::Params> label_text; diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp index 7dba53e746..bdc094bf47 100644 --- a/indra/llui/llnotifications.cpp +++ b/indra/llui/llnotifications.cpp @@ -27,6 +27,7 @@ #include "linden_common.h" #include "llnotifications.h" +#include "llnotificationtemplate.h" #include "llinstantmessage.h" #include "llxmlnode.h" @@ -37,6 +38,8 @@ #include "lltrans.h" #include "llnotificationslistener.h" #include "llstring.h" +#include "llsdparam.h" +#include "llsdutil.h" #include <algorithm> #include <boost/regex.hpp> @@ -44,6 +47,15 @@ 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); +} + + // Local channel for persistent notifications // Stores only persistent notifications. // Class users can use connectChanged() to process persistent notifications @@ -135,63 +147,58 @@ namespace LLNotificationFilters }; LLNotificationForm::LLNotificationForm() -: mFormData(LLSD::emptyArray()), - mIgnore(IGNORE_NO) +: mIgnore(IGNORE_NO) { } -LLNotificationForm::LLNotificationForm(const std::string& name, const LLXMLNodePtr xml_node) -: mFormData(LLSD::emptyArray()), - mIgnore(IGNORE_NO) +LLNotificationForm::LLNotificationForm(const std::string& name, const LLNotificationForm::Params& p) +: mIgnore(IGNORE_NO) { - if (!xml_node->hasName("form")) + if (p.ignore.isProvided()) { - llwarns << "Bad xml node for form: " << xml_node->getName() << llendl; - } - LLXMLNodePtr child = xml_node->getFirstChild(); - while(child) - { - child = LLNotifications::instance().checkForXMLTemplate(child); + mIgnoreMsg = p.ignore.text; - LLSD item_entry; - std::string element_name = child->getName()->mString; - - if (element_name == "ignore" ) + if (!p.ignore.save_option) { - bool save_option = false; - child->getAttribute_bool("save_option", save_option); - if (!save_option) - { - mIgnore = IGNORE_WITH_DEFAULT_RESPONSE; - } - else - { - // remember last option chosen by user and automatically respond with that in the future - mIgnore = IGNORE_WITH_LAST_RESPONSE; - LLUI::sSettingGroups["ignores"]->declareLLSD(std::string("Default") + name, "", std::string("Default response for notification " + name)); - } - child->getAttributeString("text", mIgnoreMsg); - BOOL show_notification = TRUE; - LLUI::sSettingGroups["ignores"]->declareBOOL(name, show_notification, "Ignore notification with this name", TRUE); + mIgnore = IGNORE_WITH_DEFAULT_RESPONSE; } else { - // flatten xml form entry into single LLSD map with type==name - item_entry["type"] = element_name; - const LLXMLAttribList::iterator attrib_end = child->mAttributes.end(); - for(LLXMLAttribList::iterator attrib_it = child->mAttributes.begin(); - attrib_it != attrib_end; - ++attrib_it) - { - item_entry[std::string(attrib_it->second->getName()->mString)] = attrib_it->second->getValue(); - } - item_entry["value"] = child->getTextContents(); - mFormData.append(item_entry); + // remember last option chosen by user and automatically respond with that in the future + mIgnore = IGNORE_WITH_LAST_RESPONSE; + LLUI::sSettingGroups["ignores"]->declareLLSD(std::string("Default") + name, "", std::string("Default response for notification " + name)); } - child = child->getNextSibling(); + BOOL show_notification = TRUE; + LLUI::sSettingGroups["ignores"]->declareBOOL(name, show_notification, "Ignore notification with this name", TRUE); } + + LLParamSDParser parser; + parser.writeSD(mFormData, p.form_elements); + + mFormData = mFormData[""]; + if (!mFormData.isArray()) + { + // change existing contents to a one element array + LLSD new_llsd_array = LLSD::emptyArray(); + new_llsd_array.append(mFormData); + mFormData = new_llsd_array; + } + + 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) @@ -293,16 +300,37 @@ std::string LLNotificationForm::getDefaultOption() return ""; } -LLNotificationTemplate::LLNotificationTemplate() : - mExpireSeconds(0), - mExpireOption(-1), - mURLOption(-1), - mURLOpenExternally(-1), - mPersist(false), - mUnique(false), - mPriority(NOTIFICATION_PRIORITY_NORMAL) +LLNotificationTemplate::LLNotificationTemplate(const LLNotificationTemplate::Params& p) +: mName(p.name), + mType(p.type), + mMessage(p.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), + mUnique(p.unique.isProvided()), + mPriority(p.priority), + mPersist(p.persist), + mDefaultFunctor(p.functor.isProvided() ? p.functor() : p.name()) { - mForm = LLNotificationFormPtr(new LLNotificationForm()); + if (p.sound.isProvided() + && LLUI::sSettingGroups["config"]->controlExists(p.sound)) + { + mSoundEffect = LLUUID(LLUI::sSettingGroups["config"]->getString(p.sound)); + } + + for(LLInitParam::ParamIterator<LLNotificationTemplate::UniquenessContext>::const_iterator it = p.unique.contexts().begin(), + end_it = p.unique.contexts().end(); + it != end_it; + ++it) + { + mUniqueContext.push_back(it->key); + } + + mForm = LLNotificationFormPtr(new LLNotificationForm(p.name, p.form_ref.form)); } LLNotification::LLNotification(const LLNotification::Params& p) : @@ -528,6 +556,43 @@ void LLNotification::respond(const LLSD& response) update(); } +const std::string& LLNotification::getName() const +{ + return mTemplatep->mName; +} + +const std::string& LLNotification::getIcon() const +{ + return mTemplatep->mIcon; +} + + +bool LLNotification::isPersistent() const +{ + return mTemplatep->mPersist; +} + +std::string LLNotification::getType() const +{ + return (mTemplatep ? mTemplatep->mType : ""); +} + +S32 LLNotification::getURLOption() const +{ + return (mTemplatep ? mTemplatep->mURLOption : -1); +} + +S32 LLNotification::getURLOpenExternally() const +{ + return(mTemplatep? mTemplatep->mURLTarget == "_external": -1); +} + +bool LLNotification::hasUniquenessConstraints() const +{ + return (mTemplatep ? mTemplatep->mUnique : false); +} + + void LLNotification::setIgnored(bool ignore) { mIgnored = ignore; @@ -1095,11 +1160,6 @@ bool LLNotifications::templateExists(const std::string& name) return (mTemplates.count(name) != 0); } -void LLNotifications::clearTemplates() -{ - mTemplates.clear(); -} - void LLNotifications::forceResponse(const LLNotification::Params& params, S32 option) { LLNotificationPtr temp_notify(new LLNotification(params)); @@ -1162,190 +1222,88 @@ void replaceSubstitutionStrings(LLXMLNodePtr node, StringMap& replacements) } } -// private to this file -// returns true if the template request was invalid and there's nothing else we -// can do with this node, false if you should keep processing (it may have -// replaced the contents of the node referred to) -LLXMLNodePtr LLNotifications::checkForXMLTemplate(LLXMLNodePtr item) +void replaceFormText(LLNotificationForm::Params& form, const std::string& pattern, const std::string& replace) { - if (item->hasName("usetemplate")) + if (form.ignore.isProvided() && form.ignore.text() == pattern) + { + form.ignore.text = replace; + } + for (LLInitParam::ParamIterator<LLNotificationForm::FormElement>::iterator it = form.form_elements.elements().begin(), + end_it = form.form_elements.elements().end(); + it != end_it; + ++it) { - std::string replacementName; - if (item->getAttributeString("name", replacementName)) + if (it->button.isChosen() && it->button.text() == pattern) { - StringMap replacements; - for (LLXMLAttribList::const_iterator it=item->mAttributes.begin(); - it != item->mAttributes.end(); ++it) - { - replacements[it->second->getName()->mString] = it->second->getValue(); - } - if (mXmlTemplates.count(replacementName)) - { - item=LLXMLNode::replaceNode(item, mXmlTemplates[replacementName]); - - // walk the nodes looking for $(substitution) here and replace - replaceSubstitutionStrings(item, replacements); - } - else - { - llwarns << "XML template lookup failure on '" << replacementName << "' " << llendl; - } + it->button.text = replace; } } - return item; } bool LLNotifications::loadTemplates() { const std::string xml_filename = "notifications.xml"; + std::string full_filename = gDirUtilp->findSkinnedFilename(LLUI::getXUIPaths().front(), xml_filename); + LLXMLNodePtr root; - BOOL success = LLUICtrlFactory::getLayeredXMLNode(xml_filename, root); if (!success || root.isNull() || !root->hasName( "notifications" )) { - llerrs << "Problem reading UI Notifications file: " << xml_filename << llendl; + llerrs << "Problem reading UI Notifications file: " << full_filename << llendl; return false; } - - clearTemplates(); - - for (LLXMLNodePtr item = root->getFirstChild(); - item.notNull(); item = item->getNextSibling()) - { - // we do this FIRST so that item can be changed if we - // encounter a usetemplate -- we just replace the - // current xml node and keep processing - item = checkForXMLTemplate(item); - - if (item->hasName("global")) - { - std::string global_name; - if (item->getAttributeString("name", global_name)) - { - mGlobalStrings[global_name] = item->getTextContents(); - } - continue; - } - - if (item->hasName("template")) - { - // store an xml template; templates must have a single node (can contain - // other nodes) - std::string name; - item->getAttributeString("name", name); - LLXMLNodePtr ptr = item->getFirstChild(); - mXmlTemplates[name] = ptr; - continue; - } - - if (!item->hasName("notification")) - { - llwarns << "Unexpected entity " << item->getName()->mString << - " found in " << xml_filename << llendl; - continue; - } - - // now we know we have a notification entry, so let's build it - LLNotificationTemplatePtr pTemplate(new LLNotificationTemplate()); - if (!item->getAttributeString("name", pTemplate->mName)) - { - llwarns << "Unable to parse notification with no name" << llendl; - continue; - } - - //llinfos << "Parsing " << pTemplate->mName << llendl; - - pTemplate->mMessage = item->getTextContents(); - pTemplate->mDefaultFunctor = pTemplate->mName; - item->getAttributeString("type", pTemplate->mType); - item->getAttributeString("icon", pTemplate->mIcon); - item->getAttributeString("label", pTemplate->mLabel); - item->getAttributeU32("duration", pTemplate->mExpireSeconds); - item->getAttributeU32("expireOption", pTemplate->mExpireOption); - - std::string priority; - item->getAttributeString("priority", priority); - pTemplate->mPriority = NOTIFICATION_PRIORITY_NORMAL; - if (!priority.empty()) - { - if (priority == "low") pTemplate->mPriority = NOTIFICATION_PRIORITY_LOW; - if (priority == "normal") pTemplate->mPriority = NOTIFICATION_PRIORITY_NORMAL; - if (priority == "high") pTemplate->mPriority = NOTIFICATION_PRIORITY_HIGH; - if (priority == "critical") pTemplate->mPriority = NOTIFICATION_PRIORITY_CRITICAL; - } - - item->getAttributeString("functor", pTemplate->mDefaultFunctor); - - BOOL persist = false; - item->getAttributeBOOL("persist", persist); - pTemplate->mPersist = persist; - - std::string sound; - item->getAttributeString("sound", sound); - if (!sound.empty()) + LLNotificationTemplate::Notifications params; + LLXUIParser parser; + parser.readXUI(root, params, full_filename); + + mTemplates.clear(); + + for(LLInitParam::ParamIterator<LLNotificationTemplate::GlobalString>::const_iterator it = params.strings().begin(), end_it = params.strings().end(); + it != end_it; + ++it) + { + mGlobalStrings[it->name] = it->value; + } + + std::map<std::string, LLNotificationForm::Params> form_templates; + + for(LLInitParam::ParamIterator<LLNotificationTemplate::Template>::const_iterator it = params.templates().begin(), end_it = params.templates().end(); + it != end_it; + ++it) + { + form_templates[it->name] = it->form; + } + + for(LLInitParam::ParamIterator<LLNotificationTemplate::Params>::iterator it = params.notifications().begin(), end_it = params.notifications().end(); + it != end_it; + ++it) + { + if (it->form_ref.form_template.isChosen()) { - // test for bad sound effect name / missing effect - if (LLUI::sSettingGroups["config"]->controlExists(sound)) + // replace form contents from template + it->form_ref.form = form_templates[it->form_ref.form_template.name]; + if(it->form_ref.form_template.yes_text.isProvided()) { - pTemplate->mSoundEffect = - LLUUID(LLUI::sSettingGroups["config"]->getString(sound)); + replaceFormText(it->form_ref.form, "$yestext", it->form_ref.form_template.yes_text); } - else + if(it->form_ref.form_template.no_text.isProvided()) { - llwarns << "Unknown sound effect control name " << sound - << llendl; + replaceFormText(it->form_ref.form, "$notext", it->form_ref.form_template.no_text); } - } - - for (LLXMLNodePtr child = item->getFirstChild(); - !child.isNull(); child = child->getNextSibling()) - { - child = checkForXMLTemplate(child); - - // <url> - if (child->hasName("url")) + if(it->form_ref.form_template.cancel_text.isProvided()) { - pTemplate->mURL = child->getTextContents(); - child->getAttributeU32("option", pTemplate->mURLOption); - child->getAttributeU32("openexternally", pTemplate->mURLOpenExternally); + replaceFormText(it->form_ref.form, "$cancel_text", it->form_ref.form_template.cancel_text); } - - if (child->hasName("unique")) - { - pTemplate->mUnique = true; - for (LLXMLNodePtr formitem = child->getFirstChild(); - !formitem.isNull(); formitem = formitem->getNextSibling()) - { - if (formitem->hasName("context")) - { - std::string key; - formitem->getAttributeString("key", key); - pTemplate->mUniqueContext.push_back(key); - //llwarns << "adding " << key << " to unique context" << llendl; - } - else - { - llwarns << "'unique' has unrecognized subelement " - << formitem->getName()->mString << llendl; - } - } - } - - // <form> - if (child->hasName("form")) + if(it->form_ref.form_template.ignore_text.isProvided()) { - pTemplate->mForm = LLNotificationFormPtr(new LLNotificationForm(pTemplate->mName, child)); + replaceFormText(it->form_ref.form, "$ignore_text", it->form_ref.form_template.ignore_text); } } - addTemplate(pTemplate->mName, pTemplate); + addTemplate(it->name, LLNotificationTemplatePtr(new LLNotificationTemplate(*it))); } - - //std::ostringstream ostream; - //root->writeToOstream(ostream, "\n "); - //llwarns << ostream.str() << llendl; - + return true; } @@ -1396,6 +1354,8 @@ LLNotificationPtr LLNotifications::add(const LLNotification::Params& p) void LLNotifications::add(const LLNotificationPtr pNotif) { + 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()) @@ -1408,6 +1368,8 @@ void LLNotifications::add(const LLNotificationPtr pNotif) void LLNotifications::cancel(LLNotificationPtr pNotif) { + if (pNotif == NULL) return; + LLNotificationSet::iterator it=mItems.find(pNotif); if (it == mItems.end()) { diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h index 11adad8194..a58e7afe23 100644 --- a/indra/llui/llnotifications.h +++ b/indra/llui/llnotifications.h @@ -100,7 +100,6 @@ #include "llnotificationptr.h" #include "llcachename.h" - typedef enum e_notification_priority { NOTIFICATION_PRIORITY_UNSPECIFIED, @@ -110,6 +109,11 @@ typedef enum e_notification_priority NOTIFICATION_PRIORITY_CRITICAL } ENotificationPriority; +struct NotificationPriorityValues : public LLInitParam::TypeValuesHelper<ENotificationPriority, NotificationPriorityValues> +{ + static void declareValues(); +}; + class LLNotificationResponderInterface { public: @@ -157,6 +161,90 @@ class LLNotificationForm LOG_CLASS(LLNotificationForm); public: + struct FormElementBase : public LLInitParam::Block<FormElementBase> + { + Mandatory<std::string> name; + + FormElementBase() + : name("name") + {} + }; + + struct FormIgnore : public LLInitParam::Block<FormIgnore, FormElementBase> + { + Optional<std::string> text; + Optional<bool> save_option; + + FormIgnore() + : text("text"), + save_option("save_option", false) + {} + }; + + struct FormButton : public LLInitParam::Block<FormButton, FormElementBase> + { + Mandatory<S32> index; + Mandatory<std::string> text; + Optional<std::string> ignore; + Optional<bool> is_default; + + Mandatory<std::string> type; + + FormButton() + : index("index"), + text("text"), + ignore("ignore"), + is_default("default"), + type("type") + { + // set type here so it gets serialized + type = "button"; + } + }; + + struct FormInput : public LLInitParam::Block<FormInput, FormElementBase> + { + Mandatory<std::string> type; + Optional<S32> width; + + FormInput() + : type("type"), + width("width", 0) + {} + }; + + struct FormElement : public LLInitParam::Choice<FormElement> + { + Alternative<FormButton> button; + Alternative<FormInput> input; + + FormElement() + : button("button"), + input("input") + {} + }; + + struct FormElements : public LLInitParam::Block<FormElements> + { + Multiple<FormElement> elements; + FormElements() + : elements("") + {} + }; + + struct Params : public LLInitParam::Block<Params> + { + Optional<std::string> name; + Optional<FormIgnore> ignore; + Optional<FormElements> form_elements; + + Params() + : name("name"), + ignore("ignore"), + form_elements("") + {} + }; + typedef enum e_ignore_type { IGNORE_NO, @@ -167,8 +255,7 @@ public: LLNotificationForm(); LLNotificationForm(const LLSD& sd); - LLNotificationForm(const std::string& name, - const LLPointer<class LLXMLNode> xml_node); + LLNotificationForm(const std::string& name, const Params& p); LLSD asLLSD() const; @@ -193,80 +280,8 @@ private: typedef boost::shared_ptr<LLNotificationForm> LLNotificationFormPtr; -// This is the class of object read from the XML file (notifications.xml, -// from the appropriate local language directory). -struct LLNotificationTemplate -{ - LLNotificationTemplate(); - // the name of the notification -- the key used to identify it - // Ideally, the key should follow variable naming rules - // (no spaces or punctuation). - std::string mName; - // The type of the notification - // used to control which queue it's stored in - std::string mType; - // The text used to display the notification. Replaceable parameters - // are enclosed in square brackets like this []. - std::string mMessage; - // The label for the notification; used for - // certain classes of notification (those with a window and a window title). - // Also used when a notification pops up underneath the current one. - // Replaceable parameters can be used in the label. - std::string mLabel; - // The name of the icon image. This should include an extension. - std::string mIcon; - // This is the Highlander bit -- "There Can Be Only One" - // An outstanding notification with this bit set - // is updated by an incoming notification with the same name, - // rather than creating a new entry in the queue. - // (used for things like progress indications, or repeating warnings - // like "the grid is going down in N minutes") - bool mUnique; - // if we want to be unique only if a certain part of the payload is constant - // specify the field names for the payload. The notification will only be - // combined if all of the fields named in the context are identical in the - // new and the old notification; otherwise, the notification will be - // duplicated. This is to support suppressing duplicate offers from the same - // sender but still differentiating different offers. Example: Invitation to - // conference chat. - std::vector<std::string> mUniqueContext; - // If this notification expires automatically, this value will be - // nonzero, and indicates the number of seconds for which the notification - // will be valid (a teleport offer, for example, might be valid for - // 300 seconds). - U32 mExpireSeconds; - // if the offer expires, one of the options is chosen automatically - // based on its "value" parameter. This controls which one. - // If expireSeconds is specified, expireOption should also be specified. - U32 mExpireOption; - // if the notification contains a url, it's stored here (and replaced - // into the message where [_URL] is found) - std::string mURL; - // if there's a URL in the message, this controls which option visits - // that URL. Obsolete this and eliminate the buttons for affected - // messages when we allow clickable URLs in the UI - U32 mURLOption; - - U32 mURLOpenExternally; - //This is a flag that tells if the url needs to open externally dispite - //what the user setting is. - - // does this notification persist across sessions? if so, it will be - // serialized to disk on first receipt and read on startup - bool mPersist; - // This is the name of the default functor, if present, to be - // used for the notification's callback. It is optional, and used only if - // the notification is constructed without an identified functor. - std::string mDefaultFunctor; - // The form data associated with a given notification (buttons, text boxes, etc) - LLNotificationFormPtr mForm; - // default priority for notifications of this type - ENotificationPriority mPriority; - // UUID of the audio file to be played when this notification arrives - // this is loaded as a name, but looked up to get the UUID upon template load. - // If null, it wasn't specified. - LLUUID mSoundEffect; -}; + +struct LLNotificationTemplate; // we want to keep a map of these by name, and it's best to manage them // with smart pointers @@ -302,7 +317,7 @@ public: // optional Optional<LLSD> substitutions; Optional<LLSD> payload; - Optional<ENotificationPriority> priority; + Optional<ENotificationPriority, NotificationPriorityValues> priority; Optional<LLSD> form_elements; Optional<LLDate> time_stamp; Optional<LLNotificationContext*> context; @@ -469,15 +484,11 @@ public: return mIgnored; } - const std::string& getName() const - { - return mTemplatep->mName; - } + const std::string& getName() const; - bool isPersistent() const - { - return mTemplatep->mPersist; - } + const std::string& getIcon() const; + + bool isPersistent() const; const LLUUID& id() const { @@ -499,28 +510,12 @@ public: return mTimestamp; } - std::string getType() const - { - return (mTemplatep ? mTemplatep->mType : ""); - } - + std::string getType() const; std::string getMessage() const; std::string getLabel() const; - std::string getURL() const; -// { -// return (mTemplatep ? mTemplatep->mURL : ""); -// } - - S32 getURLOption() const - { - return (mTemplatep ? mTemplatep->mURLOption : -1); - } - - S32 getURLOpenExternally() const - { - return(mTemplatep? mTemplatep->mURLOpenExternally : -1); - } + S32 getURLOption() const; + S32 getURLOpenExternally() const; const LLNotificationFormPtr getForm(); @@ -590,7 +585,7 @@ public: std::string summarize() const; - bool hasUniquenessConstraints() const { return (mTemplatep ? mTemplatep->mUnique : false);} + bool hasUniquenessConstraints() const; virtual ~LLNotification() {} }; @@ -872,7 +867,6 @@ public: // load notification descriptions from file; // OK to call more than once because it will reload bool loadTemplates(); - LLPointer<class LLXMLNode> checkForXMLTemplate(LLPointer<class LLXMLNode> item); // Add a simple notification (from XUI) void addFromCallback(const LLSD& name); @@ -918,8 +912,6 @@ public: // test for existence bool templateExists(const std::string& name); - // useful if you're reloading the file - void clearTemplates(); // erase all templates void forceResponse(const LLNotification::Params& params, S32 option); @@ -957,9 +949,6 @@ private: std::string mFileName; - typedef std::map<std::string, LLPointer<class LLXMLNode> > XMLTemplateMap; - XMLTemplateMap mXmlTemplates; - LLNotificationMap mUniqueNotifications; typedef std::map<std::string, std::string> GlobalStringMap; diff --git a/indra/llui/llnotificationtemplate.h b/indra/llui/llnotificationtemplate.h new file mode 100644 index 0000000000..4a020bfe70 --- /dev/null +++ b/indra/llui/llnotificationtemplate.h @@ -0,0 +1,274 @@ +/** +* @file llnotificationtemplate.h +* @brief Description of notification contents +* @author Q (with assistance from Richard and Coco) +* +* $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$ +*/ + +#ifndef LL_LLNOTIFICATION_TEMPLATE_H +#define LL_LLNOTIFICATION_TEMPLATE_H + +//#include <string> +//#include <list> +//#include <vector> +//#include <map> +//#include <set> +//#include <iomanip> +//#include <sstream> +// +//#include <boost/utility.hpp> +//#include <boost/shared_ptr.hpp> +//#include <boost/enable_shared_from_this.hpp> +//#include <boost/type_traits.hpp> +// +//// we want to minimize external dependencies, but this one is important +//#include "llsd.h" +// +//// and we need this to manage the notification callbacks +//#include "llevents.h" +//#include "llfunctorregistry.h" +//#include "llpointer.h" +#include "llinitparam.h" +//#include "llnotificationslistener.h" +//#include "llnotificationptr.h" +//#include "llcachename.h" +#include "llnotifications.h" + + +typedef boost::shared_ptr<LLNotificationForm> LLNotificationFormPtr; + +// This is the class of object read from the XML file (notifications.xml, +// from the appropriate local language directory). +struct LLNotificationTemplate +{ + struct GlobalString : public LLInitParam::Block<GlobalString> + { + Mandatory<std::string> name, + value; + + GlobalString() + : name("name"), + value("value") + {} + }; + + struct UniquenessContext : public LLInitParam::Block<UniquenessContext> + { + Mandatory<std::string> key; + + UniquenessContext() + : key("key") + {} + + }; + + struct UniquenessConstraint : public LLInitParam::Block<UniquenessConstraint> + { + Multiple<UniquenessContext> contexts; + + UniquenessConstraint() + : contexts("context") + {} + }; + + // Templates are used to define common form types, such as OK/Cancel dialogs, etc. + + struct Template : public LLInitParam::Block<Template> + { + Mandatory<std::string> name; + Mandatory<LLNotificationForm::Params> form; + + Template() + : name("name"), + form("form") + {} + }; + + // Reference a template to use its form elements + struct TemplateRef : public LLInitParam::Block<TemplateRef> + { + Mandatory<std::string> name; + Optional<std::string> yes_text, + no_text, + cancel_text, + ignore_text; + + TemplateRef() + : name("name"), + yes_text("yestext"), + no_text("notext"), + cancel_text("canceltext"), + ignore_text("ignoretext") + {} + }; + + struct URL : public LLInitParam::Block<URL> + { + Mandatory<S32> option; + Mandatory<std::string> value; + Optional<std::string> target; + Ignored name; + + URL() + : option("option", -1), + value("value"), + target("target", "_blank"), + name("name") + {} + }; + + struct FormRef : public LLInitParam::Choice<FormRef> + { + Alternative<LLNotificationForm::Params> form; + Alternative<TemplateRef> form_template; + + FormRef() + : form("form"), + form_template("usetemplate") + {} + }; + + struct Params : public LLInitParam::Block<Params> + { + Mandatory<std::string> name; + Optional<bool> persist; + Optional<std::string> functor, + icon, + label, + sound, + type, + value; + Optional<U32> duration; + Optional<S32> expire_option; + Optional<URL> url; + Optional<UniquenessConstraint> unique; + Optional<FormRef> form_ref; + Optional<ENotificationPriority, + NotificationPriorityValues> priority; + + + Params() + : name("name"), + persist("persist", false), + functor("functor"), + icon("icon"), + label("label"), + priority("priority"), + sound("sound"), + type("type"), + value("value"), + duration("duration"), + expire_option("expireOption", -1), + url("url"), + unique("unique"), + form_ref("") + {} + + }; + + struct Notifications : public LLInitParam::Block<Notifications> + { + Multiple<GlobalString> strings; + Multiple<Template> templates; + Multiple<Params> notifications; + + Notifications() + : strings("global"), + notifications("notification"), + templates("template") + {} + }; + + LLNotificationTemplate(const Params& p); + // the name of the notification -- the key used to identify it + // Ideally, the key should follow variable naming rules + // (no spaces or punctuation). + std::string mName; + // The type of the notification + // used to control which queue it's stored in + std::string mType; + // The text used to display the notification. Replaceable parameters + // are enclosed in square brackets like this []. + std::string mMessage; + // The label for the notification; used for + // certain classes of notification (those with a window and a window title). + // Also used when a notification pops up underneath the current one. + // Replaceable parameters can be used in the label. + std::string mLabel; + // The name of the icon image. This should include an extension. + std::string mIcon; + // This is the Highlander bit -- "There Can Be Only One" + // An outstanding notification with this bit set + // is updated by an incoming notification with the same name, + // rather than creating a new entry in the queue. + // (used for things like progress indications, or repeating warnings + // like "the grid is going down in N minutes") + bool mUnique; + // if we want to be unique only if a certain part of the payload is constant + // specify the field names for the payload. The notification will only be + // combined if all of the fields named in the context are identical in the + // new and the old notification; otherwise, the notification will be + // duplicated. This is to support suppressing duplicate offers from the same + // sender but still differentiating different offers. Example: Invitation to + // conference chat. + std::vector<std::string> mUniqueContext; + // If this notification expires automatically, this value will be + // nonzero, and indicates the number of seconds for which the notification + // will be valid (a teleport offer, for example, might be valid for + // 300 seconds). + U32 mExpireSeconds; + // if the offer expires, one of the options is chosen automatically + // based on its "value" parameter. This controls which one. + // If expireSeconds is specified, expireOption should also be specified. + U32 mExpireOption; + // if the notification contains a url, it's stored here (and replaced + // into the message where [_URL] is found) + std::string mURL; + // if there's a URL in the message, this controls which option visits + // that URL. Obsolete this and eliminate the buttons for affected + // messages when we allow clickable URLs in the UI + U32 mURLOption; + + std::string mURLTarget; + //This is a flag that tells if the url needs to open externally dispite + //what the user setting is. + + // does this notification persist across sessions? if so, it will be + // serialized to disk on first receipt and read on startup + bool mPersist; + // This is the name of the default functor, if present, to be + // used for the notification's callback. It is optional, and used only if + // the notification is constructed without an identified functor. + std::string mDefaultFunctor; + // The form data associated with a given notification (buttons, text boxes, etc) + LLNotificationFormPtr mForm; + // default priority for notifications of this type + ENotificationPriority mPriority; + // UUID of the audio file to be played when this notification arrives + // this is loaded as a name, but looked up to get the UUID upon template load. + // If null, it wasn't specified. + LLUUID mSoundEffect; +}; + +#endif //LL_LLNOTIFICATION_TEMPLATE_H + diff --git a/indra/llui/llsdparam.cpp b/indra/llui/llsdparam.cpp index bc1a0fd645..f97f80ab6c 100644 --- a/indra/llui/llsdparam.cpp +++ b/indra/llui/llsdparam.cpp @@ -29,6 +29,7 @@ // Project includes #include "llsdparam.h" +#include "llsdutil.h" static LLInitParam::Parser::parser_read_func_map_t sReadFuncs; static LLInitParam::Parser::parser_write_func_map_t sWriteFuncs; @@ -48,7 +49,7 @@ LLParamSDParser::LLParamSDParser() registerParserFuncs<U32>(readU32, &LLParamSDParser::writeU32Param); registerParserFuncs<F32>(readF32, &LLParamSDParser::writeTypedValue<F32>); registerParserFuncs<F64>(readF64, &LLParamSDParser::writeTypedValue<F64>); - registerParserFuncs<bool>(readBool, &LLParamSDParser::writeTypedValue<F32>); + registerParserFuncs<bool>(readBool, &LLParamSDParser::writeTypedValue<bool>); registerParserFuncs<std::string>(readString, &LLParamSDParser::writeTypedValue<std::string>); registerParserFuncs<LLUUID>(readUUID, &LLParamSDParser::writeTypedValue<LLUUID>); registerParserFuncs<LLDate>(readDate, &LLParamSDParser::writeTypedValue<LLDate>); @@ -61,7 +62,7 @@ LLParamSDParser::LLParamSDParser() bool LLParamSDParser::writeU32Param(LLParamSDParser::parser_t& parser, const void* val_ptr, const parser_t::name_stack_t& name_stack) { LLParamSDParser& sdparser = static_cast<LLParamSDParser&>(parser); - if (!sdparser.mWriteSD) return false; + if (!sdparser.mWriteRootSD) return false; LLSD* sd_to_write = sdparser.getSDWriteNode(name_stack); if (!sd_to_write) return false; @@ -81,7 +82,8 @@ void LLParamSDParser::readSD(const LLSD& sd, LLInitParam::BaseBlock& block, bool void LLParamSDParser::writeSD(LLSD& sd, const LLInitParam::BaseBlock& block) { - mWriteSD = &sd; + mNameStack.clear(); + mWriteRootSD = &sd; block.serializeBlock(*this); } @@ -131,7 +133,77 @@ void LLParamSDParser::readSDValues(const LLSD& sd, LLInitParam::BaseBlock& block LLSD* LLParamSDParser::getSDWriteNode(const parser_t::name_stack_t& name_stack) { //TODO: implement nested LLSD writing - return mWriteSD; + LLSD* sd_to_write = mWriteRootSD; + bool new_traversal = false; + for (name_stack_t::const_iterator it = name_stack.begin(), prev_it = mNameStack.begin(); + it != name_stack.end(); + ++it) + { + bool new_array_entry = false; + if (prev_it == mNameStack.end()) + { + new_traversal = true; + } + else + { + if (!new_traversal // have not diverged yet from previous trace + && prev_it->first == it->first // names match + && prev_it->second != it->second) // versions differ + { + // name stacks match, but version numbers differ in last place. + // create a different entry at this point using an LLSD array + new_array_entry = true; + } + if (prev_it->first != it->first // names differ + || prev_it->second != it->second) // versions differ + { + // at this point we have diverged from our last trace + // so any elements referenced here are new + new_traversal = true; + } + } + + LLSD* child_sd = &(*sd_to_write)[it->first]; + + if (child_sd->isArray()) + { + if (new_traversal) + { + // write to new element at end + sd_to_write = &(*child_sd)[child_sd->size()]; + } + else + { + // write to last of existing elements, or first element if empty + sd_to_write = &(*child_sd)[llmax(0, child_sd->size() - 1)]; + } + } + else + { + if (new_array_entry && !child_sd->isArray()) + { + // copy child contents into first element of an array + LLSD new_array = LLSD::emptyArray(); + new_array.append(*child_sd); + // assign array to slot that previously held the single value + *child_sd = new_array; + // return next element in that array + sd_to_write = &((*child_sd)[1]); + } + else + { + sd_to_write = child_sd; + } + } + if (prev_it != mNameStack.end()) + { + ++prev_it; + } + } + mNameStack = name_stack; + + //llinfos << ll_pretty_print_sd(*mWriteRootSD) << llendl; + return sd_to_write; } bool LLParamSDParser::readS32(Parser& parser, void* val_ptr) diff --git a/indra/llui/llsdparam.h b/indra/llui/llsdparam.h index bebf202b81..97e8b58e49 100644 --- a/indra/llui/llsdparam.h +++ b/indra/llui/llsdparam.h @@ -51,7 +51,7 @@ private: static bool writeTypedValue(Parser& parser, const void* val_ptr, const parser_t::name_stack_t& name_stack) { LLParamSDParser& sdparser = static_cast<LLParamSDParser&>(parser); - if (!sdparser.mWriteSD) return false; + if (!sdparser.mWriteRootSD) return false; LLSD* sd_to_write = sdparser.getSDWriteNode(name_stack); if (!sd_to_write) return false; @@ -77,7 +77,8 @@ private: Parser::name_stack_t mNameStack; const LLSD* mCurReadSD; - LLSD* mWriteSD; + LLSD* mWriteRootSD; + LLSD* mCurWriteSD; }; template<typename T> diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index a6f1af9274..3fa86bf0ca 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -214,7 +214,7 @@ void LLView::setUseBoundingRect( BOOL use_bounding_rect ) } } -BOOL LLView::getUseBoundingRect() +BOOL LLView::getUseBoundingRect() const { return mUseBoundingRect; } @@ -1366,12 +1366,12 @@ void LLView::drawDebugRect() // drawing solids requires texturing be disabled gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - if (mUseBoundingRect) + if (getUseBoundingRect()) { LLUI::translate((F32)mBoundingRect.mLeft - (F32)mRect.mLeft, (F32)mBoundingRect.mBottom - (F32)mRect.mBottom, 0.f); } - LLRect debug_rect = mUseBoundingRect ? mBoundingRect : mRect; + LLRect debug_rect = getUseBoundingRect() ? mBoundingRect : mRect; // draw red rectangle for the border LLColor4 border_color(0.25f, 0.25f, 0.25f, 1.f); @@ -1569,7 +1569,7 @@ void LLView::updateBoundingRect() LLRect cur_rect = mBoundingRect; - if (mUseBoundingRect) + if (getUseBoundingRect()) { mBoundingRect = calcBoundingRect(); } @@ -1579,7 +1579,7 @@ void LLView::updateBoundingRect() } // give parent view a chance to resize, in case we just moved, for example - if (getParent() && getParent()->mUseBoundingRect) + if (getParent() && getParent()->getUseBoundingRect()) { getParent()->updateBoundingRect(); } @@ -1603,7 +1603,7 @@ LLRect LLView::calcScreenBoundingRect() const { LLRect screen_rect; // get bounding rect, if used - LLRect bounding_rect = mUseBoundingRect ? mBoundingRect : mRect; + LLRect bounding_rect = getUseBoundingRect() ? mBoundingRect : mRect; // convert to local coordinates, as defined by mRect bounding_rect.translate(-mRect.mLeft, -mRect.mBottom); @@ -1734,14 +1734,14 @@ LLView* LLView::findChildView(const std::string& name, BOOL recurse) const BOOL LLView::parentPointInView(S32 x, S32 y, EHitTestType type) const { - return (mUseBoundingRect && type == HIT_TEST_USE_BOUNDING_RECT) + return (getUseBoundingRect() && type == HIT_TEST_USE_BOUNDING_RECT) ? mBoundingRect.pointInRect( x, y ) : mRect.pointInRect( x, y ); } BOOL LLView::pointInView(S32 x, S32 y, EHitTestType type) const { - return (mUseBoundingRect && type == HIT_TEST_USE_BOUNDING_RECT) + return (getUseBoundingRect() && type == HIT_TEST_USE_BOUNDING_RECT) ? mBoundingRect.pointInRect( x + mRect.mLeft, y + mRect.mBottom ) : mRect.localPointInRect( x, y ); } diff --git a/indra/llui/llview.h b/indra/llui/llview.h index 3504bb6619..6bcee98f26 100644 --- a/indra/llui/llview.h +++ b/indra/llui/llview.h @@ -234,7 +234,7 @@ public: void setSoundFlags(U8 flags) { mSoundFlags = flags; } void setName(std::string name) { mName = name; } void setUseBoundingRect( BOOL use_bounding_rect ); - BOOL getUseBoundingRect(); + BOOL getUseBoundingRect() const; ECursorType getHoverCursor() { return mHoverCursor; } diff --git a/indra/llvfs/lldir_win32.cpp b/indra/llvfs/lldir_win32.cpp index 8b1a2ddd3c..52d864e26f 100644 --- a/indra/llvfs/lldir_win32.cpp +++ b/indra/llvfs/lldir_win32.cpp @@ -116,10 +116,6 @@ LLDir_Win32::LLDir_Win32() mExecutableDir = utf16str_to_utf8str(llutf16string(w_str)); #endif - mAppRODataDir = "."; - - mSkinBaseDir = mAppRODataDir + mDirDelimiter + "skins"; - if (mExecutableDir.find("indra") == std::string::npos) { // Running from installed directory. Make sure current @@ -129,8 +125,12 @@ LLDir_Win32::LLDir_Win32() GetCurrentDirectory(MAX_PATH, w_str); mWorkingDir = utf16str_to_utf8str(llutf16string(w_str)); } + mAppRODataDir = mWorkingDir; + llinfos << "mAppRODataDir = " << mAppRODataDir << llendl; + mSkinBaseDir = mAppRODataDir + mDirDelimiter + "skins"; + // Build the default cache directory mDefaultCacheDir = buildSLOSCacheDir(); diff --git a/indra/llxuixml/llinitparam.cpp b/indra/llxuixml/llinitparam.cpp index 7b6be55ec7..dc4d93d38a 100644 --- a/indra/llxuixml/llinitparam.cpp +++ b/indra/llxuixml/llinitparam.cpp @@ -178,7 +178,7 @@ namespace LLInitParam param_handle_t param_handle = it->second->mParamHandle; const Param* param = getParamFromHandle(param_handle); ParamDescriptor::serialize_func_t serialize_func = it->second->mSerializeFunc; - if (serialize_func) + if (serialize_func && param->getProvided()) { // Ensure this param has not already been serialized // Prevents <rect> from being serialized as its own tag. diff --git a/indra/llxuixml/llinitparam.h b/indra/llxuixml/llinitparam.h index 60b14d9a90..610381dcfe 100644 --- a/indra/llxuixml/llinitparam.h +++ b/indra/llxuixml/llinitparam.h @@ -1027,6 +1027,7 @@ namespace LLInitParam operator value_assignment_t() const { return self_t::get(); } // explicit conversion value_assignment_t operator()() const { return get(); } + container_t& operator()() { return mValues; } U32 numValidElements() const { @@ -1100,24 +1101,28 @@ namespace LLInitParam static bool deserializeParam(Param& param, Parser& parser, const Parser::name_stack_range_t& name_stack, S32 generation) { self_t& typed_param = static_cast<self_t&>(param); + bool new_value = false; if (generation != typed_param.mLastParamGeneration || typed_param.mValues.empty()) { + new_value = true; typed_param.mValues.push_back(value_t()); typed_param.mCachedKeys.push_back(Data()); - typed_param.enclosingBlock().setLastChangedParam(param, true); - typed_param.mLastParamGeneration = generation; } - value_t& value = typed_param.mValues.back(); + value_ref_t value = typed_param.mValues.back(); // attempt to parse block... if(value.deserializeBlock(parser, name_stack)) { + if (new_value) + { // successfully parsed new value, let's keep it + typed_param.mLastParamGeneration = generation; + } + typed_param.enclosingBlock().setLastChangedParam(param, true); typed_param.setProvided(true); return true; } - - if(!NAME_VALUE_LOOKUP::empty()) + else if(!NAME_VALUE_LOOKUP::empty()) { // try to parse a known named value std::string name; @@ -1126,6 +1131,11 @@ namespace LLInitParam // try to parse a per type named value if (NAME_VALUE_LOOKUP::get(name, value)) { + if (new_value) + { // successfully parsed new value, let's keep it + typed_param.mLastParamGeneration = generation; + } + typed_param.mCachedKeys.back().setKey(name); typed_param.mCachedKeys.back().mKeyVersion = value.getLastChangeVersion(); typed_param.enclosingBlock().setLastChangedParam(param, true); @@ -1136,6 +1146,12 @@ namespace LLInitParam } } + if (new_value) + { // failed to parse new value, pop it off + typed_param.mValues.pop_back(); + typed_param.mCachedKeys.pop_back(); + } + return false; } @@ -1210,6 +1226,7 @@ namespace LLInitParam operator value_assignment_t() const { return self_t::get(); } // explicit conversion value_assignment_t operator()() const { return get(); } + container_t& operator()() { return mValues; } U32 numValidElements() const { diff --git a/indra/llxuixml/llxuiparser.cpp b/indra/llxuixml/llxuiparser.cpp index afc9b38246..e1ad9a5c71 100644 --- a/indra/llxuixml/llxuiparser.cpp +++ b/indra/llxuixml/llxuiparser.cpp @@ -1145,6 +1145,8 @@ void LLSimpleXUIParser::characterDataHandler(void *userData, const char *s, int void LLSimpleXUIParser::startElement(const char *name, const char **atts) { + processText(); + typedef boost::tokenizer<boost::char_separator<char> > tokenizer; boost::char_separator<char> sep("."); @@ -1238,8 +1240,7 @@ bool LLSimpleXUIParser::readAttributes(const char **atts) return any_parsed; } - -void LLSimpleXUIParser::endElement(const char *name) +void LLSimpleXUIParser::processText() { if (!mTextContents.empty()) { @@ -1250,9 +1251,14 @@ void LLSimpleXUIParser::endElement(const char *name) mCurAttributeValueBegin = mTextContents.c_str(); mOutputStack.back().first->submitValue(mNameStack, *this, mParseSilently); mNameStack.pop_back(); - mTextContents.clear(); } + mTextContents.clear(); } +} + +void LLSimpleXUIParser::endElement(const char *name) +{ + processText(); if (--mOutputStack.back().second == 0) { diff --git a/indra/llxuixml/llxuiparser.h b/indra/llxuixml/llxuiparser.h index 2522128e03..5c613b0c69 100644 --- a/indra/llxuixml/llxuiparser.h +++ b/indra/llxuixml/llxuiparser.h @@ -218,6 +218,7 @@ private: void endElement(const char *name); void characterData(const char *s, int len); bool readAttributes(const char **atts); + void processText(); Parser::name_stack_t mNameStack; struct XML_ParserStruct* mParser; diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 2920b30129..c236dc1c3f 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -91,6 +91,7 @@ set(viewer_SOURCE_FILES llbottomtray.cpp llbox.cpp llbreadcrumbview.cpp + llbrowsernotification.cpp llbuycurrencyhtml.cpp llcallbacklist.cpp llcallfloater.cpp diff --git a/indra/newview/llbrowsernotification.cpp b/indra/newview/llbrowsernotification.cpp new file mode 100644 index 0000000000..e162527e23 --- /dev/null +++ b/indra/newview/llbrowsernotification.cpp @@ -0,0 +1,57 @@ +/** + * @file llbrowsernotification.cpp + * @brief Notification Handler Class for browser popups + * + * $LicenseInfo:firstyear=2000&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$ + */ + + +#include "llviewerprecompiledheaders.h" // must be first include + +#include "llnotificationhandler.h" +#include "llnotifications.h" +#include "llfloatermediabrowser.h" +#include "llfloaterreg.h" + +using namespace LLNotificationsUI; + +bool LLBrowserNotification::processNotification(const LLSD& notify) +{ + LLNotificationPtr notification = LLNotifications::instance().find(notify["id"].asUUID()); + + if (notification) + { + LLFloaterMediaBrowser* browserp = dynamic_cast<LLFloaterMediaBrowser*>(LLFloaterReg::findInstance("media_browser", notification->getPayload()["source"])); + if (notify["sigtype"].asString() == "add" || notify["sigtype"].asString() == "load") + { + if (browserp) + { + browserp->showNotification(notification); + } + } + else if (notify["sigtype"].asString() == "delete") + { + browserp->hideNotification(); + } + } + return false; +} diff --git a/indra/newview/llfloatermediabrowser.cpp b/indra/newview/llfloatermediabrowser.cpp index 5e06a2e078..751304588b 100644 --- a/indra/newview/llfloatermediabrowser.cpp +++ b/indra/newview/llfloatermediabrowser.cpp @@ -47,6 +47,9 @@ #include "llcombobox.h" #include "llwindow.h" #include "lllayoutstack.h" +#include "llcheckboxctrl.h" + +#include "llnotifications.h" // TEMP #include "llsdutil.h" @@ -210,12 +213,16 @@ void LLFloaterMediaBrowser::draw() BOOL LLFloaterMediaBrowser::postBuild() { mBrowser = getChild<LLMediaCtrl>("browser"); + mBrowser->setMediaID(mKey); mBrowser->addObserver(this); mAddressCombo = getChild<LLComboBox>("address"); mAddressCombo->setCommitCallback(onEnterAddress, this); mAddressCombo->sortByName(); + LLButton& notification_close = getChildRef<LLButton>("close_notification"); + notification_close.setClickedCallback(boost::bind(&LLFloaterMediaBrowser::onCloseNotification, this), NULL); + childSetAction("back", onClickBack, this); childSetAction("forward", onClickForward, this); childSetAction("reload", onClickRefresh, this); @@ -319,6 +326,73 @@ void LLFloaterMediaBrowser::setCurrentURL(const std::string& url) getChildView("reload")->setEnabled(TRUE); } +void LLFloaterMediaBrowser::showNotification(LLNotificationPtr notify) +{ + mCurNotification = notify; + + // add popup here + LLSD payload = notify->getPayload(); + + LLNotificationFormPtr formp = notify->getForm(); + LLLayoutPanel& panel = getChildRef<LLLayoutPanel>("notification_area"); + panel.setVisible(true); + panel.getChild<LLUICtrl>("notification_icon")->setValue(notify->getIcon()); + panel.getChild<LLUICtrl>("notification_text")->setValue(notify->getMessage()); + panel.getChild<LLUICtrl>("notification_text")->setToolTip(notify->getMessage()); + LLNotificationForm::EIgnoreType ignore_type = formp->getIgnoreType(); + LLLayoutPanel& form_elements = panel.getChildRef<LLLayoutPanel>("form_elements"); + + const S32 FORM_PADDING_HORIZONTAL = 10; + const S32 FORM_PADDING_VERTICAL = 5; + S32 cur_x = FORM_PADDING_HORIZONTAL; + + if (ignore_type != LLNotificationForm::IGNORE_NO) + { + LLCheckBoxCtrl::Params checkbox_p; + checkbox_p.name = "ignore_check"; + checkbox_p.rect = LLRect(cur_x, form_elements.getRect().getHeight() - FORM_PADDING_VERTICAL, cur_x, FORM_PADDING_VERTICAL); + checkbox_p.label = formp->getIgnoreMessage(); + checkbox_p.label_text.text_color = LLColor4::black; + checkbox_p.commit_callback.function = boost::bind(&LLFloaterMediaBrowser::onClickIgnore, this, _1); + + LLCheckBoxCtrl* check = LLUICtrlFactory::create<LLCheckBoxCtrl>(checkbox_p); + check->setRect(check->getBoundingRect()); + form_elements.addChild(check); + cur_x = check->getRect().mRight + FORM_PADDING_HORIZONTAL; + } + + for (S32 i = 0; i < formp->getNumElements(); i++) + { + LLSD form_element = formp->getElement(i); + if (form_element["type"].asString() == "button") + { + LLButton::Params button_p; + button_p.name = form_element["name"]; + button_p.label = form_element["text"]; + button_p.rect = LLRect(cur_x, form_elements.getRect().getHeight() - FORM_PADDING_VERTICAL, cur_x, FORM_PADDING_VERTICAL); + button_p.commit_callback.function = boost::bind(&LLFloaterMediaBrowser::onClickNotificationButton, this, form_element["name"].asString()); + button_p.auto_resize = true; + + LLButton* button = LLUICtrlFactory::create<LLButton>(button_p); + button->autoResize(); + form_elements.addChild(button); + + cur_x = button->getRect().mRight + FORM_PADDING_HORIZONTAL; + } + } + + + form_elements.reshape(cur_x, form_elements.getRect().getHeight()); + + //LLWeb::loadURL(payload["url"], payload["target"]); +} + +void LLFloaterMediaBrowser::hideNotification() +{ + LLLayoutPanel& panel = getChildRef<LLLayoutPanel>("notification_area"); + panel.setVisible(FALSE); +} + //static void LLFloaterMediaBrowser::onEnterAddress(LLUICtrl* ctrl, void* user_data) { @@ -451,3 +525,29 @@ void LLFloaterMediaBrowser::openMedia(const std::string& media_url, const std::s mBrowser->navigateTo(media_url); setCurrentURL(media_url); } + +void LLFloaterMediaBrowser::onCloseNotification() +{ + LLNotifications::instance().cancel(mCurNotification); +} + +void LLFloaterMediaBrowser::onClickIgnore(LLUICtrl* ctrl) +{ + bool check = ctrl->getValue().asBoolean(); + if (mCurNotification && mCurNotification->getForm()->getIgnoreType() == LLNotificationForm::IGNORE_SHOW_AGAIN) + { + // question was "show again" so invert value to get "ignore" + check = !check; + } + mCurNotification->setIgnored(check); +} + +void LLFloaterMediaBrowser::onClickNotificationButton(const std::string& name) +{ + if (!mCurNotification) return; + + LLSD response = mCurNotification->getResponseTemplate(); + response[name] = true; + + mCurNotification->respond(response); +} diff --git a/indra/newview/llfloatermediabrowser.h b/indra/newview/llfloatermediabrowser.h index 5cb7377a36..1a6f3a0352 100644 --- a/indra/newview/llfloatermediabrowser.h +++ b/indra/newview/llfloatermediabrowser.h @@ -33,6 +33,7 @@ class LLComboBox; class LLMediaCtrl; +class LLNotification; class LLFloaterMediaBrowser : public LLFloater, @@ -59,6 +60,8 @@ public: void buildURLHistory(); std::string getSupportURL(); void setCurrentURL(const std::string& url); + void showNotification(boost::shared_ptr<LLNotification> notify); + void hideNotification(); static void onEnterAddress(LLUICtrl* ctrl, void* user_data); static void onClickRefresh(void* user_data); @@ -74,9 +77,14 @@ public: static void onClickSeek(void* user_data); private: + void onCloseNotification(); + void onClickIgnore(LLUICtrl* ctrl); + void onClickNotificationButton(const std::string& name); + LLMediaCtrl* mBrowser; LLComboBox* mAddressCombo; std::string mCurrentURL; + boost::shared_ptr<LLNotification> mCurNotification; std::string mUUID; }; diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 9892b4e357..50aacc6458 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -57,6 +57,7 @@ #include "llnearbychat.h" #include "llnotifications.h" #include "llnotificationsutil.h" +#include "llnotificationtemplate.h" #include "llpanellogin.h" #include "llradiogroup.h" #include "llsearchcombobox.h" diff --git a/indra/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp index 635ceb8380..951aaee705 100644 --- a/indra/newview/llmediactrl.cpp +++ b/indra/newview/llmediactrl.cpp @@ -48,6 +48,7 @@ // linden library includes #include "llfocusmgr.h" +#include "llsdutil.h" extern BOOL gRestoreGL; @@ -62,7 +63,8 @@ LLMediaCtrl::Params::Params() texture_width("texture_width", 1024), texture_height("texture_height", 1024), caret_color("caret_color"), - initial_mime_type("initial_mime_type") + initial_mime_type("initial_mime_type"), + media_id("media_id") { tab_stop(false); } @@ -88,6 +90,7 @@ LLMediaCtrl::LLMediaCtrl( const Params& p) : mTextureWidth ( 1024 ), mTextureHeight ( 1024 ), mClearCache(false), + mMediaID(p.media_id), mHomePageMimeType(p.initial_mime_type) { { @@ -934,9 +937,20 @@ void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event) case MEDIA_EVENT_CLICK_LINK_HREF: { LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CLICK_LINK_HREF, target is \"" << self->getClickTarget() << "\", uri is " << self->getClickURL() << LL_ENDL; + // retrieve the event parameters + std::string url = self->getClickURL(); + std::string target = self->getClickTarget(); + std::string uuid = self->getClickUUID(); + + if(gSavedSettings.getBOOL("MediaEnablePopups")) + { + LLNotificationsUtil::add("PopupAttempt", + LLSD(), + LLSD().with("source", mMediaID).with("target", target).with("url", url).with("uuid", uuid), + boost::bind(&LLMediaCtrl::onPopup, this, _1, _2)); + } }; - break; - + case MEDIA_EVENT_CLICK_LINK_NOFOLLOW: { LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CLICK_LINK_NOFOLLOW, uri is " << self->getClickURL() << LL_ENDL; @@ -991,3 +1005,16 @@ std::string LLMediaCtrl::getCurrentNavUrl() return mCurrentNavUrl; } +void LLMediaCtrl::onPopup(const LLSD& notification, const LLSD& response) +{ + if (response["open"]) + { + LLWeb::loadURL(notification["payload"]["url"], notification["payload"]["target"], notification["payload"]["uuid"]); + } + else + { + // Make sure the opening instance knows its window open request was denied, so it can clean things up. + LLViewerMedia::proxyWindowClosed(notification["payload"]["uuid"]); + } + +} diff --git a/indra/newview/llmediactrl.h b/indra/newview/llmediactrl.h index 6fefd8f6d7..54d50ce4d0 100644 --- a/indra/newview/llmediactrl.h +++ b/indra/newview/llmediactrl.h @@ -59,6 +59,7 @@ public: Optional<LLUIColor> caret_color; Optional<std::string> initial_mime_type; + Optional<std::string> media_id; Params(); }; @@ -141,6 +142,7 @@ public: bool getDecoupleTextureSize() { return mDecoupleTextureSize; } void setTextureSize(S32 width, S32 height); + void setMediaID(const std::string& id) { mMediaID = id; } // over-rides @@ -163,6 +165,7 @@ public: private: void onVisibilityChange ( const LLSD& new_visibility ); + void onPopup(const LLSD& notification, const LLSD& response); const S32 mTextureDepthBytes; LLUUID mMediaTextureID; @@ -185,6 +188,7 @@ public: bool mDecoupleTextureSize; S32 mTextureWidth; S32 mTextureHeight; + std::string mMediaID; bool mClearCache; }; diff --git a/indra/newview/llnotificationhandler.h b/indra/newview/llnotificationhandler.h index 3c84a02b68..28a69f2373 100644 --- a/indra/newview/llnotificationhandler.h +++ b/indra/newview/llnotificationhandler.h @@ -276,6 +276,15 @@ public: virtual bool processNotification(const LLSD& notify); }; +/** + * Handler for browser notifications + */ +class LLBrowserNotification : public LLSingleton<LLBrowserNotification> +{ +public: + virtual bool processNotification(const LLSD& notify); + +}; class LLHandlerUtil { diff --git a/indra/newview/llnotificationmanager.cpp b/indra/newview/llnotificationmanager.cpp index 17cf1ab2b8..6988227128 100644 --- a/indra/newview/llnotificationmanager.cpp +++ b/indra/newview/llnotificationmanager.cpp @@ -61,6 +61,7 @@ void LLNotificationManager::init() LLNotificationChannel::buildChannel("IM Notifications", "Visible", LLNotificationFilters::filterBy<std::string>(&LLNotification::getType, "notifytoast")); LLNotificationChannel::buildChannel("Offer", "Visible", LLNotificationFilters::filterBy<std::string>(&LLNotification::getType, "offer")); LLNotificationChannel::buildChannel("Hints", "Visible", LLNotificationFilters::filterBy<std::string>(&LLNotification::getType, "hint")); + LLNotificationChannel::buildChannel("Browser", "Visible", LLNotificationFilters::filterBy<std::string>(&LLNotification::getType, "browser")); LLNotifications::instance().getChannel("Notifications")->connectChanged(boost::bind(&LLNotificationManager::onNotification, this, _1)); LLNotifications::instance().getChannel("NotificationTips")->connectChanged(boost::bind(&LLNotificationManager::onNotification, this, _1)); @@ -70,6 +71,7 @@ void LLNotificationManager::init() LLNotifications::instance().getChannel("IM Notifications")->connectChanged(boost::bind(&LLNotificationManager::onNotification, this, _1)); LLNotifications::instance().getChannel("Offer")->connectChanged(boost::bind(&LLNotificationManager::onNotification, this, _1)); LLNotifications::instance().getChannel("Hints")->connectChanged(boost::bind(&LLHintHandler::processNotification, LLHintHandler::getInstance(), _1)); + LLNotifications::instance().getChannel("Browser")->connectChanged(boost::bind(&LLBrowserNotification::processNotification, LLBrowserNotification::getInstance(), _1)); mNotifyHandlers["notify"] = boost::shared_ptr<LLEventHandler>(new LLScriptHandler(NT_NOTIFY, LLSD())); mNotifyHandlers["notifytip"] = boost::shared_ptr<LLEventHandler>(new LLTipHandler(NT_NOTIFY, LLSD())); diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 860d0b9fd6..48ab122edf 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -2856,13 +2856,6 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla case MEDIA_EVENT_CLICK_LINK_HREF: { LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CLICK_LINK_HREF, target is \"" << plugin->getClickTarget() << "\", uri is " << plugin->getClickURL() << LL_ENDL; - // retrieve the event parameters - std::string url = plugin->getClickURL(); - std::string target = plugin->getClickTarget(); - std::string uuid = plugin->getClickUUID(); - - // loadURL now handles distinguishing between _blank, _external, and other named targets. - LLWeb::loadURL(url, target, uuid); }; break; case MEDIA_EVENT_PLUGIN_FAILED_LAUNCH: diff --git a/indra/newview/skins/default/xui/en/alert_check_box.xml b/indra/newview/skins/default/xui/en/alert_check_box.xml index 9f1bdb5193..5535a5dc2a 100644 --- a/indra/newview/skins/default/xui/en/alert_check_box.xml +++ b/indra/newview/skins/default/xui/en/alert_check_box.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> <check_box - text_enabled_color="LabelTextColor" - text_disabled_color="LabelDisabledColor" + label_text.text_color="LabelTextColor" + label_text.text_readonly_color="LabelDisabledColor" font="SansSerif" follows="left|top" name="check"/>
\ No newline at end of file diff --git a/indra/newview/skins/default/xui/en/floater_first_time_tip.xml b/indra/newview/skins/default/xui/en/floater_first_time_tip.xml index e4ac8fed77..084b3167c7 100644 --- a/indra/newview/skins/default/xui/en/floater_first_time_tip.xml +++ b/indra/newview/skins/default/xui/en/floater_first_time_tip.xml @@ -16,7 +16,7 @@ layout="topleft" left="5" name="DontShowFirstTimeTip_checkbox" - text_enabled_color="white" + label_text.text_color="white" top="225" width="200" /> </floater> diff --git a/indra/newview/skins/default/xui/en/floater_media_browser.xml b/indra/newview/skins/default/xui/en/floater_media_browser.xml index 3b78da2a79..c220124f46 100644 --- a/indra/newview/skins/default/xui/en/floater_media_browser.xml +++ b/indra/newview/skins/default/xui/en/floater_media_browser.xml @@ -31,6 +31,7 @@ width="800"> <layout_panel auto_resize="false" + default_tab_group="1" height="20" layout="topleft" left="0" @@ -78,6 +79,7 @@ <combo_box allow_text_entry="true" follows="left|top|right" + tab_group="1" height="20" layout="topleft" left_pad="5" @@ -182,76 +184,6 @@ function="MediaBrowser.Assign" /> </button> </layout_panel> - <layout_panel - height="30" - layout="topleft" - name="notification_area" - visible="false" - user_resize="false" - background_visible="true" - bg_alpha_image="Yellow_Gradient" - auto_resize="false" - width="800"> - <layout_stack - top="0" - height="30" - width="800" - left="0" - follows="all" - orientation="horizontal" - > - <layout_panel - height="30"> - <icon value="Popup_Caution" - left="5" - top="7" - width="16" - height="15"/> - <text left_pad="8" - top="10" - height="25" - width="400" - text_color="black" - font="SansSerifSmall" - font.style="BOLD" - name="notification_text" - value="Notification text here" - /> - </layout_panel> - <layout_panel - height="30" - width="270" - auto_resize="false" - name="form_elements"> - <check_box name="enable_check" - left="5" - top="5" - height="20" - width="120" - label="Enable all popups" - text_enabled_color="black" - /> - <button left_pad="5" - width="140" - top="4" - label="Open pop-up window"/> - </layout_panel> - <layout_panel - height="30" - width="25" - auto_resize="false" - name="close_panel"> - <button left="5" - name="close" - width="16" - height="16" - top="8" - image_color="DkGray_66" - image_unselected="Icon_Close_Foreground" - image_selected="Icon_Close_Press"/> - </layout_panel> - </layout_stack> - </layout_panel> <layout_panel height="40" layout="topleft" @@ -260,14 +192,84 @@ top_delta="0" user_resize="false" width="540"> - <web_browser + <web_browser bottom="-30" - follows="left|right|top|bottom" + follows="all" layout="topleft" left="0" name="browser" top="0" width="540" /> + <layout_stack + name="notification_stack" + left="0" + top="0" + width="540" + bottom="-30" + follows="all" + mouse_opaque="false" + orientation="vertical"> + <layout_panel + height="30" + min_height="30" + layout="topleft" + name="notification_area" + visible="false" + user_resize="false" + background_visible="true" + bg_alpha_image="Yellow_Gradient" + auto_resize="false" + width="800"> + <layout_stack + top="0" + height="30" + width="800" + left="0" + follows="bottom|left|right" + orientation="horizontal"> + <layout_panel + height="30"> + <icon name="notification_icon" + left="5" + top="7" + width="16" + height="15"/> + <text left_pad="8" + top="10" + height="25" + width="400" + text_color="black" + font="SansSerifSmall" + font.style="BOLD" + name="notification_text" + value="Notification text here"/> + </layout_panel> + <layout_panel + height="30" + width="130" + auto_resize="false" + user_resize="false" + name="form_elements"/> + <layout_panel + height="30" + width="25" + auto_resize="false" + name="close_panel"> + <button left="5" + name="close_notification" + width="16" + height="16" + top="8" + image_color="DkGray_66" + image_unselected="Icon_Close_Foreground" + image_selected="Icon_Close_Press"/> + </layout_panel> + </layout_stack> + </layout_panel> + <layout_panel + mouse_opaque="false" + auto_resize="true"/> + </layout_stack> <button follows="bottom|left" height="20" diff --git a/indra/newview/skins/default/xui/en/floater_test_checkbox.xml b/indra/newview/skins/default/xui/en/floater_test_checkbox.xml index 1935edfcc1..95aaadfcf3 100644 --- a/indra/newview/skins/default/xui/en/floater_test_checkbox.xml +++ b/indra/newview/skins/default/xui/en/floater_test_checkbox.xml @@ -41,7 +41,7 @@ layout="topleft" left_delta="0" name="text_enabled_color_checkbox" - text_enabled_color="EmphasisColor" + label_text.text_color="EmphasisColor" top_pad="14" width="150" /> <check_box @@ -51,7 +51,7 @@ layout="topleft" left_delta="0" name="text_disabled_color_checkbox" - text_disabled_color="EmphasisColor_35" + label_text.text_readonly_color="EmphasisColor_35" top_pad="14" width="150" /> <check_box diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 47bb0fe45b..59fcd3513e 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -1,6 +1,5 @@ <?xml version="1.0" ?><notifications> - - <global name="skipnexttime"> + <global name="skipnexttime"> Don't show me this again </global> @@ -97,7 +96,7 @@ </template> <notification - functor="GenericAcknowledge" + functor="GenericAcknowledge" icon="alertmodal.tga" name="MissingAlert" label="Unknown Notification Message" @@ -723,7 +722,7 @@ You need an account to enter [SECOND_LIFE]. Would you like to create one now? <url option="0" name="url" - openexternally = "1"> + target = "_external"> http://join.secondlife.com/ </url> @@ -2033,8 +2032,8 @@ Offer friendship to [NAME]? </notification> <notification - icon="alertmodal.tga" - label="Add Friend" + icon="alertmodal.tga" + label="Add Friend" name="AddFriendWithMessage" type="alertmodal"> Friends can give permissions to track each other on the map and receive online status updates. @@ -6040,7 +6039,6 @@ One or more of your Voice Morphs will expire in less than [INTERVAL] days. [[URL] Click here] to renew your subscription. <unique/> </notification> - LLNotificationsUtil::add("VoiceEffectsNew"); <notification icon="notify.tga" @@ -6453,6 +6451,27 @@ Mute everyone? <unique/> </notification> + <notification + name="PopupAttempt" + icon="Popup_Caution" + type="browser" + duration="10" + > + A pop-up was prevented from opening. + <unique/> + <form name="form"> + <ignore name="ignore" + text="Enable all pop-ups"/> + <button default="true" + index="0" + name="open" + text="Open pop-up window"/> + </form> + + + </notification> + + <global name="UnsupportedCPU"> - Your CPU speed does not meet the minimum requirements. </global> diff --git a/indra/newview/skins/default/xui/en/panel_edit_profile.xml b/indra/newview/skins/default/xui/en/panel_edit_profile.xml index 5072ec3a66..48bd9ace21 100644 --- a/indra/newview/skins/default/xui/en/panel_edit_profile.xml +++ b/indra/newview/skins/default/xui/en/panel_edit_profile.xml @@ -242,7 +242,7 @@ left="8" name="show_in_search_checkbox" height="15" - text_enabled_color="white" + label_text.text_color="white" top_pad="12" width="100" /> <text diff --git a/indra/newview/skins/default/xui/en/panel_sidetray_home_tab.xml b/indra/newview/skins/default/xui/en/panel_sidetray_home_tab.xml index e261d6d555..2be95fc081 100644 --- a/indra/newview/skins/default/xui/en/panel_sidetray_home_tab.xml +++ b/indra/newview/skins/default/xui/en/panel_sidetray_home_tab.xml @@ -17,6 +17,7 @@ left="10" name="stack" top_pad="10" + orientation="vertical" width="313"> <layout_panel height="550" diff --git a/indra/newview/skins/default/xui/en/widgets/check_box.xml b/indra/newview/skins/default/xui/en/widgets/check_box.xml index 726ae803fe..7a60bee338 100644 --- a/indra/newview/skins/default/xui/en/widgets/check_box.xml +++ b/indra/newview/skins/default/xui/en/widgets/check_box.xml @@ -1,9 +1,9 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<check_box text_enabled_color="LabelTextColor" - text_disabled_color="LabelDisabledColor" - font="SansSerifSmall" +<check_box font="SansSerifSmall" follows="left|top"> - <check_box.label_text name="checkbox label" /> + <check_box.label_text name="checkbox label" + text_color="LabelTextColor" + text_readonly_color="LabelDisabledColor"/> <check_box.check_button name="CheckboxCtrl Button" commit_on_return="false" label="" |