diff --git a/indra/llui/llalertdialog.cpp b/indra/llui/llalertdialog.cpp index 712683021..7015e9c6a 100644 --- a/indra/llui/llalertdialog.cpp +++ b/indra/llui/llalertdialog.cpp @@ -107,7 +107,7 @@ static const LLFONT_ID FONT_NAME = LLFONT_SANSSERIF; LLAlertDialog::LLAlertDialog( LLNotificationPtr notification, bool modal) : LLModalDialog( notification->getLabel(), 100, 100, modal ), // dummy size. Will reshape below. LLInstanceTracker(notification->getID()), - mDefaultOption( 0 ), + mDefaultButton( NULL ), mCheck(NULL), mCaution(notification->getPriority() >= NOTIFICATION_PRIORITY_HIGH), mLabel(notification->getName()), @@ -126,35 +126,24 @@ LLAlertDialog::LLAlertDialog( LLNotificationPtr notification, bool modal) setBackgroundVisible(TRUE); setBackgroundOpaque(TRUE); - - typedef std::vector > options_t; - options_t supplied_options; + typedef std::list options_t; + options_t options; // for now, get LLSD to iterator over form elements LLSD form_sd = form->asLLSD(); - S32 option_index = 0; for (LLSD::array_const_iterator it = form_sd.beginArray(); it != form_sd.endArray(); ++it) { std::string type = (*it)["type"].asString(); if (type == "button") { - if((*it)["default"]) - { - mDefaultOption = option_index; - } - - supplied_options.push_back(std::make_pair((*it)["name"].asString(), (*it)["text"].asString())); - - ButtonData data; - data.mSelf = this; - if (option_index == mNote->getURLOption()) - { - data.mURL = mNote->getURL(); - } - - mButtonData.push_back(data); - option_index++; + options.push_back(ButtonData()); + ButtonData& button_data = options.back(); + button_data.mName = (*it)["name"].asString(); + button_data.mText = (*it)["text"].asString(); + button_data.mDefault = (*it)["default"].asBoolean(); + if(options.size()-1 == mNote->getURLOption()) + button_data.mUrl = mNote->getURL(); } else if (type == "text") { @@ -168,23 +157,14 @@ LLAlertDialog::LLAlertDialog( LLNotificationPtr notification, bool modal) is_password = true; } } - // Buttons - options_t options; - if (supplied_options.empty()) + if (options.empty()) { - options.push_back(std::make_pair(std::string("close"), std::string("Close"))); - - // add data for ok button. - ButtonData ok_button; - ok_button.mSelf = this; - - mButtonData.push_back(ok_button); - mDefaultOption = 0; - } - else - { - options = supplied_options; + options.push_back(ButtonData()); + ButtonData& button_data = options.back(); + button_data.mName = "close"; + button_data.mText = "Close"; + button_data.mDefault = true; } S32 num_options = options.size(); @@ -192,9 +172,9 @@ LLAlertDialog::LLAlertDialog( LLNotificationPtr notification, bool modal) // Calc total width of buttons S32 button_width = 0; S32 sp = font->getWidth(std::string("OO")); - for( S32 i = 0; i < num_options; i++ ) + for( options_t::iterator it = options.begin(); it != options.end(); it++ ) { - S32 w = S32(font->getWidth( options[i].second ) + 0.99f) + sp + 2 * LLBUTTON_H_PAD; + S32 w = S32(font->getWidth( it->mText ) + 0.99f) + sp + 2 * LLBUTTON_H_PAD; button_width = llmax( w, button_width ); } S32 btn_total_width = button_width; @@ -261,33 +241,37 @@ LLAlertDialog::LLAlertDialog( LLNotificationPtr notification, bool modal) // Buttons S32 button_left = (getRect().getWidth() - btn_total_width) / 2; - for( S32 i = 0; i < num_options; i++ ) + for( options_t::iterator it = options.begin(); it != options.end(); it++ ) { LLRect button_rect; button_rect.setOriginAndSize( button_left, VPAD, button_width, BTN_HEIGHT ); + ButtonData& button_data = *it; + LLButton* btn = new LLButton( - options[i].first, button_rect, + button_data.mName, button_rect, "","", "", - NULL, NULL, + NULL, font, - options[i].second, - options[i].second); + button_data.mText, + button_data.mText); - mButtonData[i].mButton = btn; - - btn->setClickedCallback(&LLAlertDialog::onButtonPressed, (void*)(&mButtonData[i])); + btn->setClickedCallback(boost::bind(&LLAlertDialog::onButtonPressed, this, _1, button_data.mUrl)); addChild(btn); - if( i == mDefaultOption ) + if(!mDefaultButton || button_data.mDefault) { - btn->setFocus(TRUE); + mDefaultButton = btn; } button_left += button_width + BTN_HPAD; } + llassert(mDefaultButton); //'options' map should never be empty, thus mDefaultButton should always get set in the above loop. + mDefaultButton->setFocus(TRUE); + + // (Optional) Edit Box if (!edit_text_name.empty()) { @@ -346,7 +330,7 @@ bool LLAlertDialog::show() mLineEditor->setFocus(TRUE); mLineEditor->selectAll(); } - if(mDefaultOption >= 0) + if(mDefaultButton) { // delay before enabling default button mDefaultBtnTimer.start(DEFAULT_BUTTON_DELAY); @@ -385,7 +369,7 @@ bool LLAlertDialog::setCheckBox( const std::string& check_title, const std::stri check_rect.setOriginAndSize(msg_x, VPAD+BTN_HEIGHT+LINE_HEIGHT/2, max_msg_width, LINE_HEIGHT); - mCheck = new LLCheckboxCtrl(std::string("check"), check_rect, check_title, font, onClickIgnore, this); + mCheck = new LLCheckboxCtrl(std::string("check"), check_rect, check_title, font, boost::bind(&LLAlertDialog::onClickIgnore, this, _1)); addChild(mCheck); return true; @@ -402,8 +386,49 @@ void LLAlertDialog::setVisible( BOOL visible ) } } +//Fixing a hole in alert logic. If the alert isn't modal, clicking 'x' to close its floater would result +//in a dangling notification. To address this we try to find the most reasonable button to emulate clicking. +//Close tends to be the best, as it's most accurate, and is the default for alerts that lack defined buttons. +//Next up is cancel, which is the correct behavior for a majority of alert notifications +//After that, try 'ok', which is the only button that exists for a few alert notifications. 'ok' for these equates to 'dismiss'. +//Finally, if none of the above are found, issue the respond procedure with the dummy button name 'close'. void LLAlertDialog::onClose(bool app_quitting) { + if(mNote.get() && !mNote->isRespondedTo() && !mNote->isIgnored()) + { + LLButton* btn = NULL; + bool found_cancel = false; + for(child_list_const_iter_t it = beginChild(); it != endChild(); ++it) + { + LLButton* cur_btn = dynamic_cast(*it); + if(!cur_btn) + continue; + if( LLStringUtil::compareInsensitive(cur_btn->getName(), "close") == 0 )//prefer 'close' over anything else. + { + btn = cur_btn; + break; + } + else if(LLStringUtil::compareInsensitive(cur_btn->getName(), "cancel") == 0 )//prefer 'cancel' over 'ok'. + { + btn = cur_btn; + found_cancel = true; + } + else if(!found_cancel && LLStringUtil::compareInsensitive(cur_btn->getName(), "ok") == 0 )//accept 'ok' as last resort. + { + btn = cur_btn; + } + } + LLSD response = mNote->getResponseTemplate(); + if(btn) + response[btn->getName()] = true; + else + { //We found no acceptable button so just feed it a fake one. + //LLNotification::getSelectedOption will return -1 in notification callbacks. + response["Close"] = true; + } + mNote->respond(response); + + } LLModalDialog::onClose(app_quitting); } @@ -458,7 +483,7 @@ void LLAlertDialog::draw() if(mDefaultBtnTimer.hasExpired() && mDefaultBtnTimer.getStarted()) { mDefaultBtnTimer.stop(); // prevent this block from being run more than once - setDefaultBtn(mButtonData[mDefaultOption].mButton); + setDefaultBtn(mDefaultButton); } static LLColor4 shadow_color = LLUI::sColorsGroup->getColor("ColorDropShadow"); @@ -483,44 +508,37 @@ void LLAlertDialog::setEditTextArgs(const LLSD& edit_args) } } -// static -void LLAlertDialog::onButtonPressed( void* userdata ) +void LLAlertDialog::onButtonPressed( LLUICtrl* ctrl, const std::string url ) { - ButtonData* button_data = (ButtonData*)userdata; - LLAlertDialog* self = button_data->mSelf; - - LLSD response = self->mNote->getResponseTemplate(); - if (self->mLineEditor) + LLSD response = mNote->getResponseTemplate(); + if (mLineEditor) { - response[self->mLineEditor->getName()] = self->mLineEditor->getValue(); + response[mLineEditor->getName()] = mLineEditor->getValue(); } - response[button_data->mButton->getName()] = true; + response[ctrl->getName()] = true; // If we declared a URL and chose the URL option, go to the url - if (!button_data->mURL.empty() && sURLLoader != NULL) + if (!url.empty() && sURLLoader != NULL) { - sURLLoader->load(button_data->mURL); + sURLLoader->load(url); } - self->mNote->respond(response); // new notification reponse - self->close(); // deletes self + mNote->respond(response); // new notification reponse + close(); // deletes self } -//static -void LLAlertDialog::onClickIgnore(LLUICtrl* ctrl, void* user_data) +void LLAlertDialog::onClickIgnore(LLUICtrl* ctrl) { - LLAlertDialog* self = (LLAlertDialog*)user_data; - // checkbox sometimes means "hide and do the default" and // other times means "warn me again". Yuck. JC BOOL check = ctrl->getValue(); - if (self->mNote->getForm()->getIgnoreType() == LLNotificationForm::IGNORE_SHOW_AGAIN) + if (mNote->getForm()->getIgnoreType() == LLNotificationForm::IGNORE_SHOW_AGAIN) { // question was "show again" so invert value to get "ignore" check = !check; } - self->mNote->setIgnored(check); + mNote->setIgnored(check); } diff --git a/indra/llui/llalertdialog.h b/indra/llui/llalertdialog.h index 04caea651..799ab8a80 100644 --- a/indra/llui/llalertdialog.h +++ b/indra/llui/llalertdialog.h @@ -87,8 +87,8 @@ public: //statics static void initClass(); static bool onNewNotification(const LLSD& notify, bool is_modal); - static void onButtonPressed(void* userdata); - static void onClickIgnore(LLUICtrl* ctrl, void* user_data); + void onButtonPressed( LLUICtrl* ctrl, const std::string url ); + void onClickIgnore( LLUICtrl* ctrl ); private: LLNotificationPtr mNote; @@ -102,18 +102,18 @@ private: BOOL hasTitleBar() const; private: + struct ButtonData + { + std::string mName; + std::string mText; + bool mDefault; + std::string mUrl; + }; + static URLLoader* sURLLoader; static LLControlGroup* sSettings; - struct ButtonData - { - LLAlertDialog* mSelf; - LLButton* mButton; - std::string mURL; - }; - std::vector mButtonData; - - S32 mDefaultOption; + LLButton* mDefaultButton; LLCheckBoxCtrl* mCheck; BOOL mCaution; BOOL mUnique; diff --git a/indra/newview/llviewerparcelmedia.cpp b/indra/newview/llviewerparcelmedia.cpp index b95a96ad3..ee56d7b5d 100644 --- a/indra/newview/llviewerparcelmedia.cpp +++ b/indra/newview/llviewerparcelmedia.cpp @@ -123,7 +123,7 @@ void LLViewerParcelMedia::update(LLParcel* parcel) if( ! mediaUrl.empty() && gSavedSettings.getWarning("FirstStreamingVideo") ) { LLNotificationsUtil::add("ParcelCanPlayMedia", LLSD(), LLSD(), - boost::bind(callback_play_media, _1, _2, parcel)); + boost::bind(&callback_play_media, _1, _2, parcel)); return; } @@ -903,35 +903,43 @@ void callback_media_alert(const LLSD ¬ification, const LLSD &response, LLParc LLViewerParcelMedia::playStreamingMusic(parcel, false); } } - else if (option == 1 || option == 2) // Deny or Blacklist + else { - LLViewerParcelMedia::sDeniedMedia.insert(domain); - if (ip != domain && domain.find('/') == std::string::npos) - { - LLViewerParcelMedia::sDeniedMedia.insert(ip); - } if (type == 1) { LLViewerParcelMedia::stopStreamingMusic(); } - if (option == 1) // Deny + else { - LLNotificationsUtil::add("MediaBlocked", args); + LLViewerParcelMedia::stopStreamingMusic(); } - else // Blacklist + if (option == 1 || option == 2) // Deny or Blacklist { - LLSD newmedia; - newmedia["domain"] = domain; - newmedia["action"] = "deny"; - LLViewerParcelMedia::sMediaFilterList.append(newmedia); + LLViewerParcelMedia::sDeniedMedia.insert(domain); if (ip != domain && domain.find('/') == std::string::npos) { - newmedia["domain"] = ip; - LLViewerParcelMedia::sMediaFilterList.append(newmedia); + LLViewerParcelMedia::sDeniedMedia.insert(ip); + } + + if (option == 1) // Deny + { + LLNotificationsUtil::add("MediaBlocked", args); + } + else // Blacklist + { + LLSD newmedia; + newmedia["domain"] = domain; + newmedia["action"] = "deny"; + LLViewerParcelMedia::sMediaFilterList.append(newmedia); + if (ip != domain && domain.find('/') == std::string::npos) + { + newmedia["domain"] = ip; + LLViewerParcelMedia::sMediaFilterList.append(newmedia); + } + LLViewerParcelMedia::saveDomainFilterList(); + args["LISTED"] = "blacklisted"; + LLNotificationsUtil::add("MediaListed", args); } - LLViewerParcelMedia::saveDomainFilterList(); - args["LISTED"] = "blacklisted"; - LLNotificationsUtil::add("MediaListed", args); } }