Upstream merge from lindenlab/viewer-neko

master
AndreyL ProductEngine 2019-09-10 23:21:56 +03:00
commit b31a93baa8
26 changed files with 664 additions and 62 deletions

View File

@ -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)

View File

@ -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,

View File

@ -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

View File

@ -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>

View File

@ -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();

View File

@ -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"));

View File

@ -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);
}
}

View File

@ -168,7 +168,6 @@ public:
void refreshUI();
void onCommitParcelMediaAutoPlayEnable();
void onCommitMediaEnabled();
void onCommitMusicEnabled();
void applyResolution();

View File

@ -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()

View File

@ -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*/

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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.

View File

@ -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"

View File

@ -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);
}

View File

@ -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);

View File

@ -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"));
}

View File

@ -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;

View File

@ -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 &region_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 &region_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 &region_id, const S32 &parcel_id, const LLViewerParcelAskPlay::ParcelData &data)
{
mRegionMap[region_id][parcel_id] = data;
}
LLViewerParcelAskPlay::ParcelData* LLViewerParcelAskPlay::getSetting(const LLUUID &region_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 &region_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 &region_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();
}
}

View File

@ -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 &region_id, const S32 &parcel_id, const std::string &url, ask_callback cb);
void cancelNotification();
void resetCurrentParcelSetting();
void resetSetting(const LLUUID &region_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 &region_id, const S32 &parcel_id, const ParcelData &data);
ParcelData* getSetting(const LLUUID &region_id, const S32 &parcel_id);
EAskPlayMode getPlayMode(const LLUUID &region_id, const S32 &parcel_id);
void setPlayMode(const LLUUID &region_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

View File

@ -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 &region_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);
}
}
}

View File

@ -40,6 +40,9 @@ class LLViewerParcelMediaAutoPlay : LLEventTimer
static void cleanupClass();
static void playStarted();
private:
static void onStartMusicResponse(const LLUUID &region_id, const S32 &parcel_id, const std::string &url, const bool &play);
private:
S32 mLastParcelID;
LLUUID mLastRegionID;

View File

@ -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 &region_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 &region_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);

View File

@ -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 &region_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 &region_id);
static void processParcelOverlay(LLMessageSystem *msg, void **user_data);
static void processParcelProperties(LLMessageSystem *msg, void **user_data);

View File

@ -6056,6 +6056,34 @@ Would you like to turn off Do Not Disturb before completing this transaction?
</form>
</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"

View File

@ -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"