diff options
26 files changed, 665 insertions, 63 deletions
| diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp index 7bafd711cb..2e6dc6731b 100644 --- a/indra/llui/llnotifications.cpp +++ b/indra/llui/llnotifications.cpp @@ -68,7 +68,8 @@ LLNotificationForm::FormIgnore::FormIgnore()  	control("control"),  	invert_control("invert_control", false),  	save_option("save_option", false), -	session_only("session_only", false) +	session_only("session_only", false), +	checkbox_only("checkbox_only", false)  {}  LLNotificationForm::FormButton::FormButton() @@ -195,9 +196,14 @@ LLNotificationForm::LLNotificationForm(const std::string& name, const LLNotifica  {  	if (p.ignore.isProvided())  	{ +		// For all cases but IGNORE_CHECKBOX_ONLY this is name for use in preferences  		mIgnoreMsg = p.ignore.text; -		if (!p.ignore.save_option) +		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;  		} @@ -214,7 +220,7 @@ LLNotificationForm::LLNotificationForm(const std::string& name, const LLNotifica  			mIgnoreSetting = LLUI::sSettingGroups["config"]->getControl(p.ignore.control);  			mInvertSetting = p.ignore.invert_control;  		} -		else +		else if (mIgnore > IGNORE_NO)  		{  			LLUI::sSettingGroups["ignores"]->declareBOOL(name, show_notification, "Show notification with this name", LLControlVariable::PERSIST_NONDFT);  			mIgnoreSetting = LLUI::sSettingGroups["ignores"]->getControl(name); @@ -388,13 +394,12 @@ LLControlVariablePtr LLNotificationForm::getIgnoreSetting()  bool LLNotificationForm::getIgnored()  {  	bool show = true; -	if (mIgnore != LLNotificationForm::IGNORE_NO +	if (mIgnore > LLNotificationForm::IGNORE_NO  		&& mIgnoreSetting)   	{  		show = mIgnoreSetting->getValue().asBoolean();  		if (mInvertSetting) show = !show;  	} -  	return !show;  } @@ -695,7 +700,7 @@ void LLNotification::respond(const LLSD& response)  		mTemporaryResponder = false;  	} -	if (mForm->getIgnoreType() != LLNotificationForm::IGNORE_NO) +	if (mForm->getIgnoreType() > LLNotificationForm::IGNORE_NO)  	{  		mForm->setIgnored(mIgnored);  		if (mIgnored && mForm->getIgnoreType() == LLNotificationForm::IGNORE_WITH_LAST_RESPONSE) diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h index 1509446920..62cf41256b 100644 --- a/indra/llui/llnotifications.h +++ b/indra/llui/llnotifications.h @@ -180,6 +180,7 @@ public:  		Optional<std::string>	control;  		Optional<bool>			invert_control;  		Optional<bool>			session_only; +		Optional<bool>			checkbox_only;  		FormIgnore();  	}; @@ -232,7 +233,8 @@ public:  	typedef enum e_ignore_type  	{  -		IGNORE_NO, +		IGNORE_CHECKBOX_ONLY = -1, // ignore won't be handled, will set value/checkbox only +		IGNORE_NO = 0,  		IGNORE_WITH_DEFAULT_RESPONSE,  		IGNORE_WITH_DEFAULT_RESPONSE_SESSION_ONLY,  		IGNORE_WITH_LAST_RESPONSE,  diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 0ca5a08dfc..95a916d7cb 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -664,6 +664,7 @@ set(viewer_SOURCE_FILES      llviewerobject.cpp      llviewerobjectlist.cpp      llvieweroctree.cpp +    llviewerparcelaskplay.cpp      llviewerparcelmedia.cpp      llviewerparcelmediaautoplay.cpp      llviewerparcelmgr.cpp @@ -1284,6 +1285,7 @@ set(viewer_HEADER_FILES      llviewerobject.h      llviewerobjectlist.h      llvieweroctree.h +    llviewerparcelaskplay.h      llviewerparcelmedia.h      llviewerparcelmediaautoplay.h      llviewerparcelmgr.h diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index f54f683757..b9cb613b96 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -7494,11 +7494,11 @@      <key>ParcelMediaAutoPlayEnable</key>      <map>        <key>Comment</key> -      <string>Auto play parcel media when available</string> +      <string>Auto play parcel media when available. 0 - Do not autoplay; 1- Autoplay; 2 - Ask</string>        <key>Persist</key>        <integer>1</integer>        <key>Type</key> -      <string>Boolean</string> +      <string>S32</string>        <key>Value</key>        <integer>1</integer>      </map> diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 22bcbad7da..18c0cedba8 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -1713,6 +1713,24 @@ void LLAppearanceMgr::slamCategoryLinks(const LLUUID& src_id, const LLUUID& dst_  	LLInventoryModel::item_array_t* items;  	LLSD contents = LLSD::emptyArray();  	gInventory.getDirectDescendentsOf(src_id, cats, items); +	if (!cats || !items) +	{ +		// NULL means the call failed -- cats/items map doesn't exist (note: this does NOT mean +		// that the cat just doesn't have any items or subfolders). +		LLViewerInventoryCategory* category = gInventory.getCategory(src_id); +		if (category) +		{ +			LL_WARNS() << "Category '" << category->getName() << "' descendents corrupted, linking content failed." << LL_ENDL; +		} +		else +		{ +			LL_WARNS() << "Category could not be retrieved, linking content failed." << LL_ENDL; +		} +		llassert(cats != NULL && items != NULL); + +		return; +	} +  	LL_INFOS() << "copying " << items->size() << " items" << LL_ENDL;  	for (LLInventoryModel::item_array_t::const_iterator iter = items->begin();  		 iter != items->end(); diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 12a459b2b8..2a928a47a2 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -68,6 +68,7 @@  #include "llviewerwindow.h"  #include "llviewerdisplay.h"  #include "llviewermedia.h" +#include "llviewerparcelaskplay.h"  #include "llviewerparcelmedia.h"  #include "llviewermediafocus.h"  #include "llviewermessage.h" @@ -1938,6 +1939,11 @@ bool LLAppViewer::cleanup()  	{  		gSavedPerAccountSettings.saveToFile(gSavedSettings.getString("PerAccountSettingsFile"), TRUE);  		LL_INFOS() << "Saved settings" << LL_ENDL; + +		if (LLViewerParcelAskPlay::instanceExists()) +		{ +			LLViewerParcelAskPlay::getInstance()->saveSettings(); +		}  	}  	std::string warnings_settings_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, getSettingsFilename("Default", "Warnings")); diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 9d0e1972a3..b48495b5b2 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -1242,7 +1242,7 @@ void LLFloaterPreference::buildPopupLists()  		LLNotificationFormPtr formp = templatep->mForm;  		LLNotificationForm::EIgnoreType ignore = formp->getIgnoreType(); -		if (ignore == LLNotificationForm::IGNORE_NO) +		if (ignore <= LLNotificationForm::IGNORE_NO)  			continue;  		LLSD row; @@ -1824,7 +1824,7 @@ void LLFloaterPreference::resetAllIgnored()  		 iter != LLNotifications::instance().templatesEnd();  		 ++iter)  	{ -		if (iter->second->mForm->getIgnoreType() != LLNotificationForm::IGNORE_NO) +		if (iter->second->mForm->getIgnoreType() > LLNotificationForm::IGNORE_NO)  		{  			iter->second->mForm->setIgnored(false);  		} @@ -1837,7 +1837,7 @@ void LLFloaterPreference::setAllIgnored()  		 iter != LLNotifications::instance().templatesEnd();  		 ++iter)  	{ -		if (iter->second->mForm->getIgnoreType() != LLNotificationForm::IGNORE_NO) +		if (iter->second->mForm->getIgnoreType() > LLNotificationForm::IGNORE_NO)  		{  			iter->second->mForm->setIgnored(true);  		} @@ -2674,7 +2674,7 @@ void LLPanelPreference::updateMediaAutoPlayCheckbox(LLUICtrl* ctrl)  		bool music_enabled = getChild<LLCheckBoxCtrl>("enable_music")->get();  		bool media_enabled = getChild<LLCheckBoxCtrl>("enable_media")->get(); -		getChild<LLCheckBoxCtrl>("media_auto_play_btn")->setEnabled(music_enabled || media_enabled); +		getChild<LLCheckBoxCtrl>("media_auto_play_combo")->setEnabled(music_enabled || media_enabled);  	}  } diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index 8345ad1bb6..4412c95473 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -168,7 +168,6 @@ public:  	void refreshUI(); -	void onCommitParcelMediaAutoPlayEnable();  	void onCommitMediaEnabled();  	void onCommitMusicEnabled();  	void applyResolution(); diff --git a/indra/newview/llimprocessing.cpp b/indra/newview/llimprocessing.cpp index 5b9ef7e60a..42043a03f2 100644 --- a/indra/newview/llimprocessing.cpp +++ b/indra/newview/llimprocessing.cpp @@ -29,6 +29,7 @@  #include "llimprocessing.h"  #include "llagent.h" +#include "llappviewer.h"  #include "llavatarnamecache.h"  #include "llfirstuse.h"  #include "llfloaterreg.h" @@ -1474,6 +1475,7 @@ void LLIMProcessing::requestOfflineMessages()      static BOOL requested = FALSE;      if (!requested          && gMessageSystem +        && !gDisconnected          && LLMuteList::getInstance()->isLoaded()          && isAgentAvatarValid()          && gAgent.getRegion() diff --git a/indra/newview/llpanelnearbymedia.cpp b/indra/newview/llpanelnearbymedia.cpp index f3a2ed9408..af28ff8e61 100644 --- a/indra/newview/llpanelnearbymedia.cpp +++ b/indra/newview/llpanelnearbymedia.cpp @@ -43,6 +43,7 @@  #include "llbutton.h"  #include "lltextbox.h"  #include "llviewermedia.h" +#include "llviewerparcelaskplay.h"  #include "llviewerparcelmedia.h"  #include "llviewerregion.h"  #include "llviewermediafocus.h" @@ -83,10 +84,11 @@ LLPanelNearByMedia::LLPanelNearByMedia()  {  	mHoverTimer.stop(); -	mParcelAudioAutoStart = gSavedSettings.getBOOL(LLViewerMedia::AUTO_PLAY_MEDIA_SETTING) && -							gSavedSettings.getBOOL("MediaTentativeAutoPlay"); +    // This is just an initial value, mParcelAudioAutoStart does not affect ParcelMediaAutoPlayEnable +    mParcelAudioAutoStart = gSavedSettings.getS32("ParcelMediaAutoPlayEnable") != 0 +                            && gSavedSettings.getBOOL("MediaTentativeAutoPlay"); -	gSavedSettings.getControl(LLViewerMedia::AUTO_PLAY_MEDIA_SETTING)->getSignal()->connect(boost::bind(&LLPanelNearByMedia::handleMediaAutoPlayChanged, this, _2)); +    gSavedSettings.getControl("ParcelMediaAutoPlayEnable")->getSignal()->connect(boost::bind(&LLPanelNearByMedia::handleMediaAutoPlayChanged, this, _2));  	mCommitCallbackRegistrar.add("MediaListCtrl.EnableAll",		boost::bind(&LLPanelNearByMedia::onClickEnableAll, this));  	mCommitCallbackRegistrar.add("MediaListCtrl.DisableAll",		boost::bind(&LLPanelNearByMedia::onClickDisableAll, this)); @@ -177,9 +179,18 @@ BOOL LLPanelNearByMedia::postBuild()  void LLPanelNearByMedia::handleMediaAutoPlayChanged(const LLSD& newvalue)  { -	// update mParcelAudioAutoStart if AUTO_PLAY_MEDIA_SETTING changes -	mParcelAudioAutoStart = gSavedSettings.getBOOL(LLViewerMedia::AUTO_PLAY_MEDIA_SETTING) && -							gSavedSettings.getBOOL("MediaTentativeAutoPlay"); +	// update mParcelAudioAutoStartMode if "ParcelMediaAutoPlayEnable" changes +    S32 value = gSavedSettings.getS32("ParcelMediaAutoPlayEnable"); +    mParcelAudioAutoStart = value != 0 +                            && gSavedSettings.getBOOL("MediaTentativeAutoPlay"); + +    LLViewerParcelAskPlay *inst = LLViewerParcelAskPlay::getInstance(); +    if (value == 2 && !inst->hasData()) +    { +        // Init if nessesary +        inst->loadSettings(); +    } +    inst->cancelNotification();  }  /*virtual*/ diff --git a/indra/newview/llpanelplaces.cpp b/indra/newview/llpanelplaces.cpp index 48dd45480e..25961e0054 100644 --- a/indra/newview/llpanelplaces.cpp +++ b/indra/newview/llpanelplaces.cpp @@ -675,6 +675,12 @@ void LLPanelPlaces::onShowOnMapButtonClicked()  		}  		else if (mPlaceInfoType == LANDMARK_INFO_TYPE)  		{ +			if (mItem.isNull()) +			{ +				LL_WARNS() << "NULL landmark item" << LL_ENDL; +				llassert(mItem.notNull()); +				return; +			}  			LLLandmark* landmark = gLandmarkList.getAsset(mItem->getAssetUUID());  			if (!landmark)  				return; diff --git a/indra/newview/llpanelvolumepulldown.cpp b/indra/newview/llpanelvolumepulldown.cpp index 6792137350..f063d84272 100644 --- a/indra/newview/llpanelvolumepulldown.cpp +++ b/indra/newview/llpanelvolumepulldown.cpp @@ -140,7 +140,7 @@ void LLPanelVolumePulldown::updateMediaAutoPlayCheckbox(LLUICtrl* ctrl)  		bool music_enabled = getChild<LLCheckBoxCtrl>("enable_music")->get();  		bool media_enabled = getChild<LLCheckBoxCtrl>("enable_media")->get(); -		getChild<LLCheckBoxCtrl>("media_auto_play_btn")->setEnabled(music_enabled || media_enabled); +		getChild<LLCheckBoxCtrl>("media_auto_play_combo")->setEnabled(music_enabled || media_enabled);  	}  } diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 77aa7b36b9..5f235c05a6 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -158,6 +158,7 @@  #include "llviewermessage.h"  #include "llviewernetwork.h"  #include "llviewerobjectlist.h" +#include "llviewerparcelaskplay.h"  #include "llviewerparcelmedia.h"  #include "llviewerparcelmgr.h"  #include "llviewerregion.h" @@ -1425,6 +1426,10 @@ bool idle_startup()  		// create a container's instance for start a controlling conversation windows  		// by the voice's events  		LLFloaterIMContainer::getInstance(); +		if (gSavedSettings.getS32("ParcelMediaAutoPlayEnable") == 2) +		{ +			LLViewerParcelAskPlay::getInstance()->loadSettings(); +		}  		// *Note: this is where gWorldMap used to be initialized. diff --git a/indra/newview/lltoastalertpanel.cpp b/indra/newview/lltoastalertpanel.cpp index 023d1a685c..8df83c64cd 100644 --- a/indra/newview/lltoastalertpanel.cpp +++ b/indra/newview/lltoastalertpanel.cpp @@ -34,7 +34,6 @@  #include "llfontgl.h"  #include "lltextbox.h"  #include "llbutton.h" -#include "llcheckboxctrl.h"  #include "llkeyboard.h"  #include "llfocusmgr.h"  #include "lliconctrl.h" diff --git a/indra/newview/lltoastnotifypanel.cpp b/indra/newview/lltoastnotifypanel.cpp index 65684dc2fd..bccf88128d 100644 --- a/indra/newview/lltoastnotifypanel.cpp +++ b/indra/newview/lltoastnotifypanel.cpp @@ -163,6 +163,11 @@ void LLToastNotifyPanel::updateButtonsLayout(const std::vector<index_button_pair  		{  			left = (max_width - btn_rect.getWidth()) / 2;  		} +		else if (left == 0 && buttons.size() == 2) +		{ +			// Note: this and "size() == 1" shouldn't be inside the cycle, might be good idea to refactor whole placing process +			left = (max_width - (btn_rect.getWidth() * 2) - h_pad) / 2; +		}  		else if (left + btn_rect.getWidth() > max_width)// whether there is still some place for button+h_pad in the mControlPanel  		{  			// looks like we need to add button to the next row @@ -411,14 +416,17 @@ void LLToastNotifyPanel::init( LLRect rect, bool show_images )  	//can shift upward making room for the buttons inside mControlPanel. After the buttons are added, the info panel can then be set to follow 'all'.  	mInfoPanel->setFollowsAll(); -    // Add checkboxes if nessesary. -    setCheckBoxes(HPAD * 3, VPAD * 4, mInfoPanel); - +    // Add checkbox (one of couple types) if nessesary. +    setCheckBoxes(HPAD * 2, 0, mInfoPanel); +    if (mCheck) +    { +        mCheck->setFollows(FOLLOWS_BOTTOM | FOLLOWS_LEFT); +    }      // Snap to message, then to checkbox if present      snapToMessageHeight(mTextBox, LLToastPanel::MAX_TEXT_LENGTH);      if (mCheck)      { -        S32 new_panel_height = mCheck->getRect().getHeight() + getRect().getHeight(); +        S32 new_panel_height = mCheck->getRect().getHeight() + getRect().getHeight() + VPAD;          reshape(getRect().getWidth(), new_panel_height);      } diff --git a/indra/newview/lltoastpanel.cpp b/indra/newview/lltoastpanel.cpp index d69f918a54..100d5ee713 100644 --- a/indra/newview/lltoastpanel.cpp +++ b/indra/newview/lltoastpanel.cpp @@ -161,7 +161,20 @@ void LLCheckBoxToastPanel::setCheckBoxes(const S32 &h_pad, const S32 &v_pad, LLV      std::string ignore_label;      LLNotificationFormPtr form = mNotification->getForm(); -    if (form->getIgnoreType() == LLNotificationForm::IGNORE_WITH_DEFAULT_RESPONSE) +    if (form->getIgnoreType() == LLNotificationForm::IGNORE_CHECKBOX_ONLY) +    { +        // Normally text is only used to describe notification in preferences,  +        // but this one is not displayed in preferences and works on case by case +        // basis. +        // Display text if present, display 'always chose' if not. +        std::string ignore_message = form->getIgnoreMessage(); +        if (ignore_message.empty()) +        { +            ignore_message = LLNotifications::instance().getGlobalString("alwayschoose"); +        } +        setCheckBox(ignore_message, ignore_label, boost::bind(&LLCheckBoxToastPanel::onCommitCheckbox, this, _1), h_pad, v_pad, parent_view); +    } +    else if (form->getIgnoreType() == LLNotificationForm::IGNORE_WITH_DEFAULT_RESPONSE)      {          setCheckBox(LLNotifications::instance().getGlobalString("skipnexttime"), ignore_label, boost::bind(&LLCheckBoxToastPanel::onCommitCheckbox, this, _1), h_pad, v_pad, parent_view);      } @@ -211,7 +224,9 @@ bool LLCheckBoxToastPanel::setCheckBox(const std::string& check_title,      // set check_box's attributes      LLRect check_rect; -    mCheck->setRect(check_rect.setOriginAndSize(msg_x, v_pad + BTN_HEIGHT + LINE_HEIGHT / 2, max_msg_width, LINE_HEIGHT*lines.size())); +    // if we are part of the toast, we need to leave space for buttons +    S32 msg_y = v_pad + (parent_view ? 0 : (BTN_HEIGHT + LINE_HEIGHT / 2)); +    mCheck->setRect(check_rect.setOriginAndSize(msg_x, msg_y, max_msg_width, LINE_HEIGHT*lines.size()));      mCheck->setLabel(check_title);      mCheck->setCommitCallback(cb); diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index a9eb79b649..c97a42bf06 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -57,6 +57,7 @@  #include "llviewercontrol.h"  #include "llviewermenufile.h" // LLFilePickerThread  #include "llviewernetwork.h" +#include "llviewerparcelaskplay.h"  #include "llviewerparcelmedia.h"  #include "llviewerparcelmgr.h"  #include "llviewerregion.h" @@ -77,7 +78,6 @@  #include <boost/bind.hpp>	// for SkinFolder listener  #include <boost/signals2.hpp> -/*static*/ const char* LLViewerMedia::AUTO_PLAY_MEDIA_SETTING = "ParcelMediaAutoPlayEnable";  /*static*/ const char* LLViewerMedia::SHOW_MEDIA_ON_OTHERS_SETTING = "MediaShowOnOthers";  /*static*/ const char* LLViewerMedia::SHOW_MEDIA_WITHIN_PARCEL_SETTING = "MediaShowWithinParcel";  /*static*/ const char* LLViewerMedia::SHOW_MEDIA_OUTSIDE_PARCEL_SETTING = "MediaShowOutsideParcel"; @@ -1005,12 +1005,14 @@ void LLViewerMedia::setAllMediaPaused(bool val)          }      } +    LLParcel *agent_parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); +      // Also do Parcel Media and Parcel Audio      if (!val)      {          if (!LLViewerMedia::isParcelMediaPlaying() && LLViewerMedia::hasParcelMedia())          { -            LLViewerParcelMedia::play(LLViewerParcelMgr::getInstance()->getAgentParcel()); +            LLViewerParcelMedia::play(agent_parcel);          }          static LLCachedControl<bool> audio_streaming_music(gSavedSettings, "AudioStreamingMusic", true); @@ -1038,6 +1040,12 @@ void LLViewerMedia::setAllMediaPaused(bool val)              LLViewerAudio::getInstance()->stopInternetStreamWithAutoFade();          }      } + +    // remove play choice for current parcel +    if (agent_parcel && gAgent.getRegion()) +    { +        LLViewerParcelAskPlay::getInstance()->resetSetting(gAgent.getRegion()->getRegionID(), agent_parcel->getLocalID()); +    }  }  ////////////////////////////////////////////////////////////////////////////////////////// @@ -3777,7 +3785,7 @@ void LLViewerMediaImpl::setTextureID(LLUUID id)  bool LLViewerMediaImpl::isAutoPlayable() const  {  	return (mMediaAutoPlay && -			gSavedSettings.getBOOL(LLViewerMedia::AUTO_PLAY_MEDIA_SETTING) && +			gSavedSettings.getS32("ParcelMediaAutoPlayEnable") != 0 &&  			gSavedSettings.getBOOL("MediaTentativeAutoPlay"));  } diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h index bea024e952..03d97a3a72 100644 --- a/indra/newview/llviewermedia.h +++ b/indra/newview/llviewermedia.h @@ -76,7 +76,6 @@ class LLViewerMedia  public:  	// String to get/set media autoplay in gSavedSettings -	static const char* AUTO_PLAY_MEDIA_SETTING;  	static const char* SHOW_MEDIA_ON_OTHERS_SETTING;  	static const char* SHOW_MEDIA_WITHIN_PARCEL_SETTING;  	static const char* SHOW_MEDIA_OUTSIDE_PARCEL_SETTING; diff --git a/indra/newview/llviewerparcelaskplay.cpp b/indra/newview/llviewerparcelaskplay.cpp new file mode 100644 index 0000000000..d4aa783f12 --- /dev/null +++ b/indra/newview/llviewerparcelaskplay.cpp @@ -0,0 +1,301 @@ +/** + * @file llviewerparcelaskplay.cpp + * @brief stores data about parcel media user wants to auto-play and shows related notifications + * + * $LicenseInfo:firstyear=2019&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2019, 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" + +#include "llviewerparcelaskplay.h" + +#include "llnotifications.h" +#include "llnotificationsutil.h" +#include "llparcel.h" +#include "llstartup.h" +#include "llviewerparcelmgr.h" +#include "llviewerregion.h" +#include "llagent.h" +#include "llsdserialize.h" + +#include <boost/lexical_cast.hpp> + + +// class LLViewerParcelAskPlay + +LLViewerParcelAskPlay::LLViewerParcelAskPlay() : +pNotification(NULL) +{ +} + +LLViewerParcelAskPlay::~LLViewerParcelAskPlay() +{ + +} + +void LLViewerParcelAskPlay::initSingleton() +{ + +} +void LLViewerParcelAskPlay::cleanupSingleton() +{ +    cancelNotification(); +} + +void LLViewerParcelAskPlay::askToPlay(const LLUUID ®ion_id, const S32 &parcel_id, const std::string &url, ask_callback cb) +{ +    EAskPlayMode mode = getPlayMode(region_id, parcel_id); + +    switch (mode) +    { +    case ASK_PLAY_IGNORE: +        cb(region_id, parcel_id, url, false); +        break; +    case ASK_PLAY_PLAY: +        cb(region_id, parcel_id, url, true); +        break; +    case ASK_PLAY_ASK: +    default: +        { +            // create or re-create notification +            cancelNotification(); + +            if (LLStartUp::getStartupState() > STATE_PRECACHE) +            { +                LLSD args; +                args["URL"] = url; +                LLSD payload; +                payload["url"] = url; // or we can extract it from notification["substitutions"] +                payload["parcel_id"] = parcel_id; +                payload["region_id"] = region_id; +                pNotification = LLNotificationsUtil::add("ParcelPlayingMedia", args, payload, boost::bind(onAskPlayResponse, _1, _2, cb)); +            } +            else +            { +                // workaround: avoid 'new notifications arrived' on startup and just play +                // (alternative: move to different channel, may be create new one...) +                cb(region_id, parcel_id, url, true); +            } +        } +    } +} + +void LLViewerParcelAskPlay::cancelNotification() +{ +    if (pNotification) +    { +        if (!pNotification->isCancelled()) +        { +            // Force a responce +            // Alternative is to mark notification as unique +            pNotification->setIgnored(false); +            LLNotifications::getInstance()->cancel(pNotification); +        } +        pNotification = NULL; +    } +} + +void LLViewerParcelAskPlay::resetCurrentParcelSetting() +{ +    LLParcel *agent_parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); +    if (agent_parcel && gAgent.getRegion()) +    { +        LLViewerParcelAskPlay::resetSetting(gAgent.getRegion()->getRegionID(), agent_parcel->getLocalID()); +    } +} + +void LLViewerParcelAskPlay::resetSetting(const LLUUID ®ion_id, const S32 &parcel_id) +{ +    region_map_t::iterator found = mRegionMap.find(region_id); +    if (found != mRegionMap.end()) +    { +        found->second.erase(parcel_id); +    } +} + +void LLViewerParcelAskPlay::resetSettings() +{ +    if (LLViewerParcelAskPlay::instanceExists()) +    { +        LLViewerParcelAskPlay::getInstance()->mRegionMap.clear(); +    } +    LLFile::remove(getAskPlayFilename()); +} + +void LLViewerParcelAskPlay::setSetting(const LLUUID ®ion_id, const S32 &parcel_id, const LLViewerParcelAskPlay::ParcelData &data) +{ +    mRegionMap[region_id][parcel_id] = data; +} + +LLViewerParcelAskPlay::ParcelData* LLViewerParcelAskPlay::getSetting(const LLUUID ®ion_id, const S32 &parcel_id) +{ +    region_map_t::iterator found = mRegionMap.find(region_id); +    if (found != mRegionMap.end()) +    { +        parcel_data_map_t::iterator found_parcel = found->second.find(parcel_id); +        if (found_parcel != found->second.end()) +        { +            return &(found_parcel->second); +        } +    } +    return NULL; +} + +LLViewerParcelAskPlay::EAskPlayMode LLViewerParcelAskPlay::getPlayMode(const LLUUID ®ion_id, const S32 &parcel_id) +{ +    EAskPlayMode mode = ASK_PLAY_ASK; +    ParcelData* data = getSetting(region_id, parcel_id); +    if (data) +    { +        mode = data->mMode; +        // refresh date +        data->mDate = LLDate::now(); +    } +    return mode; +} + +void LLViewerParcelAskPlay::setPlayMode(const LLUUID ®ion_id, const S32 &parcel_id, LLViewerParcelAskPlay::EAskPlayMode mode) +{ +    ParcelData data; +    data.mMode = mode; +    data.mDate = LLDate::now(); +    setSetting(region_id, parcel_id, data); +} + +//static +void LLViewerParcelAskPlay::onAskPlayResponse(const LLSD& notification, const LLSD& response, ask_callback cb) +{ +    S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + +    LLUUID region_id = notification["payload"]["region_id"]; +    S32 parcel_id = notification["payload"]["parcel_id"]; +    std::string url = notification["payload"]["url"]; + +    bool play = option == 1; + +    cb(region_id, parcel_id, url, play); + +    LLViewerParcelAskPlay *inst = getInstance(); +    bool save_choice = inst->pNotification->isIgnored(); // checkbox selected +    if (save_choice) +    { +        EAskPlayMode mode = (play) ? ASK_PLAY_PLAY : ASK_PLAY_IGNORE; +        inst->setPlayMode(region_id, parcel_id, mode); +    } +} + +// static +std::string LLViewerParcelAskPlay::getAskPlayFilename() +{ +    return gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "media_autoplay.xml"); +} + +void LLViewerParcelAskPlay::loadSettings() +{ +    mRegionMap.clear(); + +    std::string path = getAskPlayFilename(); +    if (!gDirUtilp->fileExists(path)) +    { +        return; +    } + +    LLSD autoplay_llsd; +    llifstream file; +    file.open(path.c_str()); +    if (!file.is_open()) +    { +        return; +    } +    S32 status = LLSDSerialize::fromXML(autoplay_llsd, file); +    file.close(); + +    if (status == LLSDParser::PARSE_FAILURE || !autoplay_llsd.isMap()) +    { +        return; +    } + +    for (LLSD::map_const_iterator iter_region = autoplay_llsd.beginMap(); +        iter_region != autoplay_llsd.endMap(); ++iter_region) +    { +        LLUUID region_id = LLUUID(iter_region->first); +        mRegionMap[region_id] = parcel_data_map_t(); + +        const LLSD &parcel_map = iter_region->second; + +        if (parcel_map.isMap()) +        { +            for (LLSD::map_const_iterator iter_parcel = parcel_map.beginMap(); +                iter_parcel != parcel_map.endMap(); ++iter_parcel) +            { +                if (!iter_parcel->second.isMap()) +                { +                    break; +                } +                S32 parcel_id = boost::lexical_cast<S32>(iter_parcel->first.c_str()); +                ParcelData data; +                data.mMode = (EAskPlayMode)(iter_parcel->second["mode"].asInteger()); +                data.mDate = iter_parcel->second["date"].asDate(); +                mRegionMap[region_id][parcel_id] = data; +            } +        } +    } +} + +void LLViewerParcelAskPlay::saveSettings() +{ +    LLSD write_llsd; +    std::string key; +    for (region_map_t::iterator iter_region = mRegionMap.begin(); +        iter_region != mRegionMap.end(); ++iter_region) +    { +        if (iter_region->second.empty()) +        { +            continue; +        } +        key = iter_region->first.asString(); +        write_llsd[key] = LLSD(); +         +        for (parcel_data_map_t::iterator iter_parcel = iter_region->second.begin(); +            iter_parcel != iter_region->second.end(); ++iter_parcel) +        { +            if ((iter_parcel->second.mDate.secondsSinceEpoch() + (F64SecondsImplicit)U32Days(30)) > LLTimer::getTotalSeconds()) +            { +                // write unexpired parcels +                std::string parcel_id = boost::lexical_cast<std::string>(iter_parcel->first); +                write_llsd[key][parcel_id] = LLSD(); +                write_llsd[key][parcel_id]["mode"] = (LLSD::Integer)iter_parcel->second.mMode; +                write_llsd[key][parcel_id]["date"] = iter_parcel->second.mDate; +            } +        } +    } +     +    llofstream file; +    file.open(getAskPlayFilename().c_str()); +    if (file.is_open()) +    { +        LLSDSerialize::toPrettyXML(write_llsd, file); +        file.close(); +    } +} + diff --git a/indra/newview/llviewerparcelaskplay.h b/indra/newview/llviewerparcelaskplay.h new file mode 100644 index 0000000000..dc711917d2 --- /dev/null +++ b/indra/newview/llviewerparcelaskplay.h @@ -0,0 +1,89 @@ +/** + * @file llviewerparcelaskplay.h + * @brief stores data about parcel media user wants to auto-play and shows related notifications + * + * $LicenseInfo:firstyear=2019&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2019, 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 LLVIEWERPARCELASKPLAY_H +#define LLVIEWERPARCELASKPLAY_H + +#include "llnotificationptr.h" +#include "lluuid.h" + +class LLViewerParcelAskPlay : public LLSingleton<LLViewerParcelAskPlay> +{ +    LLSINGLETON(LLViewerParcelAskPlay); +    ~LLViewerParcelAskPlay(); +    void initSingleton(); +    void cleanupSingleton(); +public: +    // functor expects functor(region_id, parcel_id, url, play/stop) +    typedef boost::function<void(const LLUUID&, const S32&, const std::string&, const bool&)> ask_callback; +    void        askToPlay(const LLUUID ®ion_id, const S32 &parcel_id, const std::string &url, ask_callback cb); +    void        cancelNotification(); + +    void        resetCurrentParcelSetting(); +    void        resetSetting(const LLUUID ®ion_id, const S32 &parcel_id); +    static void resetSettings(); + +    void        loadSettings(); +    void        saveSettings(); + +    S32         hasData() { return !mRegionMap.empty(); } // subsitution for 'isInitialized' + +private: +    enum EAskPlayMode{ +        ASK_PLAY_IGNORE = 0, +        ASK_PLAY_PLAY, +        ASK_PLAY_ASK +    }; + +    class ParcelData +    { +    public: +        LLDate mDate; +        EAskPlayMode mMode; +    }; + +    void               setSetting(const LLUUID ®ion_id, const S32 &parcel_id, const ParcelData &data); +    ParcelData*        getSetting(const LLUUID ®ion_id, const S32 &parcel_id); +    EAskPlayMode       getPlayMode(const LLUUID ®ion_id, const S32 &parcel_id); +    void               setPlayMode(const LLUUID ®ion_id, const S32 &parcel_id, EAskPlayMode); + +    static void        onAskPlayResponse(const LLSD& notification, const LLSD& response, ask_callback cb); + +    static std::string getAskPlayFilename(); + +private: +    // Variables + +    typedef std::map<S32, ParcelData> parcel_data_map_t; +    typedef std::map<LLUUID, parcel_data_map_t> region_map_t; +    region_map_t mRegionMap; + +    // only one notification is supposed to exists and be visible +    LLNotificationPtr pNotification; +}; + + +#endif // LLVIEWERPARCELASKPLAY_H diff --git a/indra/newview/llviewerparcelmediaautoplay.cpp b/indra/newview/llviewerparcelmediaautoplay.cpp index 57ee583eae..b4dc6932be 100644 --- a/indra/newview/llviewerparcelmediaautoplay.cpp +++ b/indra/newview/llviewerparcelmediaautoplay.cpp @@ -24,17 +24,20 @@   * $/LicenseInfo$   */ +  #include "llviewerprecompiledheaders.h" +  #include "llviewerparcelmediaautoplay.h" -#include "llviewerparcelmedia.h" + +#include "llparcel.h"  #include "llviewercontrol.h"  #include "llviewermedia.h" -#include "llviewerregion.h" -#include "llparcel.h" +#include "llviewerparcelaskplay.h" +#include "llviewerparcelmedia.h"  #include "llviewerparcelmgr.h" -#include "lluuid.h" -#include "message.h" +#include "llviewerregion.h"  #include "llviewertexturelist.h"         // for texture stats +#include "message.h"  #include "llagent.h"  #include "llmimetypes.h" @@ -141,11 +144,28 @@ BOOL LLViewerParcelMediaAutoPlay::tick()  				{  					if (this_parcel)  					{ -						if (gSavedSettings.getBOOL("ParcelMediaAutoPlayEnable")) +						static LLCachedControl<S32> autoplay_mode(gSavedSettings, "ParcelMediaAutoPlayEnable"); + +						switch (autoplay_mode())  						{ -							// and last but not least, only play when autoplay is enabled -							LLViewerParcelMedia::play(this_parcel); -						} +							case 0: +								// Disabled +								break; +							case 1: +								// Play, default value for ParcelMediaAutoPlayEnable +								LLViewerParcelMedia::play(this_parcel); +								break; +							case 2: +							default: +							{ +								// Ask +								LLViewerParcelAskPlay::getInstance()->askToPlay(this_region->getRegionID(), +																				this_parcel->getLocalID(), +																				this_parcel->getMediaURL(), +																				onStartMusicResponse); +								break; +  							} +  						}  					}  					mPlayed = TRUE; @@ -158,5 +178,18 @@ BOOL LLViewerParcelMediaAutoPlay::tick()  	return FALSE; // continue ticking forever please.  } - +//static +void LLViewerParcelMediaAutoPlay::onStartMusicResponse(const LLUUID ®ion_id, const S32 &parcel_id, const std::string &url, const bool &play) +{ +    if (play) +    { +        LLParcel *parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + +        // make sure we are still there +        if (parcel->getLocalID() == parcel_id && gAgent.getRegion()->getRegionID() == region_id) +        { +            LLViewerParcelMedia::play(parcel); +        } +    } +} diff --git a/indra/newview/llviewerparcelmediaautoplay.h b/indra/newview/llviewerparcelmediaautoplay.h index a052362829..a404f60da1 100644 --- a/indra/newview/llviewerparcelmediaautoplay.h +++ b/indra/newview/llviewerparcelmediaautoplay.h @@ -41,6 +41,9 @@ class LLViewerParcelMediaAutoPlay : LLEventTimer  	static void playStarted();   private: +	static void onStartMusicResponse(const LLUUID ®ion_id, const S32 &parcel_id, const std::string &url, const bool &play); + + private:  	S32 mLastParcelID;  	LLUUID mLastRegionID;  	BOOL mPlayed; diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp index 416d5d8e2e..86cdf96e21 100644 --- a/indra/newview/llviewerparcelmgr.cpp +++ b/indra/newview/llviewerparcelmgr.cpp @@ -42,6 +42,7 @@  // Viewer includes  #include "llagent.h"  #include "llagentaccess.h" +#include "llviewerparcelaskplay.h"  #include "llviewerwindow.h"  #include "llviewercontrol.h"  //#include "llfirstuse.h" @@ -1832,6 +1833,7 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use                  // Only update stream if parcel changed (recreated) or music is playing (enabled)                  if (!agent_parcel_update || gSavedSettings.getBOOL("MediaTentativeAutoPlay"))                  { +                    LLViewerParcelAskPlay::getInstance()->cancelNotification();                      std::string music_url_raw = parcel->getMusicURL();                      // Trim off whitespace from front and back @@ -1843,7 +1845,8 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use                      {                          if (music_url.substr(0, 7) == "http://")                          { -                            optionally_start_music(music_url); +                            LLViewerRegion *region = LLWorld::getInstance()->getRegion(msg->getSender()); +                            optionally_start_music(music_url, parcel->mLocalID, region->getRegionID());                          }                          else                          { @@ -1864,25 +1867,61 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use  			else  			{  				// Public land has no music +				LLViewerParcelAskPlay::getInstance()->cancelNotification();  				LLViewerAudio::getInstance()->stopInternetStreamWithAutoFade();  			}  		}//if gAudiop  	};  } -void LLViewerParcelMgr::optionally_start_music(const std::string& music_url) +//static +void LLViewerParcelMgr::onStartMusicResponse(const LLUUID ®ion_id, const S32 &parcel_id, const std::string &url, const bool &play)  { -	if (gSavedSettings.getBOOL("AudioStreamingMusic")) +    if (play) +    { +        LL_INFOS("ParcelMgr") << "Starting parcel music " << url << LL_ENDL; +        LLViewerAudio::getInstance()->startInternetStreamWithAutoFade(url); +    } +} + +void LLViewerParcelMgr::optionally_start_music(const std::string &music_url, const S32 &local_id, const LLUUID ®ion_id) +{ +	static LLCachedControl<bool> streaming_music(gSavedSettings, "AudioStreamingMusic", true); +	if (streaming_music)  	{ +		static LLCachedControl<S32> autoplay_mode(gSavedSettings, "ParcelMediaAutoPlayEnable", 1); +		static LLCachedControl<bool> tentative_autoplay(gSavedSettings, "MediaTentativeAutoPlay", true);  		// only play music when you enter a new parcel if the UI control for this  		// was not *explicitly* stopped by the user. (part of SL-4878)  		LLPanelNearByMedia* nearby_media_panel = gStatusBar->getNearbyMediaPanel(); -		if ((nearby_media_panel && -		     nearby_media_panel->getParcelAudioAutoStart()) || -		    // or they have expressed no opinion in the UI, but have autoplay on... -		    (!nearby_media_panel && -		     gSavedSettings.getBOOL(LLViewerMedia::AUTO_PLAY_MEDIA_SETTING) && -			 gSavedSettings.getBOOL("MediaTentativeAutoPlay"))) + +        // ask mode //todo constants +        if (autoplay_mode == 2) +        { +            // stop previous stream +            LLViewerAudio::getInstance()->startInternetStreamWithAutoFade(LLStringUtil::null); + +            // if user set media to play - ask +            if ((nearby_media_panel && nearby_media_panel->getParcelAudioAutoStart()) +                || (!nearby_media_panel && tentative_autoplay)) +            { +                LLViewerParcelAskPlay::getInstance()->askToPlay(region_id, +                    local_id, +                    music_url, +                    onStartMusicResponse); +            } +            else +            { +                LLViewerParcelAskPlay::getInstance()->cancelNotification(); +            } +        } +        // autoplay +        else if ((nearby_media_panel +                  && nearby_media_panel->getParcelAudioAutoStart()) +                  // or they have expressed no opinion in the UI, but have autoplay on... +                 || (!nearby_media_panel +                     && autoplay_mode == 1 +                     && tentative_autoplay))  		{  			LL_INFOS("ParcelMgr") << "Starting parcel music " << music_url << LL_ENDL;  			LLViewerAudio::getInstance()->startInternetStreamWithAutoFade(music_url); diff --git a/indra/newview/llviewerparcelmgr.h b/indra/newview/llviewerparcelmgr.h index 29219843c9..288077fafc 100644 --- a/indra/newview/llviewerparcelmgr.h +++ b/indra/newview/llviewerparcelmgr.h @@ -268,7 +268,8 @@ public:  	// *NOTE: Taken out 2005-03-21. Phoenix.  	//void makeLandmarkAtSelection(); -	static void optionally_start_music(const std::string& music_url); +	static void onStartMusicResponse(const LLUUID ®ion_id, const S32 &parcel_id, const std::string &url, const bool &play); +	static void optionally_start_music(const std::string &music_url, const S32 &local_id, const LLUUID ®ion_id);  	static void processParcelOverlay(LLMessageSystem *msg, void **user_data);  	static void processParcelProperties(LLMessageSystem *msg, void **user_data); diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 874fbe19fd..a757a4beaa 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -6057,6 +6057,34 @@ Would you like to turn off Do Not Disturb before completing this transaction?    </notification>    <notification +   icon="notify.tga" +   label="Parcel is Playing Media" +   name="ParcelPlayingMedia"    +   persist="false" +   type="notify"> +This land has media: +[URL] +Would you like to play it? +    <tag>confirm</tag> +    <form name="form"> +      <ignore name="ignore" +       checkbox_only="true" +       text="Always choose this option for this land."/> +      <button +       ignore="Play Media" +       index="1" +       name="Yes" +       text="Play"/> +      <button +       default="true" +       ignore="Ignore Media" +       index="0" +       name="No" +       text="Ignore"/> +    </form> +  </notification> + +  <notification     icon="alertmodal.tga"     name="ConfirmDeleteProtectedCategory"     type="alertmodal"> diff --git a/indra/newview/skins/default/xui/en/panel_preferences_sound.xml b/indra/newview/skins/default/xui/en/panel_preferences_sound.xml index 649403184d..90f2ca2713 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_sound.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_sound.xml @@ -322,17 +322,40 @@  		name="enable_voice_check"  		width="110"/>  	<!-- --> -	<check_box -		name="media_auto_play_btn" -		control_name="ParcelMediaAutoPlayEnable" -		enabled_control="AudioStreamingMedia" -		value="true" -		follows="left|bottom|right" -		height="15" -		tool_tip="Check this to let media auto-play if it wants" -		label="Allow Media to auto-play" -		top_pad="1" -		left="25"/> +    <text +        follows="left|top" +        layout="topleft" +        height="15" +        left="0" +        top_pad="3" +        width="120" +        halign="right" +        name="media_autoplay_label"> +         Media auto-play +    </text> +    <combo_box +        control_name="ParcelMediaAutoPlayEnable" +        enabled_control="AudioStreamingMedia" +        follows="left|top" +        layout="topleft" +        height="23" +        left_pad="7" +        top_delta="-4" +        name="media_auto_play_combo" +        width="100"> +      <item +          label="Disabled" +          name="autoplay_disabled" +          value="0"/>       +      <item +          label="Enabled" +          name="autoplay_enabled" +          value="1"/> +      <item +          label="Ask" +          name="autoplay_ask" +          value="2"/> +    </combo_box>   	<check_box  		name="media_show_on_others_btn"  		control_name="MediaShowOnOthers" | 
