/** * @file llpanelmediasettingsgeneral.cpp * @brief LLPanelMediaSettingsGeneral class implementation * * $LicenseInfo:firstyear=2009&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" #include "llpanelmediasettingsgeneral.h" // library includes #include "llcombobox.h" #include "llcheckboxctrl.h" #include "llnotificationsutil.h" #include "llspinctrl.h" #include "lluictrlfactory.h" // project includes #include "llagent.h" #include "llviewerwindow.h" #include "llviewermedia.h" #include "llvovolume.h" #include "llsdutil.h" #include "llselectmgr.h" #include "llbutton.h" #include "lltexturectrl.h" #include "llurl.h" #include "llwindow.h" #include "llmediaentry.h" #include "llmediactrl.h" #include "llpanelcontents.h" #include "llpermissions.h" #include "llpluginclassmedia.h" #include "llfloatermediasettings.h" #include "llfloatertools.h" #include "lltrans.h" #include "lltextbox.h" #include "llpanelmediasettingssecurity.h" const char *CHECKERBOARD_DATA_URL = "data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 width=%22100%%22 height=%22100%%22 %3E%3Cdefs%3E%3Cpattern id=%22checker%22 patternUnits=%22userSpaceOnUse%22 x=%220%22 y=%220%22 width=%22128%22 height=%22128%22 viewBox=%220 0 128 128%22 %3E%3Crect x=%220%22 y=%220%22 width=%2264%22 height=%2264%22 fill=%22#ddddff%22 /%3E%3Crect x=%2264%22 y=%2264%22 width=%2264%22 height=%2264%22 fill=%22#ddddff%22 /%3E%3C/pattern%3E%3C/defs%3E%3Crect x=%220%22 y=%220%22 width=%22100%%22 height=%22100%%22 fill=%22url(#checker)%22 /%3E%3C/svg%3E"; //////////////////////////////////////////////////////////////////////////////// // LLPanelMediaSettingsGeneral::LLPanelMediaSettingsGeneral() : mAutoLoop( NULL ), mFirstClick( NULL ), mAutoZoom( NULL ), mAutoPlay( NULL ), mAutoScale( NULL ), mWidthPixels( NULL ), mHeightPixels( NULL ), mHomeURL( NULL ), mCurrentURL( NULL ), mParent( NULL ), mMediaEditable(false) { // build dialog from XML buildFromFile( "panel_media_settings_general.xml"); } //////////////////////////////////////////////////////////////////////////////// // bool LLPanelMediaSettingsGeneral::postBuild() { // connect member vars with UI widgets mAutoLoop = getChild< LLCheckBoxCtrl >( LLMediaEntry::AUTO_LOOP_KEY ); mAutoPlay = getChild< LLCheckBoxCtrl >( LLMediaEntry::AUTO_PLAY_KEY ); mAutoScale = getChild< LLCheckBoxCtrl >( LLMediaEntry::AUTO_SCALE_KEY ); mAutoZoom = getChild< LLCheckBoxCtrl >( LLMediaEntry::AUTO_ZOOM_KEY ); mCurrentURL = getChild< LLTextBox >( LLMediaEntry::CURRENT_URL_KEY ); mFirstClick = getChild< LLCheckBoxCtrl >( LLMediaEntry::FIRST_CLICK_INTERACT_KEY ); mHeightPixels = getChild< LLSpinCtrl >( LLMediaEntry::HEIGHT_PIXELS_KEY ); mHomeURL = getChild< LLLineEditor >( LLMediaEntry::HOME_URL_KEY ); mWidthPixels = getChild< LLSpinCtrl >( LLMediaEntry::WIDTH_PIXELS_KEY ); mPreviewMedia = getChild<LLMediaCtrl>("preview_media"); mFailWhiteListText = getChild<LLTextBox>( "home_fails_whitelist_label" ); // watch commit action for HOME URL childSetCommitCallback( LLMediaEntry::HOME_URL_KEY, onCommitHomeURL, this); childSetCommitCallback( "current_url_reset_btn",onBtnResetCurrentUrl, this); return true; } //////////////////////////////////////////////////////////////////////////////// // virtual LLPanelMediaSettingsGeneral::~LLPanelMediaSettingsGeneral() { } //////////////////////////////////////////////////////////////////////////////// // static void LLPanelMediaSettingsGeneral::draw() { // housekeeping LLPanel::draw(); // TODO: we need to call this repeatedly until the floater panels are fully // created but once we have a valid answer, we should stop looking here - the // commit callback will handle it checkHomeUrlPassesWhitelist(); // enable/disable pixel values image entry based on auto scale checkbox if (!mAutoScale->getValue().asBoolean()) { getChildView( LLMediaEntry::WIDTH_PIXELS_KEY )->setEnabled( true ); getChildView( LLMediaEntry::HEIGHT_PIXELS_KEY )->setEnabled( true ); } else { getChildView( LLMediaEntry::WIDTH_PIXELS_KEY )->setEnabled( false ); getChildView( LLMediaEntry::HEIGHT_PIXELS_KEY )->setEnabled( false ); }; // enable/disable UI based on type of media bool reset_button_is_active = true; if (mPreviewMedia) { if (LLPluginClassMedia* media_plugin = mPreviewMedia->getMediaPlugin()) { // turn off volume (if we can) for preview. Note: this really only // works for QuickTime movies right now - no way to control the // volume of a flash app embedded in a page for example media_plugin->setVolume( 0 ); // some controls are only appropriate for time or browser type plugins // so we selectively enable/disable them - need to do it in draw // because the information from plugins arrives assynchronously if (media_plugin->pluginSupportsMediaTime()) { getChildView( LLMediaEntry::CURRENT_URL_KEY )->setEnabled( false ); reset_button_is_active = false; getChildView("current_url_label")->setEnabled(false ); getChildView( LLMediaEntry::AUTO_LOOP_KEY )->setEnabled( true ); } else { getChildView( LLMediaEntry::CURRENT_URL_KEY )->setEnabled( true ); reset_button_is_active = true; getChildView("current_url_label")->setEnabled(true ); getChildView( LLMediaEntry::AUTO_LOOP_KEY )->setEnabled( false ); }; }; }; // current URL can change over time, update it here updateCurrentUrl(); LLPermissions perm; bool user_can_press_reset = mMediaEditable; // several places modify this widget so we must collect states in one place if ( reset_button_is_active ) { // user has perms to press reset button and it is active if ( user_can_press_reset ) { getChildView("current_url_reset_btn")->setEnabled(true ); } // user does not has perms to press reset button and it is active else { getChildView("current_url_reset_btn")->setEnabled(false ); }; } else // reset button is inactive so we just slam it to off - other states don't matter { getChildView("current_url_reset_btn")->setEnabled(false ); }; } //////////////////////////////////////////////////////////////////////////////// // static void LLPanelMediaSettingsGeneral::clearValues( void* userdata, bool editable, bool update_preview) { LLPanelMediaSettingsGeneral *self =(LLPanelMediaSettingsGeneral *)userdata; self->mAutoLoop->clear(); self->mAutoPlay->clear(); self->mAutoScale->clear(); self->mAutoZoom ->clear(); self->mCurrentURL->clear(); self->mFirstClick->clear(); self->mHeightPixels->clear(); self->mHomeURL->clear(); self->mWidthPixels->clear(); self->mAutoLoop ->setEnabled(editable); self->mAutoPlay ->setEnabled(editable); self->mAutoScale ->setEnabled(editable); self->mAutoZoom ->setEnabled(editable); self->mCurrentURL ->setEnabled(editable); self->mFirstClick ->setEnabled(editable); self->mHeightPixels ->setEnabled(editable); self->mHomeURL ->setEnabled(editable); self->mWidthPixels ->setEnabled(editable); if (update_preview) { self->updateMediaPreview(); } } // static bool LLPanelMediaSettingsGeneral::isMultiple() { // IF all the faces have media (or all dont have media) if ( LLFloaterMediaSettings::getInstance()->mIdenticalHasMediaInfo ) { if(LLFloaterMediaSettings::getInstance()->mMultipleMedia) { return true; } } else { if(LLFloaterMediaSettings::getInstance()->mMultipleValidMedia) { return true; } } return false; } //////////////////////////////////////////////////////////////////////////////// // static void LLPanelMediaSettingsGeneral::initValues( void* userdata, const LLSD& _media_settings, bool editable) { LLPanelMediaSettingsGeneral *self =(LLPanelMediaSettingsGeneral *)userdata; self->mMediaEditable = editable; LLSD media_settings = _media_settings; if ( LLPanelMediaSettingsGeneral::isMultiple() ) { // *HACK: "edit" the incoming media_settings media_settings[LLMediaEntry::CURRENT_URL_KEY] = LLTrans::getString("Multiple Media"); media_settings[LLMediaEntry::HOME_URL_KEY] = LLTrans::getString("Multiple Media"); } std::string base_key( "" ); std::string tentative_key( "" ); struct { std::string key_name; LLUICtrl* ctrl_ptr; std::string ctrl_type; } data_set [] = { { LLMediaEntry::AUTO_LOOP_KEY, self->mAutoLoop, "LLCheckBoxCtrl" }, { LLMediaEntry::AUTO_PLAY_KEY, self->mAutoPlay, "LLCheckBoxCtrl" }, { LLMediaEntry::AUTO_SCALE_KEY, self->mAutoScale, "LLCheckBoxCtrl" }, { LLMediaEntry::AUTO_ZOOM_KEY, self->mAutoZoom, "LLCheckBoxCtrl" }, { LLMediaEntry::CURRENT_URL_KEY, self->mCurrentURL, "LLTextBox" }, { LLMediaEntry::HEIGHT_PIXELS_KEY, self->mHeightPixels, "LLSpinCtrl" }, { LLMediaEntry::HOME_URL_KEY, self->mHomeURL, "LLLineEditor" }, { LLMediaEntry::FIRST_CLICK_INTERACT_KEY, self->mFirstClick, "LLCheckBoxCtrl" }, { LLMediaEntry::WIDTH_PIXELS_KEY, self->mWidthPixels, "LLSpinCtrl" }, { "", NULL , "" } }; for( int i = 0; data_set[ i ].key_name.length() > 0; ++i ) { base_key = std::string( data_set[ i ].key_name ); tentative_key = base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ); // TODO: CP - I bet there is a better way to do this using Boost if ( media_settings[ base_key ].isDefined() ) { if ( data_set[ i ].ctrl_type == "LLLineEditor" ) { static_cast< LLLineEditor* >( data_set[ i ].ctrl_ptr )-> setText( media_settings[ base_key ].asString() ); } else if ( data_set[ i ].ctrl_type == "LLCheckBoxCtrl" ) static_cast< LLCheckBoxCtrl* >( data_set[ i ].ctrl_ptr )-> setValue( media_settings[ base_key ].asBoolean() ); else if ( data_set[ i ].ctrl_type == "LLComboBox" ) static_cast< LLComboBox* >( data_set[ i ].ctrl_ptr )-> setCurrentByIndex( media_settings[ base_key ].asInteger() ); else if ( data_set[ i ].ctrl_type == "LLSpinCtrl" ) static_cast< LLSpinCtrl* >( data_set[ i ].ctrl_ptr )-> setValue( media_settings[ base_key ].asInteger() ); data_set[ i ].ctrl_ptr->setEnabled(self->mMediaEditable); data_set[ i ].ctrl_ptr->setTentative( media_settings[ tentative_key ].asBoolean() ); }; }; } //////////////////////////////////////////////////////////////////////////////// // Helper to set media control to media URL as required void LLPanelMediaSettingsGeneral::updateMediaPreview() { if(LLTrans::getString("Multiple Media") == mHomeURL->getValue().asString()) { return; } if ( mHomeURL->getValue().asString().length() > 0 ) { if(mPreviewMedia->getCurrentNavUrl() != mHomeURL->getValue().asString()) { mPreviewMedia->navigateTo( mHomeURL->getValue().asString() ); } } else // new home URL will be empty if media is deleted so display a // "preview goes here" data url page { if(mPreviewMedia->getCurrentNavUrl() != CHECKERBOARD_DATA_URL) { mPreviewMedia->navigateTo( CHECKERBOARD_DATA_URL ); } }; } //////////////////////////////////////////////////////////////////////////////// // virtual void LLPanelMediaSettingsGeneral::onClose(bool app_quitting) { if(mPreviewMedia) { mPreviewMedia->unloadMediaSource(); } } //////////////////////////////////////////////////////////////////////////////// // void LLPanelMediaSettingsGeneral::checkHomeUrlPassesWhitelist() { // parent floater has not constructed the security panel yet if ( mParent->getPanelSecurity() == 0 ) return; std::string home_url = getHomeUrl(); if ( home_url.empty() || mParent->getPanelSecurity()->urlPassesWhiteList( home_url ) ) { // Home URL is empty or passes the white list so hide the warning message mFailWhiteListText->setVisible( false ); } else { // Home URL does not pass the white list so show the warning message mFailWhiteListText->setVisible( true ); }; } //////////////////////////////////////////////////////////////////////////////// // static void LLPanelMediaSettingsGeneral::onCommitHomeURL( LLUICtrl* ctrl, void *userdata ) { LLPanelMediaSettingsGeneral* self =(LLPanelMediaSettingsGeneral *)userdata; // check home url passes whitelist and display warning if not self->checkHomeUrlPassesWhitelist(); self->updateMediaPreview(); } //////////////////////////////////////////////////////////////////////////////// // static void LLPanelMediaSettingsGeneral::onBtnResetCurrentUrl(LLUICtrl* ctrl, void *userdata) { LLPanelMediaSettingsGeneral* self =(LLPanelMediaSettingsGeneral *)userdata; self->navigateHomeSelectedFace(false); } //////////////////////////////////////////////////////////////////////////////// // void LLPanelMediaSettingsGeneral::preApply() { // Make sure the home URL entry is committed mHomeURL->onCommit(); } //////////////////////////////////////////////////////////////////////////////// // void LLPanelMediaSettingsGeneral::getValues( LLSD &fill_me_in, bool include_tentative ) { if (include_tentative || !mAutoLoop->getTentative()) fill_me_in[LLMediaEntry::AUTO_LOOP_KEY] = (LLSD::Boolean)mAutoLoop->getValue(); if (include_tentative || !mAutoPlay->getTentative()) fill_me_in[LLMediaEntry::AUTO_PLAY_KEY] = (LLSD::Boolean)mAutoPlay->getValue(); if (include_tentative || !mAutoScale->getTentative()) fill_me_in[LLMediaEntry::AUTO_SCALE_KEY] = (LLSD::Boolean)mAutoScale->getValue(); if (include_tentative || !mAutoZoom->getTentative()) fill_me_in[LLMediaEntry::AUTO_ZOOM_KEY] = (LLSD::Boolean)mAutoZoom->getValue(); //Don't fill in current URL: this is only supposed to get changed via navigate // if (include_tentative || !mCurrentURL->getTentative()) fill_me_in[LLMediaEntry::CURRENT_URL_KEY] = mCurrentURL->getValue(); if (include_tentative || !mHeightPixels->getTentative()) fill_me_in[LLMediaEntry::HEIGHT_PIXELS_KEY] = (LLSD::Integer)mHeightPixels->getValue(); // Don't fill in the home URL if it is the special "Multiple Media" string! if ((include_tentative || !mHomeURL->getTentative()) && LLTrans::getString("Multiple Media") != mHomeURL->getValue()) fill_me_in[LLMediaEntry::HOME_URL_KEY] = (LLSD::String)mHomeURL->getValue(); if (include_tentative || !mFirstClick->getTentative()) fill_me_in[LLMediaEntry::FIRST_CLICK_INTERACT_KEY] = (LLSD::Boolean)mFirstClick->getValue(); if (include_tentative || !mWidthPixels->getTentative()) fill_me_in[LLMediaEntry::WIDTH_PIXELS_KEY] = (LLSD::Integer)mWidthPixels->getValue(); } //////////////////////////////////////////////////////////////////////////////// // void LLPanelMediaSettingsGeneral::postApply() { // Make sure to navigate to the home URL if the current URL is empty and // autoplay is on navigateHomeSelectedFace(true); } //////////////////////////////////////////////////////////////////////////////// // void LLPanelMediaSettingsGeneral::setParent( LLFloaterMediaSettings* parent ) { mParent = parent; }; //////////////////////////////////////////////////////////////////////////////// // bool LLPanelMediaSettingsGeneral::navigateHomeSelectedFace(bool only_if_current_is_empty) { struct functor_navigate_media : public LLSelectedTEGetFunctor< bool> { functor_navigate_media(bool flag) : only_if_current_is_empty(flag) {} bool get( LLViewerObject* object, S32 face ) { if ( object && object->getTE(face) && object->permModify() ) { const LLMediaEntry *media_data = object->getTE(face)->getMediaData(); if ( media_data ) { if (!only_if_current_is_empty || (media_data->getCurrentURL().empty() && media_data->getAutoPlay())) { viewer_media_t media_impl = LLViewerMedia::getInstance()->getMediaImplFromTextureID(object->getTE(face)->getMediaData()->getMediaID()); if (media_impl) { media_impl->setPriority(LLPluginClassMedia::PRIORITY_NORMAL); media_impl->navigateHome(); if (!only_if_current_is_empty) { LLSD media_data; media_data[LLMediaEntry::CURRENT_URL_KEY] = std::string(); object->getTE(face)->mergeIntoMediaData(media_data); } return true; } } } } return false; }; bool only_if_current_is_empty; } functor_navigate_media(only_if_current_is_empty); bool all_face_media_navigated = false; LLObjectSelectionHandle selected_objects =LLSelectMgr::getInstance()->getSelection(); selected_objects->getSelectedTEValue( &functor_navigate_media, all_face_media_navigated ); if (all_face_media_navigated) { struct functor_sync_to_server : public LLSelectedObjectFunctor { virtual bool apply(LLViewerObject* object) { LLVOVolume *volume = dynamic_cast<LLVOVolume*>(object); if (volume) { volume->sendMediaDataUpdate(); } return true; } } sendfunc; selected_objects->applyToObjects(&sendfunc); } // Note: we don't update the 'current URL' field until the media data itself changes return all_face_media_navigated; } //////////////////////////////////////////////////////////////////////////////// // const std::string LLPanelMediaSettingsGeneral::getHomeUrl() { return mHomeURL->getValue().asString(); } //////////////////////////////////////////////////////////////////////////////// // void LLPanelMediaSettingsGeneral::updateCurrentUrl() { // Get the current URL from the selection const LLMediaEntry default_media_data; std::string value_str = default_media_data.getCurrentURL(); struct functor_getter_current_url : public LLSelectedTEGetFunctor< std::string > { functor_getter_current_url(const LLMediaEntry& entry): mMediaEntry(entry) {} std::string get( LLViewerObject* object, S32 face ) { if ( object ) if ( object->getTE(face) ) if ( object->getTE(face)->getMediaData() ) return object->getTE(face)->getMediaData()->getCurrentURL(); return mMediaEntry.getCurrentURL(); }; const LLMediaEntry & mMediaEntry; } func_current_url(default_media_data); bool identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func_current_url, value_str ); mCurrentURL->setText(value_str); mCurrentURL->setTentative(identical); if ( LLPanelMediaSettingsGeneral::isMultiple() ) { mCurrentURL->setText(LLTrans::getString("Multiple Media")); } }