diff options
| author | Oz Linden <oz@lindenlab.com> | 2011-01-04 16:46:09 -0500 | 
|---|---|---|
| committer | Oz Linden <oz@lindenlab.com> | 2011-01-04 16:46:09 -0500 | 
| commit | e2f197b6f77592c84d0c2967cc0e8110c79f2f49 (patch) | |
| tree | c405316265ca4248802817b8a99697063c58469d /indra/newview | |
| parent | 2d9c970babf6bab8d402482315af6be0ffb198dd (diff) | |
| parent | 78895f9e0c628dc33268578faf135e967cf30142 (diff) | |
merge changes for storm-398
Diffstat (limited to 'indra/newview')
110 files changed, 6334 insertions, 798 deletions
| diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 2dd32b7aa4..ce22a52460 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -50,6 +50,7 @@ include_directories(      ${LLCHARACTER_INCLUDE_DIRS}      ${LLCOMMON_INCLUDE_DIRS}      ${LLIMAGE_INCLUDE_DIRS} +    ${LLKDU_INCLUDE_DIRS}      ${LLINVENTORY_INCLUDE_DIRS}      ${LLMATH_INCLUDE_DIRS}      ${LLMESSAGE_INCLUDE_DIRS} @@ -222,6 +223,7 @@ set(viewer_SOURCE_FILES      llfloaterurlentry.cpp      llfloatervoiceeffect.cpp      llfloaterwater.cpp +    llfloaterwebcontent.cpp      llfloaterwhitelistentry.cpp      llfloaterwindlight.cpp      llfloaterwindowsize.cpp @@ -481,6 +483,7 @@ set(viewer_SOURCE_FILES      llvectorperfoptions.cpp      llversioninfo.cpp      llviewchildren.cpp +    llviewerassetstats.cpp      llviewerassetstorage.cpp      llviewerassettype.cpp      llviewerattachmenu.cpp @@ -757,6 +760,7 @@ set(viewer_HEADER_FILES      llfloaterurlentry.h      llfloatervoiceeffect.h      llfloaterwater.h +    llfloaterwebcontent.h      llfloaterwhitelistentry.h      llfloaterwindlight.h      llfloaterwindowsize.h @@ -1014,6 +1018,7 @@ set(viewer_HEADER_FILES      llvectorperfoptions.h      llversioninfo.h      llviewchildren.h +    llviewerassetstats.h      llviewerassetstorage.h      llviewerassettype.h      llviewerattachmenu.h @@ -1453,11 +1458,6 @@ if (WINDOWS)      # In the meantime, if you have any ideas on how to easily maintain one list, either here or in viewer_manifest.py      # and have the build deps get tracked *please* tell me about it. -    if(LLKDU_LIBRARY) -      # Configure a var for llkdu which may not exist for all builds. -      set(LLKDU_DLL_SOURCE ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/llkdu.dll) -    endif(LLKDU_LIBRARY) -      if(USE_GOOGLE_PERFTOOLS)        # Configure a var for tcmalloc location, if used.        # Note the need to specify multiple names explicitly. @@ -1474,7 +1474,6 @@ if (WINDOWS)        #${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/libtcmalloc_minimal.dll => None ... Skipping libtcmalloc_minimal.dll        ${CMAKE_SOURCE_DIR}/../etc/message.xml        ${CMAKE_SOURCE_DIR}/../scripts/messages/message_template.msg -      ${LLKDU_DLL_SOURCE}        ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/llcommon.dll        ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/libapr-1.dll        ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/libaprutil-1.dll @@ -1660,7 +1659,6 @@ target_link_libraries(${VIEWER_BINARY_NAME}      ${LLAUDIO_LIBRARIES}      ${LLCHARACTER_LIBRARIES}      ${LLIMAGE_LIBRARIES} -    ${LLIMAGEJ2COJ_LIBRARIES}      ${LLINVENTORY_LIBRARIES}      ${LLMESSAGE_LIBRARIES}      ${LLPLUGIN_LIBRARIES} @@ -1696,6 +1694,17 @@ target_link_libraries(${VIEWER_BINARY_NAME}      ${GOOGLE_PERFTOOLS_LIBRARIES}      ) +if (USE_KDU) +    target_link_libraries(${VIEWER_BINARY_NAME} +        ${LLKDU_LIBRARIES} +        ${KDU_LIBRARY} +        ) +else (USE_KDU) +    target_link_libraries(${VIEWER_BINARY_NAME} +        ${LLIMAGEJ2COJ_LIBRARIES} +        ) +endif (USE_KDU) +      build_version(viewer)  set(ARTWORK_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE PATH @@ -1843,29 +1852,31 @@ if (PACKAGE)      set(VIEWER_COPY_MANIFEST copy_l_viewer_manifest)    endif (LINUX) -  if(CMAKE_CFG_INTDIR STREQUAL ".") +  if(RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING) +    if(CMAKE_CFG_INTDIR STREQUAL ".")        set(LLBUILD_CONFIG ${CMAKE_BUILD_TYPE}) -  else(CMAKE_CFG_INTDIR STREQUAL ".") +    else(CMAKE_CFG_INTDIR STREQUAL ".")        # set LLBUILD_CONFIG to be a shell variable evaluated at build time        # reflecting the configuration we are currently building.        set(LLBUILD_CONFIG ${CMAKE_CFG_INTDIR}) -  endif(CMAKE_CFG_INTDIR STREQUAL ".") -  add_custom_command(OUTPUT "${VIEWER_SYMBOL_FILE}" -    COMMAND "${PYTHON_EXECUTABLE}" -    ARGS -      "${CMAKE_CURRENT_SOURCE_DIR}/generate_breakpad_symbols.py" -      "${LLBUILD_CONFIG}" -      "${VIEWER_DIST_DIR}" -      "${VIEWER_EXE_GLOBS}" -      "${VIEWER_LIB_GLOB}" -      "${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/bin/dump_syms" -      "${VIEWER_SYMBOL_FILE}" -    DEPENDS generate_breakpad_symbols.py -    VERBATIM -  ) -  add_custom_target(generate_breakpad_symbols DEPENDS "${VIEWER_SYMBOL_FILE}") -  add_dependencies(generate_breakpad_symbols "${VIEWER_BINARY_NAME}" "${VIEWER_COPY_MANIFEST}") -  add_dependencies(package generate_breakpad_symbols) +    endif(CMAKE_CFG_INTDIR STREQUAL ".") +    add_custom_command(OUTPUT "${VIEWER_SYMBOL_FILE}" +      COMMAND "${PYTHON_EXECUTABLE}" +      ARGS +        "${CMAKE_CURRENT_SOURCE_DIR}/generate_breakpad_symbols.py" +        "${LLBUILD_CONFIG}" +        "${VIEWER_DIST_DIR}" +        "${VIEWER_EXE_GLOBS}" +        "${VIEWER_LIB_GLOB}" +        "${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/bin/dump_syms" +        "${VIEWER_SYMBOL_FILE}" +        DEPENDS generate_breakpad_symbols.py +        VERBATIM) + +    add_custom_target(generate_breakpad_symbols DEPENDS "${VIEWER_SYMBOL_FILE}") +    add_dependencies(generate_breakpad_symbols "${VIEWER_BINARY_NAME}" "${VIEWER_COPY_MANIFEST}") +    add_dependencies(package generate_breakpad_symbols) +  endif(RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING)  endif (PACKAGE)  if (LL_TESTS) @@ -1880,6 +1891,8 @@ if (LL_TESTS)      llremoteparcelrequest.cpp      llviewerhelputil.cpp      llversioninfo.cpp +    llworldmap.cpp +    llworldmipmap.cpp    )    ################################################## @@ -1955,10 +1968,18 @@ if (LL_TESTS)      "${test_libs}"      ) +  LL_ADD_INTEGRATION_TEST(llsimplestat +	"" +    "${test_libs}" +    ) + +  LL_ADD_INTEGRATION_TEST(llviewerassetstats +	llviewerassetstats.cpp +    "${test_libs}" +    ) +    #ADD_VIEWER_BUILD_TEST(llmemoryview viewer)    #ADD_VIEWER_BUILD_TEST(llagentaccess viewer) -  #ADD_VIEWER_BUILD_TEST(llworldmap viewer) -  #ADD_VIEWER_BUILD_TEST(llworldmipmap viewer)    #ADD_VIEWER_BUILD_TEST(lltextureinfo viewer)    #ADD_VIEWER_BUILD_TEST(lltextureinfodetails viewer)    #ADD_VIEWER_BUILD_TEST(lltexturestatsuploader viewer) diff --git a/indra/newview/app_settings/lindenlab.pem b/indra/newview/app_settings/lindenlab.pem new file mode 100644 index 0000000000..cf88d0e047 --- /dev/null +++ b/indra/newview/app_settings/lindenlab.pem @@ -0,0 +1,27 @@ +-----BEGIN CERTIFICATE----- +MIIEUDCCA7mgAwIBAgIJAN4ppNGwj6yIMA0GCSqGSIb3DQEBBAUAMIHMMQswCQYD +VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5j +aXNjbzEZMBcGA1UEChMQTGluZGVuIExhYiwgSW5jLjEpMCcGA1UECxMgTGluZGVu +IExhYiBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxKTAnBgNVBAMTIExpbmRlbiBMYWIg +Q2VydGlmaWNhdGUgQXV0aG9yaXR5MR8wHQYJKoZIhvcNAQkBFhBjYUBsaW5kZW5s +YWIuY29tMB4XDTA1MDQyMTAyNDAzMVoXDTI1MDQxNjAyNDAzMVowgcwxCzAJBgNV +BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNp +c2NvMRkwFwYDVQQKExBMaW5kZW4gTGFiLCBJbmMuMSkwJwYDVQQLEyBMaW5kZW4g +TGFiIENlcnRpZmljYXRlIEF1dGhvcml0eTEpMCcGA1UEAxMgTGluZGVuIExhYiBD +ZXJ0aWZpY2F0ZSBBdXRob3JpdHkxHzAdBgkqhkiG9w0BCQEWEGNhQGxpbmRlbmxh +Yi5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKXh1MThucdTbMg9bYBO +rAm8yWns32YojB0PRfbq8rUjepEhTm3/13s0u399Uc202v4ejcGhkIDWJZd2NZMF +oKrhmRfxGHSKPCuFaXC3jh0lRECj7k8FoPkcmaPjSyodrDFDUUuv+C06oYJoI+rk +8REyal9NwgHvqCzOrZtiTXAdAgMBAAGjggE2MIIBMjAdBgNVHQ4EFgQUO1zK2e1f +1wO1fHAjq6DTJobKDrcwggEBBgNVHSMEgfkwgfaAFDtcytntX9cDtXxwI6ug0yaG +yg63oYHSpIHPMIHMMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEW +MBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEZMBcGA1UEChMQTGluZGVuIExhYiwgSW5j +LjEpMCcGA1UECxMgTGluZGVuIExhYiBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxKTAn +BgNVBAMTIExpbmRlbiBMYWIgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MR8wHQYJKoZI +hvcNAQkBFhBjYUBsaW5kZW5sYWIuY29tggkA3imk0bCPrIgwDAYDVR0TBAUwAwEB +/zANBgkqhkiG9w0BAQQFAAOBgQA/ZkgfvwHYqk1UIAKZS3kMCxz0HvYuEQtviwnu +xA39CIJ65Zozs28Eg1aV9/Y+Of7TnWhW+U3J3/wD/GghaAGiKK6vMn9gJBIdBX/9 +e6ef37VGyiOEFFjnUIbuk0RWty0orN76q/lI/xjCi15XSA/VSq2j4vmnwfZcPTDu +glmQ1A== +-----END CERTIFICATE----- + diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 06992d2b52..ea7ac6beda 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -686,6 +686,39 @@        <key>Value</key>        <string>http://www.secondlife.com</string>      </map> +    <key>BrowserIgnoreSSLCertErrors</key> +    <map> +      <key>Comment</key> +      <string>FOR TESTING ONLY: Tell the built-in web browser to ignore SSL cert errors.</string> +      <key>Persist</key> +      <integer>1</integer> +      <key>Type</key> +      <string>Boolean</string> +      <key>Value</key> +      <integer>0</integer> +    </map> +    <key>BrowserUseDefaultCAFile</key> +    <map> +      <key>Comment</key> +      <string>Tell the built-in web browser to use the CA.pem file shipped with the client.</string> +      <key>Persist</key> +      <integer>1</integer> +      <key>Type</key> +      <string>Boolean</string> +      <key>Value</key> +      <integer>1</integer> +    </map> +    <key>BrowserCAFilePath</key> +    <map> +      <key>Comment</key> +      <string>Tell the built-in web browser the path to an alternative CA.pem file (only used if BrowserUseDefaultCAFile is false).</string> +      <key>Persist</key> +      <integer>1</integer> +      <key>Type</key> +      <string>String</string> +      <key>Value</key> +      <string></string> +    </map>        <key>BlockAvatarAppearanceMessages</key>          <map>          <key>Comment</key> @@ -4747,6 +4780,17 @@        <key>Value</key>        <string>http://map.secondlife.com.s3.amazonaws.com/</string>      </map> +    <key>CurrentMapServerURL</key> +    <map> +      <key>Comment</key> +      <string>Current Session World map URL</string> +      <key>Persist</key> +      <integer>0</integer> +      <key>Type</key> +      <string>String</string> +      <key>Value</key> +      <string></string> +    </map>      <key>MapShowEvents</key>      <map>        <key>Comment</key> @@ -6572,7 +6616,18 @@      <key>MediaBrowserWindowLimit</key>      <map>        <key>Comment</key> -      <string>Maximum number of media brower windows that can be open at once (0 for no limit)</string> +      <string>Maximum number of media brower windows that can be open at once in the media browser floater (0 for no limit)</string> +      <key>Persist</key> +      <integer>1</integer> +      <key>Type</key> +      <string>S32</string> +      <key>Value</key> +      <integer>5</integer> +    </map> +    <key>WebContentWindowLimit</key> +    <map> +      <key>Comment</key> +      <string>Maximum number of web brower windows that can be open at once in the Web content floater (0 for no limit)</string>        <key>Persist</key>        <integer>1</integer>        <key>Type</key> @@ -9980,6 +10035,17 @@        <key>Value</key>        <real>500.0</real>      </map> +    <key>UpdaterMaximumBandwidth</key> +    <map> +      <key>Comment</key> +      <string>Maximum allowable downstream bandwidth for updater service (kilo bits per second)</string> +      <key>Persist</key> +      <integer>1</integer> +      <key>Type</key> +      <string>F32</string> +      <key>Value</key> +      <real>500.0</real> +    </map>      <key>ToolTipDelay</key>      <map>        <key>Comment</key> @@ -11080,16 +11146,16 @@        <key>Value</key>        <integer>15</integer>      </map> -    <key>UpdaterServiceActive</key> +    <key>UpdaterServiceSetting</key>      <map>        <key>Comment</key> -      <string>Enable or disable the updater service.</string> +      <string>Configure updater service.</string>        <key>Persist</key>        <integer>1</integer>        <key>Type</key> -      <string>Boolean</string> +      <string>U32</string>        <key>Value</key> -      <integer>1</integer> +      <integer>3</integer>      </map>      <key>UpdaterServiceCheckPeriod</key>      <map> @@ -12368,5 +12434,16 @@        <key>Value</key>        <string>name</string>      </map> +    <key>ReleaseNotesURL</key> +    <map> +      <key>Comment</key> +      <string>Release notes URL template</string> +      <key>Persist</key> +      <integer>1</integer> +      <key>Type</key> +      <string>String</string> +      <key>Value</key> +      <string>http://secondlife.com/app/releasenotes/?channel=[CHANNEL]&version=[VERSION]</string> +    </map>  </map>  </llsd> diff --git a/indra/newview/app_settings/shaders/shader_heirarchy.txt b/indra/newview/app_settings/shaders/shader_hierarchy.txt index d8bbf69b38..d8bbf69b38 100644 --- a/indra/newview/app_settings/shaders/shader_heirarchy.txt +++ b/indra/newview/app_settings/shaders/shader_hierarchy.txt diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 001a6a8851..ea3c2eb312 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -637,6 +637,9 @@ void LLAgent::setRegion(LLViewerRegion *regionp)  			// Update all of the regions.  			LLWorld::getInstance()->updateAgentOffset(mAgentOriginGlobal);  		} + +		// Pass new region along to metrics components that care about this level of detail. +		LLAppViewer::metricsUpdateRegion(regionp->getHandle());  	}  	mRegionp = regionp; diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp index 15f8e7bf4d..f01d5ff1f5 100644 --- a/indra/newview/llagentcamera.cpp +++ b/indra/newview/llagentcamera.cpp @@ -2695,6 +2695,9 @@ void LLAgentCamera::lookAtLastChat()  		new_camera_pos -= delta_pos * 0.4f;  		new_camera_pos += left * 0.3f;  		new_camera_pos += up * 0.2f; + +		setFocusOnAvatar(FALSE, FALSE); +  		if (chatter_av->mHeadp)  		{  			setFocusGlobal(gAgent.getPosGlobalFromAgent(chatter_av->mHeadp->getWorldPosition()), gAgent.getLastChatter()); @@ -2705,7 +2708,6 @@ void LLAgentCamera::lookAtLastChat()  			setFocusGlobal(chatter->getPositionGlobal(), gAgent.getLastChatter());  			mCameraFocusOffsetTarget = gAgent.getPosGlobalFromAgent(new_camera_pos) - chatter->getPositionGlobal();  		} -		setFocusOnAvatar(FALSE, TRUE);  	}  	else  	{ @@ -2725,9 +2727,10 @@ void LLAgentCamera::lookAtLastChat()  		new_camera_pos += left * 0.3f;  		new_camera_pos += up * 0.2f; +		setFocusOnAvatar(FALSE, FALSE); +  		setFocusGlobal(chatter->getPositionGlobal(), gAgent.getLastChatter());  		mCameraFocusOffsetTarget = gAgent.getPosGlobalFromAgent(new_camera_pos) - chatter->getPositionGlobal(); -		setFocusOnAvatar(FALSE, TRUE);  	}  } diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index b460885a53..3a98c23e05 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -80,6 +80,8 @@  #include "llfeaturemanager.h"  #include "llurlmatch.h"  #include "lltextutil.h" +#include "lllogininstance.h" +#include "llprogressview.h"  #include "llweb.h"  #include "llsecondlifeurls.h" @@ -192,6 +194,7 @@  #include "llparcel.h"  #include "llavatariconctrl.h"  #include "llgroupiconctrl.h" +#include "llviewerassetstats.h"  // Include for security api initialization  #include "llsecapi.h" @@ -336,6 +339,14 @@ static std::string gWindowTitle;  LLAppViewer::LLUpdaterInfo *LLAppViewer::sUpdaterInfo = NULL ; +//---------------------------------------------------------------------------- +// Metrics logging control constants +//---------------------------------------------------------------------------- +static const F32 METRICS_INTERVAL_DEFAULT = 600.0; +static const F32 METRICS_INTERVAL_QA = 30.0; +static F32 app_metrics_interval = METRICS_INTERVAL_DEFAULT; +static bool app_metrics_qa_mode = false; +  void idle_afk_check()  {  	// check idle timers @@ -593,10 +604,14 @@ LLAppViewer::LLAppViewer() :  	setupErrorHandling();  	sInstance = this;  	gLoggedInTime.stop(); +	 +	LLLoginInstance::instance().setUpdaterService(mUpdater.get());  }  LLAppViewer::~LLAppViewer()  { +	LLLoginInstance::instance().setUpdaterService(0); +	  	destroyMainloopTimeout();  	// If we got to this destructor somehow, the app didn't hang. @@ -655,6 +670,21 @@ bool LLAppViewer::init()      // Called before threads are created.      LLCurl::initClass();      LLMachineID::init(); +	 +	{ +		// Viewer metrics initialization +		static LLCachedControl<bool> metrics_submode(gSavedSettings, +													 "QAModeMetrics", +													 false, +													 "Enables QA features (logging, faster cycling) for metrics collector"); + +		if (metrics_submode) +		{ +			app_metrics_qa_mode = true; +			app_metrics_interval = METRICS_INTERVAL_QA; +		} +		LLViewerAssetStatsFF::init(); +	}      initThreads();      writeSystemInfo(); @@ -1717,6 +1747,8 @@ bool LLAppViewer::cleanup()  	LLWatchdog::getInstance()->cleanup(); +	LLViewerAssetStatsFF::cleanup(); +	  	llinfos << "Shutting down message system" << llendflush;  	end_messaging_system(); @@ -1783,7 +1815,10 @@ bool LLAppViewer::initThreads()  	// Image decoding  	LLAppViewer::sImageDecodeThread = new LLImageDecodeThread(enable_threads && true);  	LLAppViewer::sTextureCache = new LLTextureCache(enable_threads && true); -	LLAppViewer::sTextureFetch = new LLTextureFetch(LLAppViewer::getTextureCache(), sImageDecodeThread, enable_threads && true); +	LLAppViewer::sTextureFetch = new LLTextureFetch(LLAppViewer::getTextureCache(), +													sImageDecodeThread, +													enable_threads && true, +													app_metrics_qa_mode);  	LLImage::initClass();  	if (LLFastTimer::sLog || LLFastTimer::sMetricLog) @@ -2403,26 +2438,120 @@ bool LLAppViewer::initConfiguration()  }  namespace { -    // *TODO - decide if there's a better place for this function. +    // *TODO - decide if there's a better place for these functions.      // do we need a file llupdaterui.cpp or something? -brad + +	void apply_update_callback(LLSD const & notification, LLSD const & response) +	{ +		lldebugs << "LLUpdate user response: " << response << llendl; +		if(response["OK_okcancelbuttons"].asBoolean()) +		{ +			llinfos << "LLUpdate restarting viewer" << llendl; +			static const bool install_if_ready = true; +			// *HACK - this lets us launch the installer immediately for now +			LLUpdaterService().startChecking(install_if_ready); +		} +	} +	 +	void apply_update_ok_callback(LLSD const & notification, LLSD const & response) +	{ +		llinfos << "LLUpdate restarting viewer" << llendl; +		static const bool install_if_ready = true; +		// *HACK - this lets us launch the installer immediately for now +		LLUpdaterService().startChecking(install_if_ready); +	} +	 +	void on_update_downloaded(LLSD const & data) +	{ +		std::string notification_name; +		void (*apply_callback)(LLSD const &, LLSD const &) = NULL; + +		if(data["required"].asBoolean()) +		{ +			apply_callback = &apply_update_ok_callback; +			if(LLStartUp::getStartupState() <= STATE_LOGIN_WAIT) +			{ +				// The user never saw the progress bar. +				notification_name = "RequiredUpdateDownloadedVerboseDialog"; +			} +			else +			{ +				notification_name = "RequiredUpdateDownloadedDialog"; +			} +		} +		else +		{ +			apply_callback = &apply_update_callback; +			if(LLStartUp::getStartupState() < STATE_STARTED) +			{ +				// CHOP-262 we need to use a different notification +				// method prior to login. +				notification_name = "DownloadBackgroundDialog"; +			} +			else +			{ +				notification_name = "DownloadBackgroundTip"; +			} +		} + +		LLSD substitutions; +		substitutions["VERSION"] = data["version"]; + +		// truncate version at the rightmost '.'  +		std::string version_short(data["version"]); +		size_t short_length = version_short.rfind('.'); +		if (short_length != std::string::npos) +		{ +			version_short.resize(short_length); +		} + +		LLUIString relnotes_url("[RELEASE_NOTES_BASE_URL][CHANNEL_URL]/[VERSION_SHORT]"); +		relnotes_url.setArg("[VERSION_SHORT]", version_short); + +		// *TODO thread the update service's response through to this point +		std::string const & channel = LLVersionInfo::getChannel(); +		boost::shared_ptr<char> channel_escaped(curl_escape(channel.c_str(), channel.size()), &curl_free); + +		relnotes_url.setArg("[CHANNEL_URL]", channel_escaped.get()); +		relnotes_url.setArg("[RELEASE_NOTES_BASE_URL]", LLTrans::getString("RELEASE_NOTES_BASE_URL")); +		substitutions["RELEASE_NOTES_FULL_URL"] = relnotes_url.getString(); + +		LLNotificationsUtil::add(notification_name, substitutions, LLSD(), apply_callback); +	} + +	void install_error_callback(LLSD const & notification, LLSD const & response) +	{ +		LLAppViewer::instance()->forceQuit(); +	} +	      bool notify_update(LLSD const & evt)      { +		std::string notification_name;  		switch (evt["type"].asInteger())  		{  			case LLUpdaterService::DOWNLOAD_COMPLETE: -				LLNotificationsUtil::add("DownloadBackground"); +				on_update_downloaded(evt);  				break;  			case LLUpdaterService::INSTALL_ERROR: -				LLNotificationsUtil::add("FailedUpdateInstall"); +				if(evt["required"].asBoolean()) { +					LLNotificationsUtil::add("FailedRequiredUpdateInstall", LLSD(), LLSD(), &install_error_callback); +				} else { +					LLNotificationsUtil::add("FailedUpdateInstall"); +				}  				break;  			default: -				llinfos << "unhandled update event " << evt << llendl;  				break;  		}  		// let others also handle this event by default          return false;      } +	 +	bool on_bandwidth_throttle(LLUpdaterService * updater, LLSD const & evt) +	{ +		updater->setBandwidthLimit(evt.asInteger() * (1024/8)); +		return false; // Let others receive this event. +	};  };  void LLAppViewer::initUpdater() @@ -2445,7 +2574,10 @@ void LLAppViewer::initUpdater()  						 channel,   						 version);   	mUpdater->setCheckPeriod(check_period); -	if(gSavedSettings.getBOOL("UpdaterServiceActive")) +	mUpdater->setBandwidthLimit((int)gSavedSettings.getF32("UpdaterMaximumBandwidth") * (1024/8)); +	gSavedSettings.getControl("UpdaterMaximumBandwidth")->getSignal()-> +		connect(boost::bind(&on_bandwidth_throttle, mUpdater.get(), _2)); +	if(gSavedSettings.getU32("UpdaterServiceSetting"))  	{  		bool install_if_ready = true;  		mUpdater->startChecking(install_if_ready); @@ -2872,8 +3004,10 @@ void LLAppViewer::handleViewerCrash()  		pApp->removeMarkerFile(false);  	} +#if LL_SEND_CRASH_REPORTS  	// Call to pure virtual, handled by platform specific llappviewer instance.  	pApp->handleCrashReporting();  +#endif  	return;  } @@ -3045,6 +3179,9 @@ void LLAppViewer::requestQuit()  		return;  	} +	// Try to send metrics back to the grid +	metricsSend(!gDisconnected); +	  	LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral*)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE);  	effectp->setPositionGlobal(gAgent.getPositionGlobal());  	effectp->setColor(LLColor4U(gAgent.getEffectColor())); @@ -3081,7 +3218,7 @@ static LLNotificationFunctorRegistration finish_quit_reg("ConfirmQuit", finish_q  void LLAppViewer::userQuit()  { -	if (gDisconnected) +	if (gDisconnected || gViewerWindow->getProgressView()->getVisible())  	{  		requestQuit();  	} @@ -3822,6 +3959,11 @@ void LLAppViewer::idle()  				llinfos << "Unknown object updates: " << gObjectList.mNumUnknownUpdates << llendl;  				gObjectList.mNumUnknownUpdates = 0;  			} + +			// ViewerMetrics FPS piggy-backing on the debug timer. +			// The 5-second interval is nice for this purpose.  If the object debug +			// bit moves or is disabled, please give this a suitable home. +			LLViewerAssetStatsFF::record_fps_main(gFPSClamped);  		}  	} @@ -3864,6 +4006,18 @@ void LLAppViewer::idle()  		gInventory.idleNotifyObservers();  	} +	// Metrics logging (LLViewerAssetStats, etc.) +	{ +		static LLTimer report_interval; + +		// *TODO:  Add configuration controls for this +		if (report_interval.getElapsedTimeF32() >= app_metrics_interval) +		{ +			metricsSend(! gDisconnected); +			report_interval.reset(); +		} +	} +  	if (gDisconnected)      {  		return; @@ -4580,6 +4734,35 @@ void LLAppViewer::loadEventHostModule(S32 listen_port)  		return;  	} +	LL_INFOS("eventhost") << "Found lleventhost at '" << dso_path << "'" << LL_ENDL; +#if ! defined(LL_WINDOWS) +	{ +		std::string outfile("/tmp/lleventhost.file.out"); +		std::string command("file '" + dso_path + "' > '" + outfile + "' 2>&1"); +		int rc = system(command.c_str()); +		if (rc != 0) +		{ +			LL_WARNS("eventhost") << command << " ==> " << rc << ':' << LL_ENDL; +		} +		else +		{ +			LL_INFOS("eventhost") << command << ':' << LL_ENDL; +		} +		{ +			std::ifstream reader(outfile.c_str()); +			std::string line; +			while (std::getline(reader, line)) +			{ +				size_t len = line.length(); +				if (len && line[len-1] == '\n') +					line.erase(len-1); +				LL_INFOS("eventhost") << line << LL_ENDL; +			} +		} +		remove(outfile.c_str()); +	} +#endif // LL_WINDOWS +  	apr_dso_handle_t * eventhost_dso_handle = NULL;  	apr_pool_t * eventhost_dso_memory_pool = NULL; @@ -4588,13 +4771,13 @@ void LLAppViewer::loadEventHostModule(S32 listen_port)  	apr_status_t rv = apr_dso_load(&eventhost_dso_handle,  		dso_path.c_str(),  		eventhost_dso_memory_pool); -	ll_apr_assert_status(rv); +	llassert_always(! ll_apr_warn_status(rv, eventhost_dso_handle));  	llassert_always(eventhost_dso_handle != NULL);  	int (*ll_plugin_start_func)(LLSD const &) = NULL;  	rv = apr_dso_sym((apr_dso_handle_sym_t*)&ll_plugin_start_func, eventhost_dso_handle, "ll_plugin_start"); -	ll_apr_assert_status(rv); +	llassert_always(! ll_apr_warn_status(rv, eventhost_dso_handle));  	llassert_always(ll_plugin_start_func != NULL);  	LLSD args; @@ -4766,3 +4949,75 @@ bool LLAppViewer::getMasterSystemAudioMute()  {  	return gSavedSettings.getBOOL("MuteAudio");  } + +//---------------------------------------------------------------------------- +// Metrics-related methods (static and otherwise) +//---------------------------------------------------------------------------- + +/** + * LLViewerAssetStats collects data on a per-region (as defined by the agent's + * location) so we need to tell it about region changes which become a kind of + * hidden variable/global state in the collectors.  For collectors not running + * on the main thread, we need to send a message to move the data over safely + * and cheaply (amortized over a run). + */ +void LLAppViewer::metricsUpdateRegion(U64 region_handle) +{ +	if (0 != region_handle) +	{ +		LLViewerAssetStatsFF::set_region_main(region_handle); +		if (LLAppViewer::sTextureFetch) +		{ +			// Send a region update message into 'thread1' to get the new region. +			LLAppViewer::sTextureFetch->commandSetRegion(region_handle); +		} +		else +		{ +			// No 'thread1', a.k.a. TextureFetch, so update directly +			LLViewerAssetStatsFF::set_region_thread1(region_handle); +		} +	} +} + + +/** + * Attempts to start a multi-threaded metrics report to be sent back to + * the grid for consumption. + */ +void LLAppViewer::metricsSend(bool enable_reporting) +{ +	if (! gViewerAssetStatsMain) +		return; + +	if (LLAppViewer::sTextureFetch) +	{ +		LLViewerRegion * regionp = gAgent.getRegion(); + +		if (enable_reporting && regionp) +		{ +			std::string	caps_url = regionp->getCapability("ViewerMetrics"); + +			// Make a copy of the main stats to send into another thread. +			// Receiving thread takes ownership. +			LLViewerAssetStats * main_stats(new LLViewerAssetStats(*gViewerAssetStatsMain)); +			 +			// Send a report request into 'thread1' to get the rest of the data +			// and provide some additional parameters while here. +			LLAppViewer::sTextureFetch->commandSendMetrics(caps_url, +														   gAgentSessionID, +														   gAgentID, +														   main_stats); +			main_stats = 0;		// Ownership transferred +		} +		else +		{ +			LLAppViewer::sTextureFetch->commandDataBreak(); +		} +	} + +	// Reset even if we can't report.  Rather than gather up a huge chunk of +	// data, we'll keep to our sampling interval and retain the data +	// resolution in time. +	gViewerAssetStatsMain->reset(); +} + diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index 7c946b04a5..a18e6cbb02 100644 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -169,6 +169,10 @@ public:  	// mute/unmute the system's master audio  	virtual void setMasterSystemAudioMute(bool mute);  	virtual bool getMasterSystemAudioMute(); + +	// Metrics policy helper statics. +	static void metricsUpdateRegion(U64 region_handle); +	static void metricsSend(bool enable_reporting);  protected:  	virtual bool initWindow(); // Initialize the viewer's window. diff --git a/indra/newview/llbrowsernotification.cpp b/indra/newview/llbrowsernotification.cpp index d6a813d608..6e77d1e336 100644 --- a/indra/newview/llbrowsernotification.cpp +++ b/indra/newview/llbrowsernotification.cpp @@ -29,8 +29,9 @@  #include "llnotificationhandler.h"  #include "llnotifications.h" -#include "llfloaterreg.h"  #include "llmediactrl.h" +#include "llviewermedia.h" +#include "llviewermediafocus.h"  using namespace LLNotificationsUI; @@ -39,10 +40,19 @@ bool LLBrowserNotification::processNotification(const LLSD& notify)  	LLNotificationPtr notification = LLNotifications::instance().find(notify["id"].asUUID());  	if (!notification) return false; -	LLMediaCtrl* media_instance = LLMediaCtrl::getInstance(notification->getPayload()["media_id"].asUUID()); +	LLUUID media_id = notification->getPayload()["media_id"].asUUID(); +	LLMediaCtrl* media_instance = LLMediaCtrl::getInstance(media_id);  	if (media_instance)  	{  		media_instance->showNotification(notification);  	} +	else if (LLViewerMediaFocus::instance().getControlsMediaID() == media_id) +	{ +		LLViewerMediaImpl* impl = LLViewerMedia::getMediaImplFromTextureID(media_id); +		if (impl) +		{ +			impl->showNotification(notification); +		} +	}  	return false;  } diff --git a/indra/newview/llbuycurrencyhtml.cpp b/indra/newview/llbuycurrencyhtml.cpp index d35c9ed853..e5a9be0203 100644 --- a/indra/newview/llbuycurrencyhtml.cpp +++ b/indra/newview/llbuycurrencyhtml.cpp @@ -33,6 +33,7 @@  #include "llfloaterreg.h"  #include "llcommandhandler.h"  #include "llviewercontrol.h" +#include "llstatusbar.h"  // support for secondlife:///app/buycurrencyhtml/{ACTION}/{NEXT_ACTION}/{RETURN_CODE} SLapps  class LLBuyCurrencyHTMLHandler :  @@ -156,4 +157,7 @@ void LLBuyCurrencyHTML::closeDialog()  	{  		buy_currency_floater->closeFloater();  	}; +	 +	// Update L$ balance in the status bar in case L$ were purchased +	LLStatusBar::sendMoneyBalanceRequest();  } diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp index 6e778de2d8..c98bcbda45 100644 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -586,7 +586,7 @@ void LLChatHistory::initFromParams(const LLChatHistory::Params& p)  	LLLayoutStack::Params layout_p;  	layout_p.rect = stack_rect;  	layout_p.follows.flags = FOLLOWS_ALL; -	layout_p.orientation = "vertical"; +	layout_p.orientation = LLLayoutStack::VERTICAL;  	layout_p.mouse_opaque = false;  	LLLayoutStack* stackp = LLUICtrlFactory::create<LLLayoutStack>(layout_p, this); diff --git a/indra/newview/llfloaterabout.cpp b/indra/newview/llfloaterabout.cpp index 8ae3ccbae3..2873bc0059 100644 --- a/indra/newview/llfloaterabout.cpp +++ b/indra/newview/llfloaterabout.cpp @@ -272,7 +272,7 @@ LLSD LLFloaterAbout::getInfo()  	}  	// TODO: Implement media plugin version query -	info["QT_WEBKIT_VERSION"] = "4.6 (version number hard-coded)"; +	info["QT_WEBKIT_VERSION"] = "4.7.1 (version number hard-coded)";  	if (gPacketsIn > 0)  	{ diff --git a/indra/newview/llfloaterbuycurrency.cpp b/indra/newview/llfloaterbuycurrency.cpp index 58c79fdf15..e21a8594bc 100644 --- a/indra/newview/llfloaterbuycurrency.cpp +++ b/indra/newview/llfloaterbuycurrency.cpp @@ -267,17 +267,23 @@ void LLFloaterBuyCurrencyUI::onClickBuy()  {  	mManager.buy(getString("buy_currency"));  	updateUI(); +	// Update L$ balance +	LLStatusBar::sendMoneyBalanceRequest();  }  void LLFloaterBuyCurrencyUI::onClickCancel()  {  	closeFloater(); +	// Update L$ balance +	LLStatusBar::sendMoneyBalanceRequest();  }  void LLFloaterBuyCurrencyUI::onClickErrorWeb()  {  	LLWeb::loadURLExternal(mManager.errorURI());  	closeFloater(); +	// Update L$ balance +	LLStatusBar::sendMoneyBalanceRequest();  }  // static diff --git a/indra/newview/llfloaterbuycurrencyhtml.cpp b/indra/newview/llfloaterbuycurrencyhtml.cpp index bde620d965..013cf74c7b 100644 --- a/indra/newview/llfloaterbuycurrencyhtml.cpp +++ b/indra/newview/llfloaterbuycurrencyhtml.cpp @@ -82,7 +82,7 @@ void LLFloaterBuyCurrencyHTML::navigateToFinalURL()  	LLStringUtil::format( buy_currency_url, replace );  	// write final URL to debug console -	llinfos << "Buy currency HTML prased URL is " << buy_currency_url << llendl; +	llinfos << "Buy currency HTML parsed URL is " << buy_currency_url << llendl;  	// kick off the navigation  	mBrowser->navigateTo( buy_currency_url, "text/html" ); @@ -105,7 +105,7 @@ void LLFloaterBuyCurrencyHTML::handleMediaEvent( LLPluginClassMedia* self, EMedi  //  void LLFloaterBuyCurrencyHTML::onClose( bool app_quitting )  { -	// update L$ balanace one more time +	// Update L$ balance one more time  	LLStatusBar::sendMoneyBalanceRequest();  	destroy(); diff --git a/indra/newview/llfloaterhelpbrowser.cpp b/indra/newview/llfloaterhelpbrowser.cpp index cec98e9992..a650886d89 100644 --- a/indra/newview/llfloaterhelpbrowser.cpp +++ b/indra/newview/llfloaterhelpbrowser.cpp @@ -132,9 +132,10 @@ void LLFloaterHelpBrowser::onClickOpenWebBrowser(void* user_data)  void LLFloaterHelpBrowser::openMedia(const std::string& media_url)  { -	mBrowser->setHomePageUrl(media_url); -	//mBrowser->navigateTo("data:text/html;charset=utf-8,I'd really love to be going to:<br><b>" + media_url + "</b>"); // tofu HACK for debugging =:) -	mBrowser->navigateTo(media_url); +	// explicitly make the media mime type for this floater since it will +	// only ever display one type of content (Web). +	mBrowser->setHomePageUrl(media_url, "text/html"); +	mBrowser->navigateTo(media_url, "text/html");  	setCurrentURL(media_url);  } diff --git a/indra/newview/llfloatermap.cpp b/indra/newview/llfloatermap.cpp index 351b9ac5da..1b94d8cbcd 100644 --- a/indra/newview/llfloatermap.cpp +++ b/indra/newview/llfloatermap.cpp @@ -83,7 +83,6 @@ LLFloaterMap::~LLFloaterMap()  BOOL LLFloaterMap::postBuild()  {  	mMap = getChild<LLNetMap>("Net Map"); -	mMap->setScale(gSavedSettings.getF32("MiniMapScale"));  	mMap->setToolTipMsg(getString("ToolTipMsg"));	  	sendChildToBack(mMap); @@ -288,7 +287,16 @@ void LLFloaterMap::handleZoom(const LLSD& userdata)  	std::string level = userdata.asString();  	F32 scale = 0.0f; -	if (level == std::string("close")) +	if (level == std::string("default")) +	{ +		LLControlVariable *pvar = gSavedSettings.getControl("MiniMapScale"); +		if(pvar) +		{ +			pvar->resetToDefault(); +			scale = gSavedSettings.getF32("MiniMapScale"); +		} +	} +	else if (level == std::string("close"))  		scale = LLNetMap::MAP_SCALE_MAX;  	else if (level == std::string("medium"))  		scale = LLNetMap::MAP_SCALE_MID; @@ -296,7 +304,6 @@ void LLFloaterMap::handleZoom(const LLSD& userdata)  		scale = LLNetMap::MAP_SCALE_MIN;  	if (scale != 0.0f)  	{ -		gSavedSettings.setF32("MiniMapScale", scale );  		mMap->setScale(scale);  	}  } diff --git a/indra/newview/llfloatermediabrowser.cpp b/indra/newview/llfloatermediabrowser.cpp index d20092e344..7a670dd90c 100644 --- a/indra/newview/llfloatermediabrowser.cpp +++ b/indra/newview/llfloatermediabrowser.cpp @@ -306,17 +306,14 @@ void LLFloaterMediaBrowser::setCurrentURL(const std::string& url)  {  	mCurrentURL = url; -	// redirects will navigate momentarily to about:blank, don't add to history -	if (mCurrentURL != "about:blank") -	{ -		mAddressCombo->remove(mCurrentURL); -		mAddressCombo->add(mCurrentURL); -		mAddressCombo->selectByValue(mCurrentURL); +	mAddressCombo->remove(mCurrentURL); +	mAddressCombo->add(mCurrentURL); +	mAddressCombo->selectByValue(mCurrentURL); + +	// Serialize url history +	LLURLHistory::removeURL("browser", mCurrentURL); +	LLURLHistory::addURL("browser", mCurrentURL); -		// Serialize url history -		LLURLHistory::removeURL("browser", mCurrentURL); -		LLURLHistory::addURL("browser", mCurrentURL); -	}  	getChildView("back")->setEnabled(mBrowser->canNavigateBack());  	getChildView("forward")->setEnabled(mBrowser->canNavigateForward());  	getChildView("reload")->setEnabled(TRUE); @@ -334,8 +331,15 @@ void LLFloaterMediaBrowser::onClickRefresh(void* user_data)  {  	LLFloaterMediaBrowser* self = (LLFloaterMediaBrowser*)user_data; -	self->mAddressCombo->remove(0); -	self->mBrowser->navigateTo(self->mCurrentURL); +	if( self->mBrowser->getMediaPlugin() &&  self->mBrowser->getMediaPlugin()->pluginSupportsMediaBrowser()) +	{ +		bool ignore_cache = true; +		self->mBrowser->getMediaPlugin()->browse_reload( ignore_cache ); +	} +	else +	{ +		self->mBrowser->navigateTo(self->mCurrentURL); +	}  }  //static  diff --git a/indra/newview/llfloaterpostcard.cpp b/indra/newview/llfloaterpostcard.cpp index 054ab4538b..dd0b1d999c 100644 --- a/indra/newview/llfloaterpostcard.cpp +++ b/indra/newview/llfloaterpostcard.cpp @@ -366,7 +366,9 @@ void LLFloaterPostcard::sendPostcard()  	{  		gAssetStorage->storeAssetData(mTransactionID, LLAssetType::AT_IMAGE_JPEG, &uploadCallback, (void *)this, FALSE);  	} - +	 +	// give user feedback of the event +	gViewerWindow->playSnapshotAnimAndSound();  	LLUploadDialog::modalUploadDialog(getString("upload_message"));  	// don't destroy the window until the upload is done diff --git a/indra/newview/llfloatersearch.cpp b/indra/newview/llfloatersearch.cpp index 3ed4aec89a..2041fac8d8 100644 --- a/indra/newview/llfloatersearch.cpp +++ b/indra/newview/llfloatersearch.cpp @@ -200,5 +200,5 @@ void LLFloaterSearch::search(const LLSD &key)  	url = LLWeb::expandURLSubstitutions(url, subs);  	// and load the URL in the web view -	mBrowser->navigateTo(url); +	mBrowser->navigateTo(url, "text/html");  } diff --git a/indra/newview/llfloatersnapshot.cpp b/indra/newview/llfloatersnapshot.cpp index 1aba5ef92f..0931f77281 100644 --- a/indra/newview/llfloatersnapshot.cpp +++ b/indra/newview/llfloatersnapshot.cpp @@ -908,8 +908,6 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview )  			previewp->mPosTakenGlobal = gAgentCamera.getCameraPositionGlobal();  			previewp->mShineCountdown = 4; // wait a few frames to avoid animation glitch due to readback this frame  		} - -		gViewerWindow->playSnapshotAnimAndSound();  	}  	previewp->getWindow()->decBusyCount();  	// only show fullscreen preview when in freeze frame mode @@ -1006,6 +1004,7 @@ void LLSnapshotLivePreview::saveTexture()  				    LLFloaterPerms::getEveryonePerms(),  				    "Snapshot : " + pos_string,  				    callback, expected_upload_cost, userdata); +		gViewerWindow->playSnapshotAnimAndSound();  	}  	else  	{ @@ -1027,6 +1026,10 @@ BOOL LLSnapshotLivePreview::saveLocal()  	mDataSize = 0;  	updateSnapshot(FALSE, FALSE); +	if(success) +	{ +		gViewerWindow->playSnapshotAnimAndSound(); +	}  	return success;  } @@ -1046,6 +1049,8 @@ void LLSnapshotLivePreview::saveWeb()  	LLLandmarkActions::getRegionNameAndCoordsFromPosGlobal(gAgentCamera.getCameraPositionGlobal(),  		boost::bind(&LLSnapshotLivePreview::regionNameCallback, this, jpg, metadata, _1, _2, _3, _4)); + +	gViewerWindow->playSnapshotAnimAndSound();  }  void LLSnapshotLivePreview::regionNameCallback(LLImageJPEG* snapshot, LLSD& metadata, const std::string& name, S32 x, S32 y, S32 z) diff --git a/indra/newview/llfloaterwebcontent.cpp b/indra/newview/llfloaterwebcontent.cpp new file mode 100644 index 0000000000..51726112a0 --- /dev/null +++ b/indra/newview/llfloaterwebcontent.cpp @@ -0,0 +1,402 @@ +/**
 + * @file llfloaterwebcontent.cpp
 + * @brief floater for displaying web content - e.g. profiles and search (eventually)
 + *
 + * $LicenseInfo:firstyear=2006&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 "llcombobox.h"
 +#include "lliconctrl.h"
 +#include "llfloaterreg.h"
 +#include "lllayoutstack.h"
 +#include "llpluginclassmedia.h"
 +#include "llprogressbar.h"
 +#include "lltextbox.h"
 +#include "llurlhistory.h"
 +#include "llviewercontrol.h"
 +#include "llweb.h"
 +#include "llwindow.h"
 +
 +#include "llfloaterwebcontent.h"
 +
 +LLFloaterWebContent::LLFloaterWebContent( const LLSD& key )
 +	: LLFloater( key )
 +{
 +	mCommitCallbackRegistrar.add( "WebContent.Back", boost::bind( &LLFloaterWebContent::onClickBack, this ));
 +	mCommitCallbackRegistrar.add( "WebContent.Forward", boost::bind( &LLFloaterWebContent::onClickForward, this ));
 +	mCommitCallbackRegistrar.add( "WebContent.Reload", boost::bind( &LLFloaterWebContent::onClickReload, this ));
 +	mCommitCallbackRegistrar.add( "WebContent.Stop", boost::bind( &LLFloaterWebContent::onClickStop, this ));
 +	mCommitCallbackRegistrar.add( "WebContent.EnterAddress", boost::bind( &LLFloaterWebContent::onEnterAddress, this ));
 +	mCommitCallbackRegistrar.add( "WebContent.PopExternal", boost::bind( &LLFloaterWebContent::onPopExternal, this ));
 +}
 +
 +BOOL LLFloaterWebContent::postBuild()
 +{
 +	// these are used in a bunch of places so cache them
 +	mWebBrowser = getChild< LLMediaCtrl >( "webbrowser" );
 +	mAddressCombo = getChild< LLComboBox >( "address" );
 +	mStatusBarText = getChild< LLTextBox >( "statusbartext" );
 +	mStatusBarProgress = getChild<LLProgressBar>("statusbarprogress" );
 +
 +	// observe browser events
 +	mWebBrowser->addObserver( this );
 +
 +	// these buttons are always enabled
 +	getChildView("reload")->setEnabled( true );
 +	getChildView("popexternal")->setEnabled( true );
 +
 +	// cache image for secure browsing
 +	mSecureLockIcon = getChild< LLIconCtrl >("media_secure_lock_flag");
 +
 +	// initialize the URL history using the system URL History manager
 +	initializeURLHistory();
 +
 +	return TRUE;
 +}
 +
 +void LLFloaterWebContent::initializeURLHistory()
 +{
 +	// start with an empty list
 +	LLCtrlListInterface* url_list = childGetListInterface("address");
 +	if (url_list)
 +	{
 +		url_list->operateOnAll(LLCtrlListInterface::OP_DELETE);
 +	}
 +
 +	// Get all of the entries in the "browser" collection
 +	LLSD browser_history = LLURLHistory::getURLHistory("browser");
 +	LLSD::array_iterator iter_history =
 +		browser_history.beginArray();
 +	LLSD::array_iterator end_history =
 +		browser_history.endArray();
 +	for(; iter_history != end_history; ++iter_history)
 +	{
 +		std::string url = (*iter_history).asString();
 +		if(! url.empty())
 +			url_list->addSimpleElement(url);
 +	}
 +}
 +
 +//static
 +void LLFloaterWebContent::create( const std::string &url, const std::string& target, const std::string& uuid )
 +{
 +	lldebugs << "url = " << url << ", target = " << target << ", uuid = " << uuid << llendl;
 +
 +	std::string tag = target;
 +
 +	if(target.empty() || target == "_blank")
 +	{
 +		if(!uuid.empty())
 +		{
 +			tag = uuid;
 +		}
 +		else
 +		{
 +			// create a unique tag for this instance
 +			LLUUID id;
 +			id.generate();
 +			tag = id.asString();
 +		}
 +	}
 +
 +	S32 browser_window_limit = gSavedSettings.getS32("WebContentWindowLimit");
 +
 +	if(LLFloaterReg::findInstance("web_content", tag) != NULL)
 +	{
 +		// There's already a web browser for this tag, so we won't be opening a new window.
 +	}
 +	else if(browser_window_limit != 0)
 +	{
 +		// showInstance will open a new window.  Figure out how many web browsers are already open,
 +		// and close the least recently opened one if this will put us over the limit.
 +
 +		LLFloaterReg::const_instance_list_t &instances = LLFloaterReg::getFloaterList("web_content");
 +		lldebugs << "total instance count is " << instances.size() << llendl;
 +
 +		for(LLFloaterReg::const_instance_list_t::const_iterator iter = instances.begin(); iter != instances.end(); iter++)
 +		{
 +			lldebugs << "    " << (*iter)->getKey() << llendl;
 +		}
 +
 +		if(instances.size() >= (size_t)browser_window_limit)
 +		{
 +			// Destroy the least recently opened instance
 +			(*instances.begin())->closeFloater();
 +		}
 +	}
 +
 +	LLFloaterWebContent *browser = dynamic_cast<LLFloaterWebContent*> (LLFloaterReg::showInstance("web_content", tag));
 +	llassert(browser);
 +	if(browser)
 +	{
 +		browser->mUUID = uuid;
 +
 +		// tell the browser instance to load the specified URL
 +		browser->open_media(url, target);
 +		LLViewerMedia::proxyWindowOpened(target, uuid);
 +	}
 +}
 +
 +//static
 +void LLFloaterWebContent::closeRequest(const std::string &uuid)
 +{
 +	LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("web_content");
 +	lldebugs << "instance list size is " << inst_list.size() << ", incoming uuid is " << uuid << llendl;
 +	for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); iter != inst_list.end(); ++iter)
 +	{
 +		LLFloaterWebContent* i = dynamic_cast<LLFloaterWebContent*>(*iter);
 +		lldebugs << "    " << i->mUUID << llendl;
 +		if (i && i->mUUID == uuid)
 +		{
 +			i->closeFloater(false);
 +			return;
 + 		}
 + 	}
 +}
 +
 +//static
 +void LLFloaterWebContent::geometryChanged(const std::string &uuid, S32 x, S32 y, S32 width, S32 height)
 +{
 +	LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("web_content");
 +	lldebugs << "instance list size is " << inst_list.size() << ", incoming uuid is " << uuid << llendl;
 +	for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); iter != inst_list.end(); ++iter)
 +	{
 +		LLFloaterWebContent* i = dynamic_cast<LLFloaterWebContent*>(*iter);
 +		lldebugs << "    " << i->mUUID << llendl;
 +		if (i && i->mUUID == uuid)
 +		{
 +			i->geometryChanged(x, y, width, height);
 +			return;
 +		}
 +	}
 +}
 +
 +void LLFloaterWebContent::geometryChanged(S32 x, S32 y, S32 width, S32 height)
 +{
 +	// Make sure the layout of the browser control is updated, so this calculation is correct.
 +	LLLayoutStack::updateClass();
 +
 +	// TODO: need to adjust size and constrain position to make sure floaters aren't moved outside the window view, etc.
 +	LLCoordWindow window_size;
 +	getWindow()->getSize(&window_size);
 +
 +	// Adjust width and height for the size of the chrome on the web Browser window.
 +	width += getRect().getWidth() - mWebBrowser->getRect().getWidth();
 +	height += getRect().getHeight() - mWebBrowser->getRect().getHeight();
 +
 +	LLRect geom;
 +	geom.setOriginAndSize(x, window_size.mY - (y + height), width, height);
 +
 +	lldebugs << "geometry change: " << geom << llendl;
 +
 +	handleReshape(geom,false);
 +}
 +
 +void LLFloaterWebContent::open_media(const std::string& web_url, const std::string& target)
 +{
 +	// Specifying a mime type of text/html here causes the plugin system to skip the MIME type probe and just open a browser plugin.
 +	mWebBrowser->setHomePageUrl(web_url, "text/html");
 +	mWebBrowser->setTarget(target);
 +	mWebBrowser->navigateTo(web_url, "text/html");
 +	set_current_url(web_url);
 +}
 +
 +//virtual
 +void LLFloaterWebContent::onClose(bool app_quitting)
 +{
 +	LLViewerMedia::proxyWindowClosed(mUUID);
 +	destroy();
 +}
 +
 +// virtual
 +void LLFloaterWebContent::draw()
 +{
 +	// this is asychronous so we need to keep checking
 +	getChildView( "back" )->setEnabled( mWebBrowser->canNavigateBack() );
 +	getChildView( "forward" )->setEnabled( mWebBrowser->canNavigateForward() );
 +
 +	LLFloater::draw();
 +}
 +
 +// virtual
 +void LLFloaterWebContent::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event)
 +{
 +	if(event == MEDIA_EVENT_LOCATION_CHANGED)
 +	{
 +		const std::string url = self->getLocation();
 +
 +		if ( url.length() )
 +			mStatusBarText->setText( url );
 +
 +		set_current_url( url );
 +	}
 +	else if(event == MEDIA_EVENT_NAVIGATE_BEGIN)
 +	{
 +		// flags are sent with this event
 +		getChildView("back")->setEnabled( self->getHistoryBackAvailable() );
 +		getChildView("forward")->setEnabled( self->getHistoryForwardAvailable() );
 +
 +		// toggle visibility of these buttons based on browser state
 +		getChildView("reload")->setVisible( false );
 +		getChildView("stop")->setVisible( true );
 +
 +		// turn "on" progress bar now we're about to start loading
 +		mStatusBarProgress->setVisible( true );
 +	}
 +	else if(event == MEDIA_EVENT_NAVIGATE_COMPLETE)
 +	{
 +		// flags are sent with this event
 +		getChildView("back")->setEnabled( self->getHistoryBackAvailable() );
 +		getChildView("forward")->setEnabled( self->getHistoryForwardAvailable() );
 +
 +		// toggle visibility of these buttons based on browser state
 +		getChildView("reload")->setVisible( true );
 +		getChildView("stop")->setVisible( false );
 +
 +		// turn "off" progress bar now we're loaded
 +		mStatusBarProgress->setVisible( false );
 +
 +		// we populate the status bar with URLs as they change so clear it now we're done
 +		const std::string end_str = "";
 +		mStatusBarText->setText( end_str );
 +
 +		// decide if secure browsing icon should be displayed
 +		std::string prefix =  std::string("https://");
 +		std::string test_prefix = mCurrentURL.substr(0, prefix.length());
 +		LLStringUtil::toLower(test_prefix);
 +		if(test_prefix == prefix)
 +		{
 +			mSecureLockIcon->setVisible(true);
 +		}
 +		else
 +		{
 +			mSecureLockIcon->setVisible(false);
 +		}
 +	}
 +	else if(event == MEDIA_EVENT_CLOSE_REQUEST)
 +	{
 +		// The browser instance wants its window closed.
 +		closeFloater();
 +	}
 +	else if(event == MEDIA_EVENT_GEOMETRY_CHANGE)
 +	{
 +		geometryChanged(self->getGeometryX(), self->getGeometryY(), self->getGeometryWidth(), self->getGeometryHeight());
 +	}
 +	else if(event == MEDIA_EVENT_STATUS_TEXT_CHANGED )
 +	{
 +		const std::string text = self->getStatusText();
 +		if ( text.length() )
 +			mStatusBarText->setText( text );
 +	}
 +	else if(event == MEDIA_EVENT_PROGRESS_UPDATED )
 +	{
 +		int percent = (int)self->getProgressPercent();
 +		mStatusBarProgress->setValue( percent );
 +	}
 +	else if(event == MEDIA_EVENT_NAME_CHANGED )
 +	{
 +		std::string page_title = self->getMediaName();
 +		// simulate browser behavior - title is empty, use the current URL
 +		if ( page_title.length() > 0 )
 +			setTitle( page_title );
 +		else
 +			setTitle( mCurrentURL );
 +	}
 +	else if(event == MEDIA_EVENT_LINK_HOVERED )
 +	{
 +		const std::string link = self->getHoverLink();
 +		mStatusBarText->setText( link );
 +	}
 +}
 +
 +void LLFloaterWebContent::set_current_url(const std::string& url)
 +{
 +	mCurrentURL = url;
 +
 +	// serialize url history into the system URL History manager
 +	LLURLHistory::removeURL("browser", mCurrentURL);
 +	LLURLHistory::addURL("browser", mCurrentURL);
 +
 +	mAddressCombo->remove( mCurrentURL );
 +	mAddressCombo->add( mCurrentURL );
 +	mAddressCombo->selectByValue( mCurrentURL );
 +}
 +
 +void LLFloaterWebContent::onClickForward()
 +{
 +	mWebBrowser->navigateForward();
 +}
 +
 +void LLFloaterWebContent::onClickBack()
 +{
 +	mWebBrowser->navigateBack();
 +}
 +
 +void LLFloaterWebContent::onClickReload()
 +{
 +
 +	if( mWebBrowser->getMediaPlugin() )
 +	{
 +		bool ignore_cache = true;
 +		mWebBrowser->getMediaPlugin()->browse_reload( ignore_cache );
 +	}
 +	else
 +	{
 +		mWebBrowser->navigateTo(mCurrentURL);
 +	}
 +}
 +
 +void LLFloaterWebContent::onClickStop()
 +{
 +	if( mWebBrowser->getMediaPlugin() )
 +		mWebBrowser->getMediaPlugin()->browse_stop();
 +
 +	// still should happen when we catch the navigate complete event
 +	// but sometimes (don't know why) that event isn't sent from Qt
 +	// and we getto a point where the stop button stays active.
 +	getChildView("reload")->setVisible( true );
 +	getChildView("stop")->setVisible( false );
 +}
 +
 +void LLFloaterWebContent::onEnterAddress()
 +{
 +	// make sure there is at least something there.
 +	// (perhaps this test should be for minimum length of a URL)
 +	std::string url = mAddressCombo->getValue().asString();
 +	if ( url.length() > 0 )
 +	{
 +		mWebBrowser->navigateTo( url, "text/html");
 +	};
 +}
 +
 +void LLFloaterWebContent::onPopExternal()
 +{
 +	// make sure there is at least something there.
 +	// (perhaps this test should be for minimum length of a URL)
 +	std::string url = mAddressCombo->getValue().asString();
 +	if ( url.length() > 0 )
 +	{
 +		LLWeb::loadURLExternal( url );
 +	};
 +}
 diff --git a/indra/newview/llfloaterwebcontent.h b/indra/newview/llfloaterwebcontent.h new file mode 100644 index 0000000000..001d822ada --- /dev/null +++ b/indra/newview/llfloaterwebcontent.h @@ -0,0 +1,82 @@ +/**
 + * @file llfloaterwebcontent.h
 + * @brief floater for displaying web content - e.g. profiles and search (eventually)
 + *
 + * $LicenseInfo:firstyear=2006&license=viewerlgpl$
 + * Second Life Viewer Source Code
 + * Copyright (C) 2010, Linden Research, Inc.
 + *
 + * This library is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation;
 + * version 2.1 of the License only.
 + *
 + * This library is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
 + * License along with this library; if not, write to the Free Software
 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 + *
 + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 + * $/LicenseInfo$
 + */
 +
 +#ifndef LL_LLFLOATERWEBCONTENT_H
 +#define LL_LLFLOATERWEBCONTENT_H
 +
 +#include "llfloater.h"
 +#include "llmediactrl.h"
 +
 +class LLMediaCtrl;
 +class LLComboBox;
 +class LLTextBox;
 +class LLProgressBar;
 +class LLIconCtrl;
 +
 +class LLFloaterWebContent :
 +	public LLFloater,
 +	public LLViewerMediaObserver
 +{
 +public:
 +    LOG_CLASS(LLFloaterWebContent);
 +	LLFloaterWebContent(const LLSD& key);
 +
 +	void initializeURLHistory(); +
 +	static void create(const std::string &url, const std::string& target, const std::string& uuid = LLStringUtil::null);
 +
 +	static void closeRequest(const std::string &uuid);
 +	static void geometryChanged(const std::string &uuid, S32 x, S32 y, S32 width, S32 height);
 +	void geometryChanged(S32 x, S32 y, S32 width, S32 height);
 +
 +	/* virtual */ BOOL postBuild();
 +	/* virtual */ void onClose(bool app_quitting);
 +	/* virtual */ void draw();
 +
 +	// inherited from LLViewerMediaObserver
 +	/*virtual*/ void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event);
 +
 +	void onClickBack();
 +	void onClickForward();
 +	void onClickReload();
 +	void onClickStop();
 +	void onEnterAddress();
 +	void onPopExternal();
 +
 +private:
 +	void open_media(const std::string& media_url, const std::string& target);
 +	void set_current_url(const std::string& url);
 +
 +	LLMediaCtrl* mWebBrowser;
 +	LLComboBox* mAddressCombo;
 +	LLIconCtrl *mSecureLockIcon;
 +	LLTextBox* mStatusBarText;
 +	LLProgressBar* mStatusBarProgress;
 +	std::string mCurrentURL;
 +	std::string mUUID;
 +};
 +
 +#endif  // LL_LLFLOATERWEBCONTENT_H
 diff --git a/indra/newview/llimfloater.cpp b/indra/newview/llimfloater.cpp index bdc0dfa7e2..f74ae92a7b 100644 --- a/indra/newview/llimfloater.cpp +++ b/indra/newview/llimfloater.cpp @@ -470,7 +470,7 @@ LLIMFloater* LLIMFloater::show(const LLUUID& session_id)  }  //static -bool LLIMFloater::resetAllowedRectPadding(const LLSD& newvalue) +bool LLIMFloater::resetAllowedRectPadding()  {  	//reset allowed rect right padding if "SidebarCameraMovement" option   	//or sidebar state changed @@ -482,10 +482,10 @@ void LLIMFloater::getAllowedRect(LLRect& rect)  {  	if (sAllowedRectRightPadding == RECT_PADDING_NOT_INIT) //wasn't initialized  	{ -		gSavedSettings.getControl("SidebarCameraMovement")->getSignal()->connect(boost::bind(&LLIMFloater::resetAllowedRectPadding, _2)); +		gSavedSettings.getControl("SidebarCameraMovement")->getSignal()->connect(boost::bind(&LLIMFloater::resetAllowedRectPadding));  		LLSideTray*	side_bar = LLSideTray::getInstance(); -		side_bar->getCollapseSignal().connect(boost::bind(&LLIMFloater::resetAllowedRectPadding, _2)); +		side_bar->setVisibleWidthChangeCallback(boost::bind(&LLIMFloater::resetAllowedRectPadding));  		sAllowedRectRightPadding = RECT_PADDING_NEED_RECALC;  	} @@ -500,10 +500,7 @@ void LLIMFloater::getAllowedRect(LLRect& rect)  		if (gSavedSettings.getBOOL("SidebarCameraMovement") == FALSE)  		{ -			LLSideTray*	side_bar = LLSideTray::getInstance(); - -			if (side_bar->getVisible() && !side_bar->getCollapsed()) -				sAllowedRectRightPadding += side_bar->getRect().getWidth(); +			sAllowedRectRightPadding += LLSideTray::getInstance()->getVisibleWidth();  		}  	}  	rect.mRight -= sAllowedRectRightPadding; diff --git a/indra/newview/llimfloater.h b/indra/newview/llimfloater.h index e80e45e64a..5158f6c1f7 100644 --- a/indra/newview/llimfloater.h +++ b/indra/newview/llimfloater.h @@ -156,7 +156,7 @@ private:  	static void closeHiddenIMToasts(); -	static bool resetAllowedRectPadding(const LLSD& newvalue); +	static bool resetAllowedRectPadding();  	//need to keep this static for performance issues  	static S32 sAllowedRectRightPadding; diff --git a/indra/newview/llinspecttoast.cpp b/indra/newview/llinspecttoast.cpp index 58b3f0309f..d7b82667d1 100644 --- a/indra/newview/llinspecttoast.cpp +++ b/indra/newview/llinspecttoast.cpp @@ -46,6 +46,7 @@ public:  	virtual ~LLInspectToast();  	/*virtual*/ void onOpen(const LLSD& notification_id); +	/*virtual*/ BOOL handleToolTip(S32 x, S32 y, MASK mask);  private:  	void onToastDestroy(LLToast * toast); @@ -73,6 +74,7 @@ LLInspectToast::~LLInspectToast()  	LLTransientFloaterMgr::getInstance()->removeControlView(this);  } +// virtual  void LLInspectToast::onOpen(const LLSD& notification_id)  {  	LLInspect::onOpen(notification_id); @@ -103,6 +105,15 @@ void LLInspectToast::onOpen(const LLSD& notification_id)  	LLUI::positionViewNearMouse(this);  } +// virtual +BOOL LLInspectToast::handleToolTip(S32 x, S32 y, MASK mask) +{ +	// We don't like the way LLInspect handles tooltips +	// (black tooltips look weird), +	// so force using the default implementation (STORM-511). +	return LLFloater::handleToolTip(x, y, mask); +} +  void LLInspectToast::onToastDestroy(LLToast * toast)  {  	closeFloater(false); diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 5ba87423c7..5108f68592 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -104,6 +104,7 @@ void remove_inventory_category_from_avatar_step2( BOOL proceed, LLUUID category_  bool move_task_inventory_callback(const LLSD& notification, const LLSD& response, LLMoveInv*);  bool confirm_attachment_rez(const LLSD& notification, const LLSD& response);  void teleport_via_landmark(const LLUUID& asset_id); +static BOOL can_move_to_outfit(LLInventoryItem* inv_item, BOOL move_is_into_current_outfit);  // +=================================================+  // |        LLInvFVBridge                            | @@ -2341,6 +2342,10 @@ void LLFolderBridge::pasteFromClipboard()  	LLInventoryModel* model = getInventoryModel();  	if(model && isClipboardPasteable())  	{ +		const LLUUID ¤t_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false); +		const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id); +		const BOOL move_is_into_outfit = (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT); +  		const LLUUID parent_id(mUUID);  		LLDynamicArray<LLUUID> objects; @@ -2353,7 +2358,14 @@ void LLFolderBridge::pasteFromClipboard()  			LLInventoryItem *item = model->getItem(item_id);  			if (item)  			{ -				if(LLInventoryClipboard::instance().isCutMode()) +				if (move_is_into_current_outfit || move_is_into_outfit) +				{ +					if (can_move_to_outfit(item, move_is_into_current_outfit)) +					{ +						dropToOutfit(item, move_is_into_current_outfit); +					} +				} +				else if(LLInventoryClipboard::instance().isCutMode())  				{  					// move_inventory_item() is not enough,  					//we have to update inventory locally too @@ -2381,9 +2393,13 @@ void LLFolderBridge::pasteFromClipboard()  void LLFolderBridge::pasteLinkFromClipboard()  { -	const LLInventoryModel* model = getInventoryModel(); +	LLInventoryModel* model = getInventoryModel();  	if(model)  	{ +		const LLUUID ¤t_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false); +		const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id); +		const BOOL move_is_into_outfit = (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT); +  		const LLUUID parent_id(mUUID);  		LLDynamicArray<LLUUID> objects; @@ -2393,7 +2409,15 @@ void LLFolderBridge::pasteLinkFromClipboard()  			 ++iter)  		{  			const LLUUID &object_id = (*iter); -			if (LLInventoryCategory *cat = model->getCategory(object_id)) +			if (move_is_into_current_outfit || move_is_into_outfit) +			{ +				LLInventoryItem *item = model->getItem(object_id); +				if (item && can_move_to_outfit(item, move_is_into_current_outfit)) +				{ +					dropToOutfit(item, move_is_into_current_outfit); +				} +			} +			else if (LLInventoryCategory *cat = model->getCategory(object_id))  			{  				const std::string empty_description = "";  				link_inventory_item( @@ -5320,11 +5344,6 @@ void LLRecentItemsFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags)  	menuentry_vec_t disabled_items, items = getMenuItems(); -	items.erase(std::remove(items.begin(), items.end(), std::string("New Body Parts")), items.end()); -	items.erase(std::remove(items.begin(), items.end(), std::string("New Clothes")), items.end()); -	items.erase(std::remove(items.begin(), items.end(), std::string("New Note")), items.end()); -	items.erase(std::remove(items.begin(), items.end(), std::string("New Gesture")), items.end()); -	items.erase(std::remove(items.begin(), items.end(), std::string("New Script")), items.end());  	items.erase(std::remove(items.begin(), items.end(), std::string("New Folder")), items.end());  	hide_context_entries(menu, items, disabled_items); diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp index 0546803784..d866db1829 100644 --- a/indra/newview/lllogininstance.cpp +++ b/indra/newview/lllogininstance.cpp @@ -49,18 +49,421 @@  #include "llnotifications.h"  #include "llwindow.h"  #include "llviewerwindow.h" +#include "llprogressview.h"  #if LL_LINUX || LL_SOLARIS  #include "lltrans.h"  #endif  #include "llsecapi.h"  #include "llstartup.h"  #include "llmachineid.h" +#include "llupdaterservice.h" +#include "llevents.h" +#include "llnotificationsutil.h" +#include "llappviewer.h" + +#include <boost/scoped_ptr.hpp> +#include <sstream> + +class LLLoginInstance::Disposable { +public: +	virtual ~Disposable() {} +}; + +namespace { +	class MandatoryUpdateMachine: +		public LLLoginInstance::Disposable +	{ +	public: +		MandatoryUpdateMachine(LLLoginInstance & loginInstance, LLUpdaterService & updaterService); +		 +		void start(void); +		 +	private: +		class State; +		class CheckingForUpdate; +		class Error; +		class ReadyToInstall;  +		class StartingUpdaterService; +		class WaitingForDownload; +		 +		LLLoginInstance & mLoginInstance; +		boost::scoped_ptr<State> mState; +		LLUpdaterService & mUpdaterService; +		 +		void setCurrentState(State * newState); +	}; + +	 +	class MandatoryUpdateMachine::State { +	public: +		virtual ~State() {} +		virtual void enter(void) {} +		virtual void exit(void) {} +	}; +	 +	 +	class MandatoryUpdateMachine::CheckingForUpdate: +	public MandatoryUpdateMachine::State +	{ +	public: +		CheckingForUpdate(MandatoryUpdateMachine & machine); +		 +		virtual void enter(void); +		virtual void exit(void); +		 +	private: +		LLTempBoundListener mConnection; +		MandatoryUpdateMachine & mMachine; +		LLProgressView * mProgressView; +		 +		bool onEvent(LLSD const & event); +	}; +	 +	 +	class MandatoryUpdateMachine::Error: +	public MandatoryUpdateMachine::State +	{ +	public: +		Error(MandatoryUpdateMachine & machine); +		 +		virtual void enter(void); +		virtual void exit(void); +		void onButtonClicked(const LLSD &, const LLSD &); +		 +	private: +		MandatoryUpdateMachine & mMachine; +	}; +	 +	 +	class MandatoryUpdateMachine::ReadyToInstall: +	public MandatoryUpdateMachine::State +	{ +	public: +		ReadyToInstall(MandatoryUpdateMachine & machine); +		 +		virtual void enter(void); +		virtual void exit(void); +		 +	private: +		MandatoryUpdateMachine & mMachine; +	}; +	 +	 +	class MandatoryUpdateMachine::StartingUpdaterService: +	public MandatoryUpdateMachine::State +	{ +	public: +		StartingUpdaterService(MandatoryUpdateMachine & machine); +		 +		virtual void enter(void); +		virtual void exit(void); +		void onButtonClicked(const LLSD & uiform, const LLSD & result); +	private: +		MandatoryUpdateMachine & mMachine; +	}; +	 +	 +	class MandatoryUpdateMachine::WaitingForDownload: +		public MandatoryUpdateMachine::State +	{ +	public: +		WaitingForDownload(MandatoryUpdateMachine & machine); +		 +		virtual void enter(void); +		virtual void exit(void); +		 +	private: +		LLTempBoundListener mConnection; +		MandatoryUpdateMachine & mMachine; +		LLProgressView * mProgressView; +		 +		bool onEvent(LLSD const & event); +	}; +}  static const char * const TOS_REPLY_PUMP = "lllogininstance_tos_callback";  static const char * const TOS_LISTENER_NAME = "lllogininstance_tos";  std::string construct_start_string(); + + +// MandatoryUpdateMachine +//----------------------------------------------------------------------------- + + +MandatoryUpdateMachine::MandatoryUpdateMachine(LLLoginInstance & loginInstance, LLUpdaterService & updaterService): +	mLoginInstance(loginInstance), +	mUpdaterService(updaterService) +{ +	; // No op. +} + + +void MandatoryUpdateMachine::start(void) +{ +	llinfos << "starting manditory update machine" << llendl; +	 +	if(mUpdaterService.isChecking()) { +		switch(mUpdaterService.getState()) { +			case LLUpdaterService::UP_TO_DATE: +				mUpdaterService.stopChecking(); +				mUpdaterService.startChecking(); +				// Fall through. +			case LLUpdaterService::INITIAL: +			case LLUpdaterService::CHECKING_FOR_UPDATE: +				setCurrentState(new CheckingForUpdate(*this)); +				break; +			case LLUpdaterService::DOWNLOADING: +				setCurrentState(new WaitingForDownload(*this)); +				break; +			case LLUpdaterService::TERMINAL: +				if(LLUpdaterService::updateReadyToInstall()) { +					setCurrentState(new ReadyToInstall(*this)); +				} else { +					setCurrentState(new Error(*this)); +				} +				break; +			case LLUpdaterService::FAILURE: +				setCurrentState(new Error(*this)); +				break; +			default: +				llassert(!"unpossible case"); +				break; +		} +	} else { +		setCurrentState(new StartingUpdaterService(*this)); +	} +} + + +void MandatoryUpdateMachine::setCurrentState(State * newStatePointer) +{ +	{ +		boost::scoped_ptr<State> newState(newStatePointer); +		if(mState != 0) mState->exit(); +		mState.swap(newState); +		 +		// Old state will be deleted on exit from this block before the new state +		// is entered. +	} +	if(mState != 0) mState->enter(); +} + + + +// MandatoryUpdateMachine::CheckingForUpdate +//----------------------------------------------------------------------------- + + +MandatoryUpdateMachine::CheckingForUpdate::CheckingForUpdate(MandatoryUpdateMachine & machine): +	mMachine(machine) +{ +	; // No op. +} + + +void MandatoryUpdateMachine::CheckingForUpdate::enter(void) +{ +	llinfos << "entering checking for update" << llendl; +	 +	mProgressView = gViewerWindow->getProgressView(); +	mProgressView->setMessage("Looking for update..."); +	mProgressView->setText("There is a required update for your Second Life installation."); +	mProgressView->setPercent(0); +	mProgressView->setVisible(true); +	mConnection = LLEventPumps::instance().obtain(LLUpdaterService::pumpName()). +		listen("MandatoryUpdateMachine::CheckingForUpdate", boost::bind(&MandatoryUpdateMachine::CheckingForUpdate::onEvent, this, _1)); +} + + +void MandatoryUpdateMachine::CheckingForUpdate::exit(void) +{ +} + + +bool MandatoryUpdateMachine::CheckingForUpdate::onEvent(LLSD const & event) +{ +	if(event["type"].asInteger() == LLUpdaterService::STATE_CHANGE) { +		switch(event["state"].asInteger()) { +			case LLUpdaterService::DOWNLOADING: +				mMachine.setCurrentState(new WaitingForDownload(mMachine)); +				break; +			case LLUpdaterService::UP_TO_DATE: +			case LLUpdaterService::TERMINAL: +			case LLUpdaterService::FAILURE: +				mProgressView->setVisible(false); +				mMachine.setCurrentState(new Error(mMachine)); +				break; +			case LLUpdaterService::INSTALLING: +				llassert(!"can't possibly be installing"); +				break; +			default: +				break; +		} +	} else { +		; // Ignore. +	} +	 +	return false; +} + + + +// MandatoryUpdateMachine::Error +//----------------------------------------------------------------------------- + + +MandatoryUpdateMachine::Error::Error(MandatoryUpdateMachine & machine): +	mMachine(machine) +{ +	; // No op. +} + + +void MandatoryUpdateMachine::Error::enter(void) +{ +	llinfos << "entering error" << llendl; +	LLNotificationsUtil::add("FailedUpdateInstall", LLSD(), LLSD(), boost::bind(&MandatoryUpdateMachine::Error::onButtonClicked, this, _1, _2)); +} + + +void MandatoryUpdateMachine::Error::exit(void) +{ +	LLAppViewer::instance()->forceQuit(); +} + + +void MandatoryUpdateMachine::Error::onButtonClicked(const LLSD &, const LLSD &) +{ +	mMachine.setCurrentState(0); +} + + + +// MandatoryUpdateMachine::ReadyToInstall +//----------------------------------------------------------------------------- + + +MandatoryUpdateMachine::ReadyToInstall::ReadyToInstall(MandatoryUpdateMachine & machine): +	mMachine(machine) +{ +	; // No op. +} + + +void MandatoryUpdateMachine::ReadyToInstall::enter(void) +{ +	llinfos << "entering ready to install" << llendl; +	// Open update ready dialog. +} + + +void MandatoryUpdateMachine::ReadyToInstall::exit(void) +{ +	// Restart viewer. +} + + + +// MandatoryUpdateMachine::StartingUpdaterService +//----------------------------------------------------------------------------- + + +MandatoryUpdateMachine::StartingUpdaterService::StartingUpdaterService(MandatoryUpdateMachine & machine): +	mMachine(machine) +{ +	; // No op. +} + + +void MandatoryUpdateMachine::StartingUpdaterService::enter(void) +{ +	llinfos << "entering start update service" << llendl; +	LLNotificationsUtil::add("UpdaterServiceNotRunning", LLSD(), LLSD(), boost::bind(&MandatoryUpdateMachine::StartingUpdaterService::onButtonClicked, this, _1, _2)); +} + + +void MandatoryUpdateMachine::StartingUpdaterService::exit(void) +{ +	; // No op. +} + + +void MandatoryUpdateMachine::StartingUpdaterService::onButtonClicked(const LLSD & uiform, const LLSD & result) +{ +	if(result["OK_okcancelbuttons"].asBoolean()) { +		mMachine.mUpdaterService.startChecking(false); +		mMachine.setCurrentState(new CheckingForUpdate(mMachine)); +	} else { +		LLAppViewer::instance()->forceQuit(); +	} +} + + + +// MandatoryUpdateMachine::WaitingForDownload +//----------------------------------------------------------------------------- + + +MandatoryUpdateMachine::WaitingForDownload::WaitingForDownload(MandatoryUpdateMachine & machine): +	mMachine(machine), +	mProgressView(0) +{ +	; // No op. +} + + +void MandatoryUpdateMachine::WaitingForDownload::enter(void) +{ +	llinfos << "entering waiting for download" << llendl; +	mProgressView = gViewerWindow->getProgressView(); +	mProgressView->setMessage("Downloading update..."); +	std::ostringstream stream; +	stream << "There is a required update for your Second Life installation." << std::endl << +		"Version " << mMachine.mUpdaterService.updatedVersion(); +	mProgressView->setText(stream.str()); +	mProgressView->setPercent(0); +	mProgressView->setVisible(true); +	mConnection = LLEventPumps::instance().obtain(LLUpdaterService::pumpName()). +		listen("MandatoryUpdateMachine::CheckingForUpdate", boost::bind(&MandatoryUpdateMachine::WaitingForDownload::onEvent, this, _1)); +} + + +void MandatoryUpdateMachine::WaitingForDownload::exit(void) +{ +	mProgressView->setVisible(false); +} + + +bool MandatoryUpdateMachine::WaitingForDownload::onEvent(LLSD const & event) +{ +	switch(event["type"].asInteger()) { +		case LLUpdaterService::DOWNLOAD_COMPLETE: +			mMachine.setCurrentState(new ReadyToInstall(mMachine)); +			break; +		case LLUpdaterService::DOWNLOAD_ERROR: +			mMachine.setCurrentState(new Error(mMachine)); +			break; +		case LLUpdaterService::PROGRESS: { +			double downloadSize = event["download_size"].asReal(); +			double bytesDownloaded = event["bytes_downloaded"].asReal(); +			mProgressView->setPercent(100. * bytesDownloaded / downloadSize); +			break; +		} +		default: +			break; +	} + +	return false; +} + + + +// LLLoginInstance +//----------------------------------------------------------------------------- + +  LLLoginInstance::LLLoginInstance() :  	mLoginModule(new LLLogin()),  	mNotifications(NULL), @@ -69,7 +472,8 @@ LLLoginInstance::LLLoginInstance() :  	mSkipOptionalUpdate(false),  	mAttemptComplete(false),  	mTransferRate(0.0f), -	mDispatcher("LLLoginInstance", "change") +	mDispatcher("LLLoginInstance", "change"), +	mUpdaterService(0)  {  	mLoginModule->getEventPump().listen("lllogininstance",   		boost::bind(&LLLoginInstance::handleLoginEvent, this, _1)); @@ -354,6 +758,15 @@ bool LLLoginInstance::handleTOSResponse(bool accepted, const std::string& key)  void LLLoginInstance::updateApp(bool mandatory, const std::string& auth_msg)  { +	if(mandatory) +	{ +		gViewerWindow->setShowProgress(false); +		MandatoryUpdateMachine * machine = new MandatoryUpdateMachine(*this, *mUpdaterService); +		mUpdateStateMachine.reset(machine); +		machine->start(); +		return; +	} +	  	// store off config state, as we might quit soon  	gSavedSettings.saveToFile(gSavedSettings.getString("ClientSettingsFile"), TRUE);	  	LLUIColorTable::instance().saveUserSettings(); diff --git a/indra/newview/lllogininstance.h b/indra/newview/lllogininstance.h index 159e05046c..b872d7d1b1 100644 --- a/indra/newview/lllogininstance.h +++ b/indra/newview/lllogininstance.h @@ -34,12 +34,15 @@  class LLLogin;  class LLEventStream;  class LLNotificationsInterface; +class LLUpdaterService;  // This class hosts the login module and is used to   // negotiate user authentication attempts.  class LLLoginInstance : public LLSingleton<LLLoginInstance>  {  public: +	class Disposable; +  	LLLoginInstance();  	~LLLoginInstance(); @@ -75,6 +78,7 @@ public:  	typedef boost::function<void()> UpdaterLauncherCallback;  	void setUpdaterLauncher(const UpdaterLauncherCallback& ulc) { mUpdaterLauncher = ulc; } +	void setUpdaterService(LLUpdaterService * updaterService) { mUpdaterService = updaterService; }  private:  	void constructAuthParams(LLPointer<LLCredential> user_credentials);  	void updateApp(bool mandatory, const std::string& message); @@ -104,6 +108,8 @@ private:  	int mLastExecEvent;  	UpdaterLauncherCallback mUpdaterLauncher;  	LLEventDispatcher mDispatcher; +	LLUpdaterService * mUpdaterService;	 +	boost::scoped_ptr<Disposable> mUpdateStateMachine;  };  #endif diff --git a/indra/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp index 0f66713ab0..9493fddf50 100644 --- a/indra/newview/llmediactrl.cpp +++ b/indra/newview/llmediactrl.cpp @@ -25,7 +25,7 @@   */  #include "llviewerprecompiledheaders.h" - +#include "lltooltip.h"  #include "llmediactrl.h" @@ -54,6 +54,10 @@  #include "llbutton.h"  #include "llcheckboxctrl.h"  #include "llnotifications.h" +#include "lllineeditor.h" +#include "llfloatermediabrowser.h" +#include "llfloaterwebcontent.h" +#include "llwindowshade.h"  extern BOOL gRestoreGL; @@ -98,7 +102,9 @@ LLMediaCtrl::LLMediaCtrl( const Params& p) :  	mTextureHeight ( 1024 ),  	mClearCache(false),  	mHomePageMimeType(p.initial_mime_type), -	mTrusted(p.trusted_content) +	mTrusted(p.trusted_content), +	mWindowShade(NULL), +	mHoverTextChanged(false)  {  	{  		LLColor4 color = p.caret_color().get(); @@ -127,7 +133,7 @@ LLMediaCtrl::LLMediaCtrl( const Params& p) :  		setTextureSize(screen_width, screen_height);  	} -	mMediaTextureID.generate(); +	mMediaTextureID = getKey();  	// We don't need to create the media source up front anymore unless we have a non-empty home URL to navigate to.  	if(!mHomePageUrl.empty()) @@ -141,8 +147,6 @@ LLMediaCtrl::LLMediaCtrl( const Params& p) :  //	addChild( mBorder );  } -//////////////////////////////////////////////////////////////////////////////// -// note: this is now a singleton and destruction happens via initClass() now  LLMediaCtrl::~LLMediaCtrl()  { @@ -182,6 +186,13 @@ BOOL LLMediaCtrl::handleHover( S32 x, S32 y, MASK mask )  		mMediaSource->mouseMove(x, y, mask);  		gViewerWindow->setCursor(mMediaSource->getLastSetCursor());  	} +	 +	// TODO: Is this the right way to handle hover text changes driven by the plugin? +	if(mHoverTextChanged) +	{ +		mHoverTextChanged = false; +		handleToolTip(x, y, mask); +	}  	return TRUE;  } @@ -198,6 +209,35 @@ BOOL LLMediaCtrl::handleScrollWheel( S32 x, S32 y, S32 clicks )  }  //////////////////////////////////////////////////////////////////////////////// +//	virtual  +BOOL LLMediaCtrl::handleToolTip(S32 x, S32 y, MASK mask) +{ +	std::string hover_text; +	 +	if (mMediaSource && mMediaSource->hasMedia()) +		hover_text = mMediaSource->getMediaPlugin()->getHoverText(); +	 +	if(hover_text.empty()) +	{ +		return FALSE; +	} +	else +	{ +		S32 screen_x, screen_y; + +		localPointToScreen(x, y, &screen_x, &screen_y); +		LLRect sticky_rect_screen; +		sticky_rect_screen.setCenterAndSize(screen_x, screen_y, 20, 20); + +		LLToolTipMgr::instance().show(LLToolTip::Params() +			.message(hover_text) +			.sticky_rect(sticky_rect_screen));		 +	} + +	return TRUE; +} + +////////////////////////////////////////////////////////////////////////////////  //  BOOL LLMediaCtrl::handleMouseUp( S32 x, S32 y, MASK mask )  { @@ -338,85 +378,6 @@ void LLMediaCtrl::onFocusLost()  //  BOOL LLMediaCtrl::postBuild ()  { -	LLLayoutStack::Params layout_p; -	layout_p.name = "notification_stack"; -	layout_p.rect = LLRect(0,getLocalRect().mTop,getLocalRect().mRight, 30); -	layout_p.follows.flags = FOLLOWS_ALL; -	layout_p.mouse_opaque = false; -	layout_p.orientation = "vertical"; - -	LLLayoutStack* stackp = LLUICtrlFactory::create<LLLayoutStack>(layout_p); -	addChild(stackp); - -	LLLayoutPanel::Params panel_p; -	panel_p.rect = LLRect(0, 30, 800, 0); -	panel_p.min_height = 30; -	panel_p.name = "notification_area"; -	panel_p.visible = false; -	panel_p.user_resize = false; -	panel_p.background_visible = true; -	panel_p.bg_alpha_image.name = "Yellow_Gradient"; -	panel_p.auto_resize = false; -	LLLayoutPanel* notification_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p); -	stackp->addChild(notification_panel); - -	panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>(); -	panel_p.auto_resize = true; -	panel_p.mouse_opaque = false; -	LLLayoutPanel* dummy_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p); -	stackp->addChild(dummy_panel); - -	layout_p = LLUICtrlFactory::getDefaultParams<LLLayoutStack>(); -	layout_p.rect = LLRect(0, 30, 800, 0); -	layout_p.follows.flags = FOLLOWS_ALL; -	layout_p.orientation = "horizontal"; -	stackp = LLUICtrlFactory::create<LLLayoutStack>(layout_p); -	notification_panel->addChild(stackp); - -	panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>(); -	panel_p.rect.height = 30; -	LLLayoutPanel* panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p); -	stackp->addChild(panel); - -	LLIconCtrl::Params icon_p; -	icon_p.name = "notification_icon"; -	icon_p.rect = LLRect(5, 23, 21, 8); -	panel->addChild(LLUICtrlFactory::create<LLIconCtrl>(icon_p)); - -	LLTextBox::Params text_p; -	text_p.rect = LLRect(31, 20, 430, 0); -	text_p.text_color = LLColor4::black; -	text_p.font = LLFontGL::getFontSansSerif(); -	text_p.font.style = "BOLD"; -	text_p.name = "notification_text"; -	text_p.use_ellipses = true; -	panel->addChild(LLUICtrlFactory::create<LLTextBox>(text_p)); - -	panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>(); -	panel_p.auto_resize = false; -	panel_p.user_resize = false; -	panel_p.name="form_elements"; -	panel_p.rect = LLRect(0, 30, 130, 0); -	LLLayoutPanel* form_elements_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p); -	stackp->addChild(form_elements_panel); - -	panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>(); -	panel_p.auto_resize = false; -	panel_p.user_resize = false; -	panel_p.rect = LLRect(0, 30, 25, 0); -	LLLayoutPanel* close_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p); -	stackp->addChild(close_panel); - -	LLButton::Params button_p; -	button_p.name = "close_notification"; -	button_p.rect = LLRect(5, 23, 21, 7); -	button_p.image_color=LLUIColorTable::instance().getColor("DkGray_66"); -    button_p.image_unselected.name="Icon_Close_Foreground"; -	button_p.image_selected.name="Icon_Close_Press"; -	button_p.click_callback.function = boost::bind(&LLMediaCtrl::onCloseNotification, this); - -	close_panel->addChild(LLUICtrlFactory::create<LLButton>(button_p)); -  	setVisibleCallback(boost::bind(&LLMediaCtrl::onVisibilityChange, this, _2));  	return TRUE;  } @@ -425,13 +386,15 @@ BOOL LLMediaCtrl::postBuild ()  //  BOOL LLMediaCtrl::handleKeyHere( KEY key, MASK mask )  { -	if (LLPanel::handleKeyHere(key, mask)) return TRUE;  	BOOL result = FALSE;  	if (mMediaSource)  	{  		result = mMediaSource->handleKeyHere(key, mask);  	} +	 +	if ( ! result ) +		result = LLPanel::handleKeyHere(key, mask);  	return result;  } @@ -451,7 +414,6 @@ void LLMediaCtrl::handleVisibilityChange ( BOOL new_visibility )  //  BOOL LLMediaCtrl::handleUnicodeCharHere(llwchar uni_char)  { -	if (LLPanel::handleUnicodeCharHere(uni_char)) return TRUE;  	BOOL result = FALSE;  	if (mMediaSource) @@ -459,6 +421,9 @@ BOOL LLMediaCtrl::handleUnicodeCharHere(llwchar uni_char)  		result = mMediaSource->handleUnicodeCharHere(uni_char);  	} +	if ( ! result ) +		result = LLPanel::handleUnicodeCharHere(uni_char); +  	return result;  } @@ -914,11 +879,6 @@ void LLMediaCtrl::draw()  	if ( mBorder && mBorder->getVisible() )  		mBorder->setKeyboardFocusHighlight( gFocusMgr.childHasKeyboardFocus( this ) ); -	if (mCurNotification && !mCurNotification->isActive()) -	{ -		hideNotification(); -	} -	  	LLPanel::draw();  	// Restore the previous values @@ -1026,7 +986,7 @@ void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event)  			LLNotification::Params notify_params;  			notify_params.name = "PopupAttempt"; -			notify_params.payload = LLSD().with("target", target).with("url", url).with("uuid", uuid).with("media_id", getKey()); +			notify_params.payload = LLSD().with("target", target).with("url", url).with("uuid", uuid).with("media_id", mMediaTextureID);  			notify_params.functor.function = boost::bind(&LLMediaCtrl::onPopup, this, _1, _2);  			if (mTrusted) @@ -1081,6 +1041,31 @@ void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event)  			LL_DEBUGS("Media") << "Media event:  MEDIA_EVENT_GEOMETRY_CHANGE, uuid is " << self->getClickUUID() << LL_ENDL;  		}  		break; + +		case MEDIA_EVENT_AUTH_REQUEST: +		{ +			LLNotification::Params auth_request_params; +			auth_request_params.name = "AuthRequest"; + +			// pass in host name and realm for site (may be zero length but will always exist) +			LLSD args; +			LLURL raw_url( self->getAuthURL().c_str() ); +			args["HOST_NAME"] = raw_url.getAuthority(); +			args["REALM"] = self->getAuthRealm(); +			auth_request_params.substitutions = args; + +			auth_request_params.payload = LLSD().with("media_id", mMediaTextureID); +			auth_request_params.functor.function = boost::bind(&LLViewerMedia::onAuthSubmit, _1, _2); +			LLNotifications::instance().add(auth_request_params); +		}; +		break; + +		case MEDIA_EVENT_LINK_HOVERED: +		{ +			LL_DEBUGS("Media") <<  "Media event:  MEDIA_EVENT_LINK_HOVERED, hover text is: " << self->getHoverText() << LL_ENDL; +			mHoverTextChanged = true; +		}; +		break;  	};  	// chain all events to any potential observers of this object. @@ -1098,109 +1083,85 @@ void LLMediaCtrl::onPopup(const LLSD& notification, const LLSD& response)  {  	if (response["open"])  	{ -		LLWeb::loadURL(notification["payload"]["url"], notification["payload"]["target"], notification["payload"]["uuid"]); +		// name of default floater to open +		std::string floater_name = "media_browser"; + +		// look for parent floater name +		if ( gFloaterView ) +		{ +			if ( gFloaterView->getParentFloater(this) ) +			{ +				floater_name = gFloaterView->getParentFloater(this)->getInstanceName(); +			} +			else +			{ +				lldebugs << "No gFloaterView->getParentFloater(this) for onPopuup()" << llendl; +			}; +		} +		else +		{ +			lldebugs << "No gFloaterView for onPopuup()" << llendl; +		}; + +		// (for now) open web content floater if that's our parent, otherwise, open the current media floater +		// (this will change soon) +		if ( floater_name == "web_content" ) +		{ +			LLWeb::loadWebURL(notification["payload"]["url"], notification["payload"]["target"], notification["payload"]["uuid"]); +		} +		else +		{ +			LLWeb::loadURL(notification["payload"]["url"], notification["payload"]["target"], notification["payload"]["uuid"]); +		}  	}  	else  	{  		// Make sure the opening instance knows its window open request was denied, so it can clean things up.  		LLViewerMedia::proxyWindowClosed(notification["payload"]["uuid"]);  	} -  } -void LLMediaCtrl::onCloseNotification() -{ -	LLNotifications::instance().cancel(mCurNotification); -} - -void LLMediaCtrl::onClickIgnore(LLUICtrl* ctrl) +void LLMediaCtrl::showNotification(LLNotificationPtr notify)  { -	bool check = ctrl->getValue().asBoolean(); -	if (mCurNotification && mCurNotification->getForm()->getIgnoreType() == LLNotificationForm::IGNORE_SHOW_AGAIN) +	delete mWindowShade; + +	LLWindowShade::Params params; +	params.name = "notification_shade"; +	params.rect = getLocalRect(); +	params.follows.flags = FOLLOWS_ALL; +	params.notification = notify; +	params.modal = true; +	//HACK: don't hardcode this +	if (notify->getIcon() == "Popup_Caution")  	{ -		// question was "show again" so invert value to get "ignore" -		check = !check; +		params.bg_image.name = "Yellow_Gradient"; +		params.text_color = LLColor4::black;  	} -	mCurNotification->setIgnored(check); -} - -void LLMediaCtrl::onClickNotificationButton(const std::string& name) -{ -	if (!mCurNotification) return; - -	LLSD response = mCurNotification->getResponseTemplate(); -	response[name] = true; - -	mCurNotification->respond(response);  -} - -void LLMediaCtrl::showNotification(LLNotificationPtr notify) -{ -	mCurNotification = notify; - -	// add popup here -	LLSD payload = notify->getPayload(); - -	LLNotificationFormPtr formp = notify->getForm(); -	LLLayoutPanel& panel = getChildRef<LLLayoutPanel>("notification_area"); -	panel.setVisible(true); -	panel.getChild<LLUICtrl>("notification_icon")->setValue(notify->getIcon()); -	panel.getChild<LLUICtrl>("notification_text")->setValue(notify->getMessage()); -	panel.getChild<LLUICtrl>("notification_text")->setToolTip(notify->getMessage()); -	LLNotificationForm::EIgnoreType ignore_type = formp->getIgnoreType();  -	LLLayoutPanel& form_elements = panel.getChildRef<LLLayoutPanel>("form_elements"); -	form_elements.deleteAllChildren(); - -	const S32 FORM_PADDING_HORIZONTAL = 10; -	const S32 FORM_PADDING_VERTICAL = 3; -	S32 cur_x = FORM_PADDING_HORIZONTAL; - -	if (ignore_type != LLNotificationForm::IGNORE_NO) +	else +	//HACK: another one since XUI doesn't support what we need right now +	if (notify->getName() == "AuthRequest")  	{ -		LLCheckBoxCtrl::Params checkbox_p; -		checkbox_p.name = "ignore_check"; -		checkbox_p.rect = LLRect(cur_x, form_elements.getRect().getHeight() - FORM_PADDING_VERTICAL, cur_x, FORM_PADDING_VERTICAL); -		checkbox_p.label = formp->getIgnoreMessage(); -		checkbox_p.label_text.text_color = LLColor4::black; -		checkbox_p.commit_callback.function = boost::bind(&LLMediaCtrl::onClickIgnore, this, _1); -		checkbox_p.initial_value = formp->getIgnored(); - -		LLCheckBoxCtrl* check = LLUICtrlFactory::create<LLCheckBoxCtrl>(checkbox_p); -		check->setRect(check->getBoundingRect()); -		form_elements.addChild(check); -		cur_x = check->getRect().mRight + FORM_PADDING_HORIZONTAL; +		params.bg_image.name = "Yellow_Gradient"; +		params.text_color = LLColor4::black; +		params.can_close = false;  	} - -	for (S32 i = 0; i < formp->getNumElements(); i++) +	else  	{ -		LLSD form_element = formp->getElement(i); -		if (form_element["type"].asString() == "button") -		{ -			LLButton::Params button_p; -			button_p.name = form_element["name"]; -			button_p.label = form_element["text"]; -			button_p.rect = LLRect(cur_x, form_elements.getRect().getHeight() - FORM_PADDING_VERTICAL, cur_x, FORM_PADDING_VERTICAL); -			button_p.click_callback.function = boost::bind(&LLMediaCtrl::onClickNotificationButton, this, form_element["name"].asString()); -			button_p.auto_resize = true; - -			LLButton* button = LLUICtrlFactory::create<LLButton>(button_p); -			button->autoResize(); -			form_elements.addChild(button); - -			cur_x = button->getRect().mRight + FORM_PADDING_HORIZONTAL; -		} +		//HACK: make this a property of the notification itself, "cancellable" +		params.can_close = false; +		params.text_color.control = "LabelTextColor";  	} +	mWindowShade = LLUICtrlFactory::create<LLWindowShade>(params); -	form_elements.reshape(cur_x, form_elements.getRect().getHeight()); - -	//LLWeb::loadURL(payload["url"], payload["target"]); +	addChild(mWindowShade); +	mWindowShade->show();  }  void LLMediaCtrl::hideNotification()  { -	LLLayoutPanel& panel = getChildRef<LLLayoutPanel>("notification_area"); -	panel.setVisible(FALSE); - -	mCurNotification.reset(); +	if (mWindowShade) +	{ +		mWindowShade->hide(); +	}  } diff --git a/indra/newview/llmediactrl.h b/indra/newview/llmediactrl.h index 96bb0c1df5..38a74f90d3 100644 --- a/indra/newview/llmediactrl.h +++ b/indra/newview/llmediactrl.h @@ -90,6 +90,7 @@ public:  		virtual BOOL handleRightMouseUp(S32 x, S32 y, MASK mask);  		virtual BOOL handleDoubleClick( S32 x, S32 y, MASK mask );  		virtual BOOL handleScrollWheel( S32 x, S32 y, S32 clicks ); +		virtual BOOL handleToolTip(S32 x, S32 y, MASK mask);  		// navigation  		void navigateTo( std::string url_in, std::string mime_type = ""); @@ -168,9 +169,6 @@ public:  	private:  		void onVisibilityChange ( const LLSD& new_visibility );  		void onPopup(const LLSD& notification, const LLSD& response); -		void onCloseNotification(); -		void onClickNotificationButton(const std::string& name); -		void onClickIgnore(LLUICtrl* ctrl);  		const S32 mTextureDepthBytes;  		LLUUID mMediaTextureID; @@ -194,7 +192,8 @@ public:  		S32 mTextureWidth;  		S32 mTextureHeight;  		bool mClearCache; -		boost::shared_ptr<class LLNotification> mCurNotification; +		class LLWindowShade* mWindowShade; +		bool mHoverTextChanged;  };  #endif // LL_LLMediaCtrl_H diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp index f084002385..1a8ec4991d 100644 --- a/indra/newview/llnetmap.cpp +++ b/indra/newview/llnetmap.cpp @@ -94,10 +94,12 @@ LLNetMap::LLNetMap (const Params & p)  	mToolTipMsg()  {  	mDotRadius = llmax(DOT_SCALE * mPixelsPerMeter, MIN_DOT_RADIUS); +	setScale(gSavedSettings.getF32("MiniMapScale"));  }  LLNetMap::~LLNetMap()  { +	gSavedSettings.setF32("MiniMapScale", mScale);  }  void LLNetMap::setScale( F32 scale ) diff --git a/indra/newview/llpanelavatar.cpp b/indra/newview/llpanelavatar.cpp index 1249d5d856..a9bcdef47c 100644 --- a/indra/newview/llpanelavatar.cpp +++ b/indra/newview/llpanelavatar.cpp @@ -341,10 +341,11 @@ LLPanelAvatarNotes::~LLPanelAvatarNotes()  	if(getAvatarId().notNull())  	{  		LLAvatarTracker::instance().removeParticularFriendObserver(getAvatarId(), this); -		if(LLVoiceClient::instanceExists()) -		{ -			LLVoiceClient::getInstance()->removeObserver((LLVoiceClientStatusObserver*)this); -		} +	} + +	if(LLVoiceClient::instanceExists()) +	{ +		LLVoiceClient::getInstance()->removeObserver((LLVoiceClientStatusObserver*)this);  	}  } @@ -758,10 +759,11 @@ LLPanelAvatarProfile::~LLPanelAvatarProfile()  	if(getAvatarId().notNull())  	{  		LLAvatarTracker::instance().removeParticularFriendObserver(getAvatarId(), this); -		if(LLVoiceClient::instanceExists()) -		{ -			LLVoiceClient::getInstance()->removeObserver((LLVoiceClientStatusObserver*)this); -		} +	} + +	if(LLVoiceClient::instanceExists()) +	{ +		LLVoiceClient::getInstance()->removeObserver((LLVoiceClientStatusObserver*)this);  	}  } diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index 2e4be78be1..5f89097c17 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -73,7 +73,6 @@  #endif  // LL_WINDOWS  #include "llsdserialize.h" -#define USE_VIEWER_AUTH 0  const S32 BLACK_BORDER_HEIGHT = 160;  const S32 MAX_PASSWORD = 16; @@ -190,10 +189,6 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,  	buildFromFile( "panel_login.xml"); -#if USE_VIEWER_AUTH -	//leave room for the login menu bar -	setRect(LLRect(0, rect.getHeight()-18, rect.getWidth(), 0));  -#endif  	// Legacy login web page is hidden under the menu bar.  	// Adjust reg-in-client web browser widget to not be hidden.  	if (gSavedSettings.getBOOL("RegInClient")) @@ -205,16 +200,12 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,  		reshape(rect.getWidth(), rect.getHeight());  	} -#if !USE_VIEWER_AUTH  	getChild<LLLineEditor>("password_edit")->setKeystrokeCallback(onPassKey, this);  	// change z sort of clickable text to be behind buttons  	//sendChildToBack(getChildView("channel_text"));  	sendChildToBack(getChildView("forgot_password_text")); -	LLLineEditor* edit = getChild<LLLineEditor>("password_edit"); -	if (edit) edit->setDrawAsterixes(TRUE); -  	if(LLStartUp::getStartSLURL().getType() != LLSLURL::LOCATION)  	{  		LLSLURL slurl(gSavedSettings.getString("LoginLocation")); @@ -248,7 +239,6 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,  	LLTextBox* need_help_text = getChild<LLTextBox>("login_help");  	need_help_text->setClickedCallback(onClickHelp, NULL); -#endif      	// get the web browser control  	LLMediaCtrl* web_browser = getChild<LLMediaCtrl>("login_html"); @@ -275,15 +265,9 @@ void LLPanelLogin::reshapeBrowser()  	LLMediaCtrl* web_browser = getChild<LLMediaCtrl>("login_html");  	LLRect rect = gViewerWindow->getWindowRectScaled();  	LLRect html_rect; -#if USE_VIEWER_AUTH -	html_rect.setCenterAndSize(  -		rect.getCenterX() - 2, rect.getCenterY(),  -		rect.getWidth() + 6, rect.getHeight()); -#else  	html_rect.setCenterAndSize(  		rect.getCenterX() - 2, rect.getCenterY() + 40,  		rect.getWidth() + 6, rect.getHeight() - 78 ); -#endif  	web_browser->setRect( html_rect );  	web_browser->reshape( html_rect.getWidth(), html_rect.getHeight(), TRUE );  	reshape( rect.getWidth(), rect.getHeight(), 1 ); @@ -306,7 +290,6 @@ void LLPanelLogin::setSiteIsAlive( bool alive )  	else  	// the site is not available (missing page, server down, other badness)  	{ -#if !USE_VIEWER_AUTH  		if ( web_browser )  		{  			// hide browser control (revealing default one) @@ -315,16 +298,6 @@ void LLPanelLogin::setSiteIsAlive( bool alive )  			// mark as unavailable  			mHtmlAvailable = FALSE;  		} -#else - -		if ( web_browser ) -		{	 -			web_browser->navigateToLocalPage( "loading-error" , "index.html" ); - -			// mark as available -			mHtmlAvailable = TRUE; -		} -#endif  	}  } @@ -364,7 +337,6 @@ void LLPanelLogin::draw()  		if ( mHtmlAvailable )  		{ -#if !USE_VIEWER_AUTH  			if (getChild<LLView>("login_widgets")->getVisible())  			{  				// draw a background box in black @@ -373,7 +345,6 @@ void LLPanelLogin::draw()  				// just the blue background to the native client UI  				mLogoImage->draw(0, -264, width + 8, mLogoImage->getHeight());  			} -#endif  		}  		else  		{ @@ -419,12 +390,6 @@ void LLPanelLogin::setFocus(BOOL b)  // static  void LLPanelLogin::giveFocus()  { -#if USE_VIEWER_AUTH -	if (sInstance) -	{ -		sInstance->setFocus(TRUE); -	} -#else  	if( sInstance )  	{  		// Grab focus and move cursor to first blank input field @@ -453,17 +418,18 @@ void LLPanelLogin::giveFocus()  			edit->selectAll();  		}  	} -#endif  }  // static  void LLPanelLogin::showLoginWidgets()  { +	// *NOTE: Mani - This may or may not be obselete code. +	// It seems to be part of the defunct? reg-in-client project.  	sInstance->getChildView("login_widgets")->setVisible( true);  	LLMediaCtrl* web_browser = sInstance->getChild<LLMediaCtrl>("login_html");  	sInstance->reshapeBrowser();  	// *TODO: Append all the usual login parameters, like first_login=Y etc. -	std::string splash_screen_url = sInstance->getString("real_url"); +	std::string splash_screen_url = LLGridManager::getInstance()->getLoginPage();  	web_browser->navigateTo( splash_screen_url, "text/html" );  	LLUICtrl* username_edit = sInstance->getChild<LLUICtrl>("username_edit");  	username_edit->setFocus(TRUE); @@ -833,73 +799,6 @@ void LLPanelLogin::loadLoginPage()  	curl_free(curl_grid);  	gViewerWindow->setMenuBackgroundColor(false, !LLGridManager::getInstance()->isInProductionGrid());  	gLoginMenuBarView->setBackgroundColor(gMenuBarView->getBackgroundColor()); - - -#if USE_VIEWER_AUTH -	LLURLSimString::sInstance.parse(); - -	std::string location; -	std::string region; -	std::string password; -	 -	if (LLURLSimString::parse()) -	{ -		std::ostringstream oRegionStr; -		location = "specify"; -		oRegionStr << LLURLSimString::sInstance.mSimName << "/" << LLURLSimString::sInstance.mX << "/" -			 << LLURLSimString::sInstance.mY << "/" -			 << LLURLSimString::sInstance.mZ; -		region = oRegionStr.str(); -	} -	else -	{ -		location = gSavedSettings.getString("LoginLocation"); -	} -	 -	std::string username; - -    if(gSavedSettings.getLLSD("UserLoginInfo").size() == 3) -    { -        LLSD cmd_line_login = gSavedSettings.getLLSD("UserLoginInfo"); -		username = cmd_line_login[0].asString() + " " + cmd_line_login[1]; -        password = cmd_line_login[2].asString(); -    } -    	 -	 -	char* curl_region = curl_escape(region.c_str(), 0); - -	oStr <<"username=" << username << -		 "&location=" << location <<	"®ion=" << curl_region; -	 -	curl_free(curl_region); - -	if (!password.empty()) -	{ -		oStr << "&password=" << password; -	} -	else if (!(password = load_password_from_disk()).empty()) -	{ -		oStr << "&password=$1$" << password; -	} -	if (gAutoLogin) -	{ -		oStr << "&auto_login=TRUE"; -	} -	if (gSavedSettings.getBOOL("ShowStartLocation")) -	{ -		oStr << "&show_start_location=TRUE"; -	}	 -	if (gSavedSettings.getBOOL("RememberPassword")) -	{ -		oStr << "&remember_password=TRUE"; -	}	 -#ifndef	LL_RELEASE_FOR_DOWNLOAD -	oStr << "&show_grid=TRUE"; -#else -	if (gSavedSettings.getBOOL("ForceShowGrid")) -		oStr << "&show_grid=TRUE"; -#endif -#endif  	LLMediaCtrl* web_browser = sInstance->getChild<LLMediaCtrl>("login_html"); diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp index 17433a557b..c83176d980 100644 --- a/indra/newview/llpanelmaininventory.cpp +++ b/indra/newview/llpanelmaininventory.cpp @@ -506,9 +506,6 @@ void LLPanelMainInventory::onFilterSelected()  		return;  	} -	BOOL recent_active = ("Recent Items" == mActivePanel->getName()); -	getChildView("add_btn_panel")->setVisible( !recent_active); -  	setFilterSubString(mFilterSubString);  	LLInventoryFilter* filter = mActivePanel->getFilter();  	LLFloaterInventoryFinder *finder = getFinder(); @@ -944,6 +941,11 @@ void LLPanelMainInventory::updateListCommands()  void LLPanelMainInventory::onAddButtonClick()  { +// Gray out the "New Folder" option when the Recent tab is active as new folders will not be displayed +// unless "Always show folders" is checked in the filter options. +	bool recent_active = ("Recent Items" == mActivePanel->getName()); +	mMenuAdd->getChild<LLMenuItemGL>("New Folder")->setEnabled(!recent_active); +  	setUploadCostIfNeeded();  	showActionMenu(mMenuAdd,"add_btn"); diff --git a/indra/newview/llpanelplaces.cpp b/indra/newview/llpanelplaces.cpp index 1869e92c8c..00ac34efa5 100644 --- a/indra/newview/llpanelplaces.cpp +++ b/indra/newview/llpanelplaces.cpp @@ -753,6 +753,11 @@ void LLPanelPlaces::onOverflowButtonClicked()  		// there is no landmark already pointing to that parcel in agent's inventory.  		menu->getChild<LLMenuItemCallGL>("landmark")->setEnabled(is_agent_place_info_visible &&  																 !LLLandmarkActions::landmarkAlreadyExists()); +		// STORM-411 +		// Creating landmarks for remote locations is impossible. +		// So hide menu item "Make a Landmark" in "Teleport History Profile" panel. +		menu->setItemVisible("landmark", mPlaceInfoType != TELEPORT_HISTORY_INFO_TYPE); +		menu->arrangeAndClear();  	}  	else if (mPlaceInfoType == LANDMARK_INFO_TYPE && mLandmarkMenu != NULL)  	{ diff --git a/indra/newview/llpanelprimmediacontrols.cpp b/indra/newview/llpanelprimmediacontrols.cpp index 614700fb0a..8ae3553857 100644 --- a/indra/newview/llpanelprimmediacontrols.cpp +++ b/indra/newview/llpanelprimmediacontrols.cpp @@ -59,6 +59,7 @@  #include "llvovolume.h"  #include "llweb.h"  #include "llwindow.h" +#include "llwindowshade.h"  #include "llfloatertools.h"  // to enable hide if build tools are up  // Functions pulled from pipeline.cpp @@ -90,7 +91,8 @@ LLPanelPrimMediaControls::LLPanelPrimMediaControls() :  	mTargetObjectNormal(LLVector3::zero),  	mZoomObjectID(LLUUID::null),  	mZoomObjectFace(0), -	mVolumeSliderVisible(0) +	mVolumeSliderVisible(0), +	mWindowShade(NULL)  {  	mCommitCallbackRegistrar.add("MediaCtrl.Close",		boost::bind(&LLPanelPrimMediaControls::onClickClose, this));  	mCommitCallbackRegistrar.add("MediaCtrl.Back",		boost::bind(&LLPanelPrimMediaControls::onClickBack, this)); @@ -205,6 +207,9 @@ BOOL LLPanelPrimMediaControls::postBuild()  	mMediaAddress->setFocusReceivedCallback(boost::bind(&LLPanelPrimMediaControls::onInputURL, _1, this )); +	LLWindowShade::Params window_shade_params; +	window_shade_params.name = "window_shade"; +  	mCurrentZoom = ZOOM_NONE;  	// clicks on buttons do not remove keyboard focus from media  	setIsChrome(TRUE); @@ -698,6 +703,24 @@ void LLPanelPrimMediaControls::updateShape()  /*virtual*/  void LLPanelPrimMediaControls::draw()  { +	LLViewerMediaImpl* impl = getTargetMediaImpl(); +	if (impl) +	{ +		LLNotificationPtr notification = impl->getCurrentNotification(); +		if (notification != mActiveNotification) +		{ +			mActiveNotification = notification; +			if (notification) +			{ +				showNotification(notification); +			} +			else +			{ +				hideNotification(); +			} +		} +	} +  	F32 alpha = getDrawContext().mAlpha;  	if(mFadeTimer.getStarted())  	{ @@ -1295,3 +1318,38 @@ bool LLPanelPrimMediaControls::shouldVolumeSliderBeVisible()  {  	return mVolumeSliderVisible > 0;  } + +void LLPanelPrimMediaControls::showNotification(LLNotificationPtr notify) +{ +	delete mWindowShade; +	LLWindowShade::Params params; +	params.rect = mMediaRegion->getLocalRect(); +	params.follows.flags = FOLLOWS_ALL; +	params.notification = notify; + +	//HACK: don't hardcode this +	if (notify->getIcon() == "Popup_Caution") +	{ +		params.bg_image.name = "Yellow_Gradient"; +		params.text_color = LLColor4::black; +	} +	else +	{ +		//HACK: make this a property of the notification itself, "cancellable" +		params.can_close = false; +		params.text_color.control = "LabelTextColor"; +	} + +	mWindowShade = LLUICtrlFactory::create<LLWindowShade>(params); + +	mMediaRegion->addChild(mWindowShade); +	mWindowShade->show(); +} + +void LLPanelPrimMediaControls::hideNotification() +{ +	if (mWindowShade) +	{ +		mWindowShade->hide(); +	} +} diff --git a/indra/newview/llpanelprimmediacontrols.h b/indra/newview/llpanelprimmediacontrols.h index 3ec24f0e24..0b9664359c 100644 --- a/indra/newview/llpanelprimmediacontrols.h +++ b/indra/newview/llpanelprimmediacontrols.h @@ -29,6 +29,7 @@  #include "llpanel.h"  #include "llviewermedia.h" +#include "llnotificationptr.h"  class LLButton;  class LLCoordWindow; @@ -37,6 +38,7 @@ class LLLayoutStack;  class LLProgressBar;  class LLSliderCtrl;  class LLViewerMediaImpl; +class LLWindowShade;  class LLPanelPrimMediaControls : public LLPanel  { @@ -54,6 +56,9 @@ public:  	void updateShape();  	bool isMouseOver(); +	void showNotification(LLNotificationPtr notify); +	void hideNotification(); +  	enum EZoomLevel  	{  		ZOOM_NONE = 0, @@ -162,6 +167,7 @@ private:  	LLUICtrl *mRightBookend;  	LLUIImage* mBackgroundImage;  	LLUIImage* mVolumeSliderBackgroundImage; +	LLWindowShade* mWindowShade;  	F32 mSkipStep;  	S32 mMinWidth;  	S32 mMinHeight; @@ -204,6 +210,8 @@ private:  	S32 mZoomObjectFace;  	S32 mVolumeSliderVisible; + +	LLNotificationPtr mActiveNotification;  };  #endif // LL_PANELPRIMMEDIACONTROLS_H diff --git a/indra/newview/llpanelprofile.cpp b/indra/newview/llpanelprofile.cpp index 6038ab20d8..b035d7d473 100644 --- a/indra/newview/llpanelprofile.cpp +++ b/indra/newview/llpanelprofile.cpp @@ -114,11 +114,109 @@ public:  LLAgentHandler gAgentHandler; +//-- LLPanelProfile::ChildStack begins ---------------------------------------- +LLPanelProfile::ChildStack::ChildStack() +:	mParent(NULL) +{ +} + +void LLPanelProfile::ChildStack::setParent(LLPanel* parent) +{ +	llassert_always(parent != NULL); +	mParent = parent; +} + +/// Save current parent's child views and remove them from the child list. +bool LLPanelProfile::ChildStack::push() +{ +	view_list_t vlist = *mParent->getChildList(); + +	for (view_list_t::const_iterator it = vlist.begin(); it != vlist.end(); ++it) +	{ +		LLView* viewp = *it; +		mParent->removeChild(viewp); +	} + +	mStack.push_back(vlist); +	dump(); +	return true; +} + +/// Restore saved children (adding them back to the child list). +bool LLPanelProfile::ChildStack::pop() +{ +	if (mStack.size() == 0) +	{ +		llwarns << "Empty stack" << llendl; +		llassert(mStack.size() == 0); +		return false; +	} + +	view_list_t& top = mStack.back(); +	for (view_list_t::const_iterator it = top.begin(); it != top.end(); ++it) +	{ +		LLView* viewp = *it; +		mParent->addChild(viewp); +	} + +	mStack.pop_back(); +	dump(); +	return true; +} + +/// Temporarily add all saved children back. +void LLPanelProfile::ChildStack::preParentReshape() +{ +	mSavedStack = mStack; +	while(mStack.size() > 0) +	{ +		pop(); +	} +} + +/// Add the temporarily saved children back. +void LLPanelProfile::ChildStack::postParentReshape() +{ +	mStack = mSavedStack; +	mSavedStack = stack_t(); + +	for (stack_t::const_iterator stack_it = mStack.begin(); stack_it != mStack.end(); ++stack_it) +	{ +		const view_list_t& vlist = (*stack_it); +		for (view_list_t::const_iterator list_it = vlist.begin(); list_it != vlist.end(); ++list_it) +		{ +			LLView* viewp = *list_it; +			lldebugs << "removing " << viewp->getName() << llendl; +			mParent->removeChild(viewp); +		} +	} +} + +void LLPanelProfile::ChildStack::dump() +{ +	unsigned lvl = 0; +	lldebugs << "child stack dump:" << llendl; +	for (stack_t::const_iterator stack_it = mStack.begin(); stack_it != mStack.end(); ++stack_it, ++lvl) +	{ +		std::ostringstream dbg_line; +		dbg_line << "lvl #" << lvl << ":"; +		const view_list_t& vlist = (*stack_it); +		for (view_list_t::const_iterator list_it = vlist.begin(); list_it != vlist.end(); ++list_it) +		{ +			dbg_line << " " << (*list_it)->getName(); +		} +		lldebugs << dbg_line.str() << llendl; +	} +} + +//-- LLPanelProfile::ChildStack ends ------------------------------------------ +  LLPanelProfile::LLPanelProfile()   : LLPanel()   , mTabCtrl(NULL)   , mAvatarId(LLUUID::null)  { +	mChildStack.setParent(this);  }  BOOL LLPanelProfile::postBuild() @@ -136,6 +234,15 @@ BOOL LLPanelProfile::postBuild()  	return TRUE;  } +// virtual +void LLPanelProfile::reshape(S32 width, S32 height, BOOL called_from_parent) +{ +	// Temporarily add saved children back and reshape them. +	mChildStack.preParentReshape(); +	LLPanel::reshape(width, height, called_from_parent); +	mChildStack.postParentReshape(); +} +  void LLPanelProfile::onOpen(const LLSD& key)  {  	// open the desired panel @@ -177,7 +284,6 @@ void LLPanelProfile::onOpen(const LLSD& key)  	}  } -//*TODO redo panel toggling  void LLPanelProfile::togglePanel(LLPanel* panel, const LLSD& key)  {  	// TRUE - we need to open/expand "panel" @@ -204,21 +310,10 @@ void LLPanelProfile::onTabSelected(const LLSD& param)  	}  } -void LLPanelProfile::setAllChildrenVisible(BOOL visible) -{ -	const child_list_t* child_list = getChildList(); -	child_list_const_iter_t child_it = child_list->begin(); -	for (; child_it != child_list->end(); ++child_it) -	{ -		LLView* viewp = *child_it; -		viewp->setVisible(visible); -	} -} -  void LLPanelProfile::openPanel(LLPanel* panel, const LLSD& params)  {  	// Hide currently visible panel (STORM-690). -	setAllChildrenVisible(FALSE); +	mChildStack.push();  	// Add the panel or bring it to front.  	if (panel->getParent() != this) @@ -231,7 +326,7 @@ void LLPanelProfile::openPanel(LLPanel* panel, const LLSD& params)  	}  	panel->setVisible(TRUE); - +	panel->setFocus(TRUE); // prevent losing focus by the floater  	panel->onOpen(params);  	LLRect new_rect = getRect(); @@ -249,15 +344,17 @@ void LLPanelProfile::closePanel(LLPanel* panel)  		removeChild(panel);  		// Make the underlying panel visible. +		mChildStack.pop(); + +		// Prevent losing focus by the floater  		const child_list_t* child_list = getChildList();  		if (child_list->size() > 0)  		{ -			child_list->front()->setVisible(TRUE); -			child_list->front()->setFocus(TRUE); // prevent losing focus by the floater +			child_list->front()->setFocus(TRUE);  		}  		else  		{ -			llwarns << "No underlying panel to make visible." << llendl; +			llwarns << "No underlying panel to focus." << llendl;  		}  	}  } diff --git a/indra/newview/llpanelprofile.h b/indra/newview/llpanelprofile.h index d2bcee8076..0a572e6f25 100644 --- a/indra/newview/llpanelprofile.h +++ b/indra/newview/llpanelprofile.h @@ -41,7 +41,7 @@ class LLPanelProfile : public LLPanel  public:  	/*virtual*/ BOOL postBuild(); - +	/*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);  	/*virtual*/ void onOpen(const LLSD& key);  	virtual void togglePanel(LLPanel*, const LLSD& key = LLSD()); @@ -58,8 +58,6 @@ protected:  	virtual void onTabSelected(const LLSD& param); -	virtual void setAllChildrenVisible(BOOL visible); -  	LLTabContainer* getTabCtrl() { return mTabCtrl; }  	const LLUUID& getAvatarId() { return mAvatarId; } @@ -72,8 +70,34 @@ protected:  private: +	//-- ChildStack begins ---------------------------------------------------- +	class ChildStack +	{ +		LOG_CLASS(LLPanelProfile::ChildStack); +	public: +		ChildStack(); +		void setParent(LLPanel* parent); + +		bool push(); +		bool pop(); +		void preParentReshape(); +		void postParentReshape(); + +	private: +		void dump(); + +		typedef LLView::child_list_t view_list_t; +		typedef std::list<view_list_t> stack_t; + +		stack_t		mStack; +		stack_t		mSavedStack; +		LLPanel*	mParent; +	}; +	//-- ChildStack ends ------------------------------------------------------ +  	LLTabContainer* mTabCtrl;	  	profile_tabs_t mTabContainer; +	ChildStack		mChildStack;  	LLUUID mAvatarId;  }; diff --git a/indra/newview/llpaneltopinfobar.cpp b/indra/newview/llpaneltopinfobar.cpp index a9ca7314ce..30949f8f02 100644 --- a/indra/newview/llpaneltopinfobar.cpp +++ b/indra/newview/llpaneltopinfobar.cpp @@ -38,6 +38,7 @@  #include "llsidetray.h"  #include "llslurl.h"  #include "llstatusbar.h" +#include "lltrans.h"  #include "llviewercontrol.h"  #include "llviewerinventory.h"  #include "llviewermenu.h" @@ -102,6 +103,13 @@ void LLPanelTopInfoBar::initParcelIcons()  	mParcelIcon[SCRIPTS_ICON] = getChild<LLIconCtrl>("scripts_icon");  	mParcelIcon[DAMAGE_ICON] = getChild<LLIconCtrl>("damage_icon"); +	mParcelIcon[VOICE_ICON]->setToolTip(LLTrans::getString("LocationCtrlVoiceTooltip")); +	mParcelIcon[FLY_ICON]->setToolTip(LLTrans::getString("LocationCtrlFlyTooltip")); +	mParcelIcon[PUSH_ICON]->setToolTip(LLTrans::getString("LocationCtrlPushTooltip")); +	mParcelIcon[BUILD_ICON]->setToolTip(LLTrans::getString("LocationCtrlBuildTooltip")); +	mParcelIcon[SCRIPTS_ICON]->setToolTip(LLTrans::getString("LocationCtrlScriptsTooltip")); +	mParcelIcon[DAMAGE_ICON]->setToolTip(LLTrans::getString("LocationCtrlDamageTooltip")); +  	mParcelIcon[VOICE_ICON]->setMouseDownCallback(boost::bind(&LLPanelTopInfoBar::onParcelIconClick, this, VOICE_ICON));  	mParcelIcon[FLY_ICON]->setMouseDownCallback(boost::bind(&LLPanelTopInfoBar::onParcelIconClick, this, FLY_ICON));  	mParcelIcon[PUSH_ICON]->setMouseDownCallback(boost::bind(&LLPanelTopInfoBar::onParcelIconClick, this, PUSH_ICON)); @@ -129,6 +137,7 @@ BOOL LLPanelTopInfoBar::postBuild()  {  	mInfoBtn = getChild<LLButton>("place_info_btn");  	mInfoBtn->setClickedCallback(boost::bind(&LLPanelTopInfoBar::onInfoButtonClicked, this)); +	mInfoBtn->setToolTip(LLTrans::getString("LocationCtrlInfoBtnTooltip"));  	mParcelInfoText = getChild<LLTextBox>("parcel_info_text");  	mDamageText = getChild<LLTextBox>("damage_text"); diff --git a/indra/newview/llpreview.cpp b/indra/newview/llpreview.cpp index 69542764d2..a90f23d637 100644 --- a/indra/newview/llpreview.cpp +++ b/indra/newview/llpreview.cpp @@ -454,12 +454,13 @@ LLMultiPreview::LLMultiPreview()  	{  		// start with a rect in the top-left corner ; will get resized  		LLRect rect; -		rect.setLeftTopAndSize(0, gViewerWindow->getWindowHeightScaled(), 200, 200); +		rect.setLeftTopAndSize(0, gViewerWindow->getWindowHeightScaled(), 200, 400);  		setRect(rect);  	}  	setTitle(LLTrans::getString("MultiPreviewTitle"));  	buildTabContainer();  	setCanResize(TRUE); +	mAutoResize = FALSE;  }  void LLMultiPreview::onOpen(const LLSD& key) diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp index 330e809c53..d0ebf047e8 100644 --- a/indra/newview/llpreviewscript.cpp +++ b/indra/newview/llpreviewscript.cpp @@ -2034,7 +2034,17 @@ bool LLLiveLSLEditor::writeToFile(const std::string& filename)  std::string LLLiveLSLEditor::getTmpFileName()  { -	return std::string(LLFile::tmpdir()) + "sl_script_" + mObjectUUID.asString() + ".lsl"; +	// Take script inventory item id (within the object inventory) +	// to consideration so that it's possible to edit multiple scripts +	// in the same object inventory simultaneously (STORM-781). +	std::string script_id = mObjectUUID.asString() + "_" + mItemUUID.asString(); + +	// Use MD5 sum to make the file name shorter and not exceed maximum path length. +	char script_id_hash_str[33];               /* Flawfinder: ignore */ +	LLMD5 script_id_hash((const U8 *)script_id.c_str()); +	script_id_hash.hex_digest(script_id_hash_str); + +	return std::string(LLFile::tmpdir()) + "sl_script_" + script_id_hash_str + ".lsl";  }  void LLLiveLSLEditor::uploadAssetViaCaps(const std::string& url, diff --git a/indra/newview/llpreviewtexture.cpp b/indra/newview/llpreviewtexture.cpp index fd6b326ef1..7657cccd4e 100644 --- a/indra/newview/llpreviewtexture.cpp +++ b/indra/newview/llpreviewtexture.cpp @@ -318,7 +318,7 @@ void LLPreviewTexture::reshape(S32 width, S32 height, BOOL called_from_parent)  		}  	} -	mClientRect.setLeftTopAndSize(client_rect.getCenterX() - (client_width / 2), client_rect.getCenterY() +  (client_height / 2), client_width, client_height);	 +	mClientRect.setLeftTopAndSize(client_rect.getCenterX() - (client_width / 2), client_rect.getCenterY() +  (client_height / 2), client_width, client_height);  } @@ -400,7 +400,6 @@ void LLPreviewTexture::updateDimensions()  	{  		return;  	} -  	mUpdateDimensions = FALSE; @@ -408,80 +407,12 @@ void LLPreviewTexture::updateDimensions()  	getChild<LLUICtrl>("dimensions")->setTextArg("[HEIGHT]", llformat("%d", mImage->getFullHeight())); -	LLRect dim_rect(getChildView("dimensions")->getRect()); - -	S32 horiz_pad = 2 * (LLPANEL_BORDER_WIDTH + PREVIEW_PAD) + PREVIEW_RESIZE_HANDLE_SIZE; - -	// add space for dimensions and aspect ratio -	S32 info_height = dim_rect.mTop + CLIENT_RECT_VPAD; - -	S32 screen_width = gFloaterView->getSnapRect().getWidth(); -	S32 screen_height = gFloaterView->getSnapRect().getHeight(); - -	S32 max_image_width = screen_width - 2*horiz_pad; -	S32 max_image_height = screen_height - (PREVIEW_HEADER_SIZE + CLIENT_RECT_VPAD)  -		- (PREVIEW_BORDER + CLIENT_RECT_VPAD + info_height); - -	S32 client_width = llmin(max_image_width,mImage->getFullWidth()); -	S32 client_height = llmin(max_image_height,mImage->getFullHeight()); - -	if (mAspectRatio > 0.f) -	{ -		if(mAspectRatio > 1.f) -		{ -			client_height = llceil((F32)client_width / mAspectRatio); -			if(client_height > max_image_height) -			{ -				client_height = max_image_height; -				client_width = llceil((F32)client_height * mAspectRatio); -			} -		} -		else//mAspectRatio < 1.f -		{ -			client_width = llceil((F32)client_height * mAspectRatio); -			if(client_width > max_image_width) -			{ -				client_width = max_image_width; -				client_height = llceil((F32)client_width / mAspectRatio); -			} -		} -	} -	else -	{ - -		if(client_height > max_image_height) -		{ -			F32 ratio = (F32)max_image_height/client_height; -			client_height = max_image_height; -			client_width = llceil((F32)client_height * ratio); -		} -		 -		if(client_width > max_image_width) -		{ -			F32 ratio = (F32)max_image_width/client_width; -			client_width = max_image_width; -			client_height = llceil((F32)client_width * ratio); -		} -	} - -	//now back to whole floater -	S32 floater_width = llmax(getMinWidth(),client_width + 2*horiz_pad); -	S32 floater_height = llmax(getMinHeight(),client_height + (PREVIEW_HEADER_SIZE + CLIENT_RECT_VPAD) -		+ (PREVIEW_BORDER + CLIENT_RECT_VPAD + info_height)); -  	//reshape floater -	reshape( floater_width, floater_height ); -	gFloaterView->adjustToFitScreen(this, FALSE); +	reshape(getRect().getWidth(), getRect().getHeight()); -	//setup image rect... -	LLRect client_rect(horiz_pad, getRect().getHeight(), getRect().getWidth() - horiz_pad, 0); -	client_rect.mTop -= (PREVIEW_HEADER_SIZE + CLIENT_RECT_VPAD); -	client_rect.mBottom += PREVIEW_BORDER + CLIENT_RECT_VPAD + info_height ; - -	mClientRect.setLeftTopAndSize(client_rect.getCenterX() - (client_width / 2), client_rect.getCenterY() +  (client_height / 2), client_width, client_height);	 +	gFloaterView->adjustToFitScreen(this, FALSE); -	// Hide the aspect ratio label if the window is too narrow -	// Assumes the label should be to the right of the dimensions +	LLRect dim_rect(getChildView("dimensions")->getRect());  	LLRect aspect_label_rect(getChildView("aspect_ratio")->getRect());  	getChildView("aspect_ratio")->setVisible( dim_rect.mRight < aspect_label_rect.mLeft);  } diff --git a/indra/newview/llprogressview.cpp b/indra/newview/llprogressview.cpp index db02d76139..31fde5d58a 100644 --- a/indra/newview/llprogressview.cpp +++ b/indra/newview/llprogressview.cpp @@ -133,13 +133,13 @@ void LLProgressView::setVisible(BOOL visible)  		mFadeTimer.start();  	}  	// showing progress view -	else if (!getVisible() && visible) +	else if (visible && (!getVisible() || mFadeTimer.getStarted()))  	{  		setFocus(TRUE);  		mFadeTimer.stop();  		mProgressTimer.start();  		LLPanel::setVisible(TRUE); -	} +	}   } diff --git a/indra/newview/llremoteparcelrequest.cpp b/indra/newview/llremoteparcelrequest.cpp index 0dff087553..e5ef51bdd1 100644 --- a/indra/newview/llremoteparcelrequest.cpp +++ b/indra/newview/llremoteparcelrequest.cpp @@ -140,22 +140,25 @@ void LLRemoteParcelInfoProcessor::processParcelInfoReply(LLMessageSystem* msg, v  	typedef std::vector<observer_multimap_t::iterator> deadlist_t;  	deadlist_t dead_iters; -	observer_multimap_t::iterator oi; -	observer_multimap_t::iterator start = observers.lower_bound(parcel_data.parcel_id); +	observer_multimap_t::iterator oi = observers.lower_bound(parcel_data.parcel_id);  	observer_multimap_t::iterator end = observers.upper_bound(parcel_data.parcel_id); -	for (oi = start; oi != end; ++oi) +	while (oi != end)  	{ -		LLRemoteParcelInfoObserver * observer = oi->second.get(); +		// increment the loop iterator now since it may become invalid below +		observer_multimap_t::iterator cur_oi = oi++; + +		LLRemoteParcelInfoObserver * observer = cur_oi->second.get();  		if(observer)  		{ +			// may invalidate cur_oi if the observer removes itself   			observer->processParcelInfo(parcel_data);  		}  		else  		{  			// the handle points to an expired observer, so don't keep it  			// around anymore -			dead_iters.push_back(oi); +			dead_iters.push_back(cur_oi);  		}  	} diff --git a/indra/newview/llscreenchannel.cpp b/indra/newview/llscreenchannel.cpp index 9e0e10d66f..e3bc67a414 100644 --- a/indra/newview/llscreenchannel.cpp +++ b/indra/newview/llscreenchannel.cpp @@ -83,11 +83,10 @@ bool  LLScreenChannelBase::isHovering()  	return mHoveredToast->isHovered();  } -bool LLScreenChannelBase::resetPositionAndSize(const LLSD& newvalue) +void LLScreenChannelBase::resetPositionAndSize()  {  	LLRect rc = gViewerWindow->getWorldViewRectScaled();  	updatePositionAndSize(rc, rc); -	return true;  }  void LLScreenChannelBase::updatePositionAndSize(LLRect old_world_rect, LLRect new_world_rect) @@ -99,10 +98,7 @@ void LLScreenChannelBase::updatePositionAndSize(LLRect old_world_rect, LLRect ne  	if (gSavedSettings.getBOOL("SidebarCameraMovement") == FALSE  		&& LLSideTray::instanceCreated	())  	{ -		LLSideTray*	side_bar = LLSideTray::getInstance(); - -		if (side_bar->getVisible() && !side_bar->getCollapsed()) -			world_rect_padding += side_bar->getRect().getWidth(); +		world_rect_padding += LLSideTray::getInstance()->getVisibleWidth();  	} @@ -133,7 +129,7 @@ void LLScreenChannelBase::init(S32 channel_left, S32 channel_right)  	if(LLSideTray::instanceCreated())  	{  		LLSideTray*	side_bar = LLSideTray::getInstance(); -		side_bar->getCollapseSignal().connect(boost::bind(&LLScreenChannelBase::resetPositionAndSize, this, _2)); +		side_bar->setVisibleWidthChangeCallback(boost::bind(&LLScreenChannelBase::resetPositionAndSize, this));  	}  	// top and bottom set by updateBottom() @@ -214,10 +210,7 @@ void LLScreenChannel::updatePositionAndSize(LLRect old_world_rect, LLRect new_wo  	if (gSavedSettings.getBOOL("SidebarCameraMovement") == FALSE   		&& LLSideTray::instanceCreated	())  	{ -		LLSideTray*	side_bar = LLSideTray::getInstance(); - -		if (side_bar->getVisible() && !side_bar->getCollapsed()) -			world_rect_padding += side_bar->getRect().getWidth(); +		world_rect_padding += LLSideTray::getInstance()->getVisibleWidth();  	} @@ -495,7 +488,7 @@ void LLScreenChannel::modifyToastByNotificationID(LLUUID id, LLPanel* panel)  //--------------------------------------------------------------------------  void LLScreenChannel::redrawToasts()  { -	if(mToastList.size() == 0 || isHovering()) +	if(mToastList.size() == 0)  		return;  	switch(mToastAlignment) @@ -595,20 +588,15 @@ void LLScreenChannel::showToastsBottom()  		}  	} +	// Dismiss toasts we don't have space for (STORM-391).  	if(it != mToastList.rend())  	{  		mHiddenToastsNum = 0;  		for(; it != mToastList.rend(); it++)  		{ -			(*it).toast->stopTimer(); -			(*it).toast->setVisible(FALSE); -			mHiddenToastsNum++; +			(*it).toast->hide();  		}  	} -	else -	{ -		closeOverflowToastPanel(); -	}  }  //-------------------------------------------------------------------------- @@ -731,7 +719,6 @@ void LLNotificationsUI::LLScreenChannel::startToastTimer(LLToast* toast)  //--------------------------------------------------------------------------  void LLScreenChannel::hideToastsFromScreen()  { -	closeOverflowToastPanel();  	for(std::vector<ToastElem>::iterator it = mToastList.begin(); it != mToastList.end(); it++)  		(*it).toast->setVisible(FALSE);  } @@ -847,8 +834,7 @@ void LLScreenChannel::onToastHover(LLToast* toast, bool mouse_enter)  		}  	} -	if(!isHovering()) -		redrawToasts(); +	redrawToasts();  }  //-------------------------------------------------------------------------- diff --git a/indra/newview/llscreenchannel.h b/indra/newview/llscreenchannel.h index 023a65d872..d207d13981 100644 --- a/indra/newview/llscreenchannel.h +++ b/indra/newview/llscreenchannel.h @@ -59,8 +59,8 @@ public:  	// Channel's outfit-functions  	// update channel's size and position in the World View  	virtual void		updatePositionAndSize(LLRect old_world_rect, LLRect new_world_rect); +	void				resetPositionAndSize(); -	bool resetPositionAndSize(const LLSD& newvalue);  	// initialization of channel's shape and position  	virtual void		init(S32 channel_left, S32 channel_right); @@ -81,9 +81,6 @@ public:  	// show all toasts in a channel  	virtual void		redrawToasts() {}; -	virtual void 		closeOverflowToastPanel() {}; -	virtual void 		hideOverflowToastPanel() {}; -  	// Channel's behavior-functions  	// set whether a channel will control hovering inside itself or not diff --git a/indra/newview/llscriptfloater.h b/indra/newview/llscriptfloater.h index dc52baa115..8e959a3d0e 100644 --- a/indra/newview/llscriptfloater.h +++ b/indra/newview/llscriptfloater.h @@ -30,7 +30,7 @@  #include "lltransientdockablefloater.h"  #include "llnotificationptr.h" -class LLToastNotifyPanel; +class LLToastPanel;  /**   * Handles script notifications ("ScriptDialog" and "ScriptDialogGroup") @@ -206,7 +206,7 @@ protected:  private:  	bool isScriptTextbox(LLNotificationPtr notification); -	LLToastNotifyPanel* mScriptForm; +	LLToastPanel* mScriptForm;  	LLUUID mNotificationId;  	LLUUID mObjectId;  	bool mSaveFloaterPosition; diff --git a/indra/newview/llscrollingpanelparam.cpp b/indra/newview/llscrollingpanelparam.cpp index 05b273cd29..f8c20dada0 100644 --- a/indra/newview/llscrollingpanelparam.cpp +++ b/indra/newview/llscrollingpanelparam.cpp @@ -165,12 +165,16 @@ void LLScrollingPanelParam::draw()  	getChildView("max param text")->setVisible( FALSE );  	LLPanel::draw(); +	// If we're in a focused floater, don't apply the floater's alpha to visual param hint, +	// making its behavior similar to texture controls'. +	F32 alpha = getTransparencyType() == TT_ACTIVE ? 1.0f : getCurrentTransparency(); +  	// Draw the hints over the "less" and "more" buttons.  	gGL.pushUIMatrix();  	{  		const LLRect& r = mHintMin->getRect();  		gGL.translateUI((F32)r.mLeft, (F32)r.mBottom, 0.f); -		mHintMin->draw(); +		mHintMin->draw(alpha);  	}  	gGL.popUIMatrix(); @@ -178,7 +182,7 @@ void LLScrollingPanelParam::draw()  	{  		const LLRect& r = mHintMax->getRect();  		gGL.translateUI((F32)r.mLeft, (F32)r.mBottom, 0.f); -		mHintMax->draw(); +		mHintMax->draw(alpha);  	}  	gGL.popUIMatrix(); diff --git a/indra/newview/llsearchcombobox.cpp b/indra/newview/llsearchcombobox.cpp index db531b5695..6558c9a7fa 100644 --- a/indra/newview/llsearchcombobox.cpp +++ b/indra/newview/llsearchcombobox.cpp @@ -131,6 +131,9 @@ void LLSearchComboBox::focusTextEntry()  	if (mTextEntry)  	{  		gFocusMgr.setKeyboardFocus(mTextEntry); + +		// Let the editor handle editing hotkeys (STORM-431). +		LLEditMenuHandler::gEditMenuHandler = mTextEntry;  	}  } diff --git a/indra/newview/llsidepaneliteminfo.cpp b/indra/newview/llsidepaneliteminfo.cpp index be797ea937..c8c6858b81 100644 --- a/indra/newview/llsidepaneliteminfo.cpp +++ b/indra/newview/llsidepaneliteminfo.cpp @@ -71,12 +71,12 @@ void LLItemPropertiesObserver::changed(U32 mask)  	const std::set<LLUUID>& mChangedItemIDs = gInventory.getChangedIDs();  	std::set<LLUUID>::const_iterator it; -	const LLUUID& object_id = mFloater->getObjectID(); +	const LLUUID& item_id = mFloater->getItemID();  	for (it = mChangedItemIDs.begin(); it != mChangedItemIDs.end(); it++)  	{  		// set dirty for 'item profile panel' only if changed item is the item for which 'item profile panel' is shown (STORM-288) -		if (*it == object_id) +		if (*it == item_id)  		{  			// if there's a change we're interested in.  			if((mask & (LLInventoryObserver::LABEL | LLInventoryObserver::INTERNAL | LLInventoryObserver::REMOVE)) != 0) @@ -196,6 +196,11 @@ const LLUUID& LLSidepanelItemInfo::getObjectID() const  	return mObjectID;  } +const LLUUID& LLSidepanelItemInfo::getItemID() const +{ +	return mItemID; +} +  void LLSidepanelItemInfo::reset()  {  	LLSidepanelInventorySubpanel::reset(); diff --git a/indra/newview/llsidepaneliteminfo.h b/indra/newview/llsidepaneliteminfo.h index 6416e2cfe4..25be145f64 100644 --- a/indra/newview/llsidepaneliteminfo.h +++ b/indra/newview/llsidepaneliteminfo.h @@ -55,6 +55,7 @@ public:  	void setEditMode(BOOL edit);  	const LLUUID& getObjectID() const; +	const LLUUID& getItemID() const;  protected:  	/*virtual*/ void refresh(); diff --git a/indra/newview/llsidetray.cpp b/indra/newview/llsidetray.cpp index 3bc3959e0b..aef665a35c 100644 --- a/indra/newview/llsidetray.cpp +++ b/indra/newview/llsidetray.cpp @@ -561,7 +561,7 @@ BOOL LLSideTray::postBuild()  	{  		if ((*it).channel)  		{ -			getCollapseSignal().connect(boost::bind(&LLScreenChannelBase::resetPositionAndSize, (*it).channel, _2)); +			setVisibleWidthChangeCallback(boost::bind(&LLScreenChannelBase::resetPositionAndSize, (*it).channel));  		}  	} @@ -980,9 +980,6 @@ void LLSideTray::reflectCollapseChange()  	}  	gFloaterView->refresh(); -	 -	LLSD new_value = mCollapsed; -	mCollapseSignal(this,new_value);  }  void LLSideTray::arrange() @@ -1262,9 +1259,29 @@ bool		LLSideTray::isPanelActive(const std::string& panel_name)  void	LLSideTray::updateSidetrayVisibility()  {  	// set visibility of parent container based on collapsed state -	if (getParent()) +	LLView* parent = getParent(); +	if (parent)  	{ -		getParent()->setVisible(!mCollapsed && !gAgentCamera.cameraMouselook()); +		bool old_visibility = parent->getVisible(); +		bool new_visibility = !mCollapsed && !gAgentCamera.cameraMouselook(); + +		if (old_visibility != new_visibility) +		{ +			parent->setVisible(new_visibility); + +			// Signal change of visible width. +			llinfos << "Visible: " << new_visibility << llendl; +			mVisibleWidthChangeSignal(this, new_visibility); +		}  	}  } +S32 LLSideTray::getVisibleWidth() +{ +	return (isInVisibleChain() && !mCollapsed) ? getRect().getWidth() : 0; +} + +void LLSideTray::setVisibleWidthChangeCallback(const commit_signal_t::slot_type& cb) +{ +	mVisibleWidthChangeSignal.connect(cb); +} diff --git a/indra/newview/llsidetray.h b/indra/newview/llsidetray.h index 3c572dde95..184d78845f 100644 --- a/indra/newview/llsidetray.h +++ b/indra/newview/llsidetray.h @@ -165,9 +165,18 @@ public:  	void		reshape			(S32 width, S32 height, BOOL called_from_parent = TRUE); -	void		updateSidetrayVisibility(); +	/** +	 * @return side tray width if it's visible and expanded, 0 otherwise. +	 * +	 * Not that width of the tab buttons is not included. +	 * +	 * @see setVisibleWidthChangeCallback() +	 */ +	S32			getVisibleWidth(); + +	void		setVisibleWidthChangeCallback(const commit_signal_t::slot_type& cb); -	commit_signal_t& getCollapseSignal() { return mCollapseSignal; } +	void		updateSidetrayVisibility();  	void		handleLoginComplete(); @@ -216,7 +225,7 @@ private:  	tab_order_vector_t				mOriginalTabOrder;  	LLSideTrayTab*					mActiveTab;	 -	commit_signal_t					mCollapseSignal; +	commit_signal_t					mVisibleWidthChangeSignal;  	LLButton*						mCollapseButton;  	bool							mCollapsed; diff --git a/indra/newview/llsimplestat.h b/indra/newview/llsimplestat.h new file mode 100644 index 0000000000..a90e503adb --- /dev/null +++ b/indra/newview/llsimplestat.h @@ -0,0 +1,158 @@ +/**  + * @file llsimplestat.h + * @brief Runtime statistics accumulation. + * + * $LicenseInfo:firstyear=2010&license=viewergpl$ + *  + * Copyright (c) 2010, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_SIMPLESTAT_H +#define LL_SIMPLESTAT_H + +// History +// +// The original source for this code is the server repositories' +// llcommon/llstat.h file.  This particular code was added after the +// viewer/server code schism but before the effort to convert common +// code to libraries was complete.  Rather than add to merge issues, +// the needed code was cut'n'pasted into this new header as it isn't +// too awful a burden.  Post-modularization, we can look at removing +// this redundancy. + + +/** + * @class LLSimpleStatCounter + * @brief Just counts events. + * + * Really not needed but have a pattern in mind in the future. + * Interface limits what can be done at that's just fine. + * + * *TODO:  Update/transfer unit tests + * Unit tests:  indra/test/llcommon_llstat_tut.cpp + */ +class LLSimpleStatCounter +{ +public: +	inline LLSimpleStatCounter()		{ reset(); } +	// Default destructor and assignment operator are valid + +	inline void reset()					{ mCount = 0; } + +	inline void merge(const LLSimpleStatCounter & src) +										{ mCount += src.mCount; } +	 +	inline U32 operator++()				{ return ++mCount; } + +	inline U32 getCount() const			{ return mCount; } +		 +protected: +	U32			mCount; +}; + + +/** + * @class LLSimpleStatMMM + * @brief Templated collector of min, max and mean data for stats. + * + * Fed a stream of data samples, keeps a running account of the + * min, max and mean seen since construction or the last reset() + * call.  A freshly-constructed or reset instance returns counts + * and values of zero. + * + * Overflows and underflows (integer, inf or -inf) and NaN's + * are the caller's problem.  As is loss of precision when + * the running sum's exponent (when parameterized by a floating + * point of some type) differs from a given data sample's. + * + * Unit tests:  indra/test/llcommon_llstat_tut.cpp + */ +template <typename VALUE_T = F32> +class LLSimpleStatMMM +{ +public: +	typedef VALUE_T Value; +	 +public: +	LLSimpleStatMMM()				{ reset(); } +	// Default destructor and assignment operator are valid + +	/** +	 * Resets the object returning all counts and derived +	 * values back to zero. +	 */ +	void reset() +		{ +			mCount = 0; +			mMin = Value(0); +			mMax = Value(0); +			mTotal = Value(0); +		} + +	void record(Value v) +		{ +			if (mCount) +			{ +				mMin = llmin(mMin, v); +				mMax = llmax(mMax, v); +			} +			else +			{ +				mMin = v; +				mMax = v; +			} +			mTotal += v; +			++mCount; +		} + +	void merge(const LLSimpleStatMMM<VALUE_T> & src) +		{ +			if (! mCount) +			{ +				*this = src; +			} +			else if (src.mCount) +			{ +				mMin = llmin(mMin, src.mMin); +				mMax = llmax(mMax, src.mMax); +				mCount += src.mCount; +				mTotal += src.mTotal; +			} +		} +	 +	inline U32 getCount() const		{ return mCount; } +	inline Value getMin() const		{ return mMin; } +	inline Value getMax() const		{ return mMax; } +	inline Value getMean() const	{ return mCount ? mTotal / mCount : mTotal; } +		 +protected: +	U32			mCount; +	Value		mMin; +	Value		mMax; +	Value		mTotal; +}; + +#endif // LL_SIMPLESTAT_H diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index d945af0776..611f9de2e6 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -3095,7 +3095,16 @@ bool process_login_success_response()  	std::string map_server_url = response["map-server-url"];  	if(!map_server_url.empty())  	{ -		gSavedSettings.setString("MapServerURL", map_server_url);  +		// We got an answer from the grid -> use that for map for the current session +		gSavedSettings.setString("CurrentMapServerURL", map_server_url);  +		LL_INFOS("LLStartup") << "map-server-url : we got an answer from the grid : " << map_server_url << LL_ENDL; +	} +	else +	{ +		// No answer from the grid -> use the default setting for current session  +		map_server_url = gSavedSettings.getString("MapServerURL");  +		gSavedSettings.setString("CurrentMapServerURL", map_server_url);  +		LL_INFOS("LLStartup") << "map-server-url : no map-server-url answer, we use the default setting for the map : " << map_server_url << LL_ENDL;  	}  	// Default male and female avatars allowing the user to choose their avatar on first login. diff --git a/indra/newview/llstatusbar.cpp b/indra/newview/llstatusbar.cpp index e9fc25404a..1b8be7a5b2 100644 --- a/indra/newview/llstatusbar.cpp +++ b/indra/newview/llstatusbar.cpp @@ -115,6 +115,7 @@ LLStatusBar::LLStatusBar(const LLRect& rect)  	mSGBandwidth(NULL),  	mSGPacketLoss(NULL),  	mBtnVolume(NULL), +	mBoxBalance(NULL),  	mBalance(0),  	mHealth(100),  	mSquareMetersCredit(0), @@ -168,6 +169,9 @@ BOOL LLStatusBar::postBuild()  	getChild<LLUICtrl>("buyL")->setCommitCallback(  		boost::bind(&LLStatusBar::onClickBuyCurrency, this)); +	mBoxBalance = getChild<LLTextBox>("balance"); +	mBoxBalance->setClickedCallback( &LLStatusBar::onClickBalance, this ); +  	mBtnVolume = getChild<LLButton>( "volume_btn" );  	mBtnVolume->setClickedCallback( onClickVolume, this );  	mBtnVolume->setMouseEnterCallback(boost::bind(&LLStatusBar::onMouseEnterVolume, this)); @@ -304,6 +308,7 @@ void LLStatusBar::setVisibleForMouselook(bool visible)  {  	mTextTime->setVisible(visible);  	getChild<LLUICtrl>("balance_bg")->setVisible(visible); +	mBoxBalance->setVisible(visible);  	mBtnVolume->setVisible(visible);  	mMediaToggle->setVisible(visible);  	mSGBandwidth->setVisible(visible); @@ -330,16 +335,15 @@ void LLStatusBar::setBalance(S32 balance)  	std::string money_str = LLResMgr::getInstance()->getMonetaryString( balance ); -	LLTextBox* balance_box = getChild<LLTextBox>("balance");  	LLStringUtil::format_map_t string_args;  	string_args["[AMT]"] = llformat("%s", money_str.c_str());  	std::string label_str = getString("buycurrencylabel", string_args); -	balance_box->setValue(label_str); +	mBoxBalance->setValue(label_str);  	// Resize the L$ balance background to be wide enough for your balance plus the buy button  	{  		const S32 HPAD = 24; -		LLRect balance_rect = balance_box->getTextBoundingRect(); +		LLRect balance_rect = mBoxBalance->getTextBoundingRect();  		LLRect buy_rect = getChildView("buyL")->getRect();  		LLView* balance_bg_view = getChildView("balance_bg");  		LLRect balance_bg_rect = balance_bg_view->getRect(); @@ -506,6 +510,14 @@ static void onClickVolume(void* data)  }  //static  +void LLStatusBar::onClickBalance(void* ) +{ +	// Force a balance request message: +	LLStatusBar::sendMoneyBalanceRequest(); +	// The refresh of the display (call to setBalance()) will be done by process_money_balance_reply() +} + +//static   void LLStatusBar::onClickMediaToggle(void* data)  {  	LLStatusBar *status_bar = (LLStatusBar*)data; diff --git a/indra/newview/llstatusbar.h b/indra/newview/llstatusbar.h index 2388aeb0c8..4ea3183d18 100644 --- a/indra/newview/llstatusbar.h +++ b/indra/newview/llstatusbar.h @@ -94,6 +94,7 @@ private:  	void onClickScreen(S32 x, S32 y);  	static void onClickMediaToggle(void* data); +	static void onClickBalance(void* data);  private:  	LLTextBox	*mTextTime; @@ -102,6 +103,7 @@ private:  	LLStatGraph *mSGPacketLoss;  	LLButton	*mBtnVolume; +	LLTextBox	*mBoxBalance;  	LLButton	*mMediaToggle;  	LLView*		mScriptOut;  	LLFrameTimer	mClockUpdateTimer; diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index 13fd51f473..4f63abb152 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -27,6 +27,7 @@  #include "llviewerprecompiledheaders.h"  #include <iostream> +#include <map>  #include "llstl.h" @@ -49,6 +50,7 @@  #include "llviewertexture.h"  #include "llviewerregion.h"  #include "llviewerstats.h" +#include "llviewerassetstats.h"  #include "llworld.h"  ////////////////////////////////////////////////////////////////////////////// @@ -143,7 +145,7 @@ public:  	/*virtual*/ bool deleteOK(); // called from update() (WORK THREAD)  	~LLTextureFetchWorker(); -	void relese() { --mActiveCount; } +	// void relese() { --mActiveCount; }  	S32 callbackHttpGet(const LLChannelDescriptors& channels,  						 const LLIOPipe::buffer_ptr_t& buffer, @@ -161,9 +163,11 @@ public:  		mGetReason = reason;  	} -	void setCanUseHTTP(bool can_use_http) {mCanUseHTTP = can_use_http;} -	bool getCanUseHTTP()const {return mCanUseHTTP ;} +	void setCanUseHTTP(bool can_use_http) { mCanUseHTTP = can_use_http; } +	bool getCanUseHTTP() const { return mCanUseHTTP; } +	LLTextureFetch & getFetcher() { return *mFetcher; } +	  protected:  	LLTextureFetchWorker(LLTextureFetch* fetcher, const std::string& url, const LLUUID& id, const LLHost& host,  						 F32 priority, S32 discard, S32 size); @@ -277,6 +281,8 @@ private:  	S32 mLastPacket;  	U16 mTotalPackets;  	U8 mImageCodec; + +	LLViewerAssetStats::duration_t mMetricsStartTime;  };  ////////////////////////////////////////////////////////////////////////////// @@ -344,6 +350,18 @@ public:  			}  			mFetcher->removeFromHTTPQueue(mID, data_size); + +			if (worker->mMetricsStartTime) +			{ +				LLViewerAssetStatsFF::record_response_thread1(LLViewerAssetType::AT_TEXTURE, +															  true, +															  LLImageBase::TYPE_AVATAR_BAKE == worker->mType, +															  LLViewerAssetStatsFF::get_timestamp() - worker->mMetricsStartTime); +				worker->mMetricsStartTime = 0; +			} +			LLViewerAssetStatsFF::record_dequeue_thread1(LLViewerAssetType::AT_TEXTURE, +														 true, +														 LLImageBase::TYPE_AVATAR_BAKE == worker->mType);  		}  		else  		{ @@ -368,6 +386,229 @@ private:  ////////////////////////////////////////////////////////////////////////////// +// Cross-thread messaging for asset metrics. + +/** + * @brief Base class for cross-thread requests made of the fetcher + * + * I believe the intent of the LLQueuedThread class was to + * have these operations derived from LLQueuedThread::QueuedRequest + * but the texture fetcher has elected to manage the queue + * in its own manner.  So these are free-standing objects which are + * managed in simple FIFO order on the mCommands queue of the + * LLTextureFetch object. + * + * What each represents is a simple command sent from an + * outside thread into the TextureFetch thread to be processed + * in order and in a timely fashion (though not an absolute + * higher priority than other operations of the thread). + * Each operation derives a new class from the base customizing + * members, constructors and the doWork() method to effect + * the command. + * + * The flow is one-directional.  There are two global instances + * of the LLViewerAssetStats collector, one for the main program's + * thread pointed to by gViewerAssetStatsMain and one for the + * TextureFetch thread pointed to by gViewerAssetStatsThread1. + * Common operations has each thread recording metrics events + * into the respective collector unconcerned with locking and + * the state of any other thread.  But when the agent moves into + * a different region or the metrics timer expires and a report + * needs to be sent back to the grid, messaging across threads + * is required to distribute data and perform global actions. + * In pseudo-UML, it looks like: + * + *                       Main                 Thread1 + *                        .                      . + *                        .                      . + *                     +-----+                   . + *                     | AM  |                   . + *                     +--+--+                   . + *      +-------+         |                      . + *      | Main  |      +--+--+                   . + *      |       |      | SRE |---.               . + *      | Stats |      +-----+    \              . + *      |       |         |        \  (uuid)  +-----+ + *      | Coll. |      +--+--+      `-------->| SR  | + *      +-------+      | MSC |                +--+--+ + *         | ^         +-----+                   | + *         | |  (uuid)  / .                   +-----+ (uuid) + *         |  `--------'  .                   | MSC |---------. + *         |              .                   +-----+         | + *         |           +-----+                   .            v + *         |           | TE  |                   .        +-------+ + *         |           +--+--+                   .        | Thd1  | + *         |              |                      .        |       | + *         |           +-----+                   .        | Stats | + *          `--------->| RSC |                   .        |       | + *                     +--+--+                   .        | Coll. | + *                        |                      .        +-------+ + *                     +--+--+                   .            | + *                     | SME |---.               .            | + *                     +-----+    \              .            | + *                        .        \ (clone)  +-----+         | + *                        .         `-------->| SM  |         | + *                        .                   +--+--+         | + *                        .                      |            | + *                        .                   +-----+         | + *                        .                   | RSC |<--------' + *                        .                   +-----+ + *                        .                      | + *                        .                   +-----+ + *                        .                   | CP  |--> HTTP POST + *                        .                   +-----+ + *                        .                      . + *                        .                      . + * + * + * Key: + * + * SRE - Set Region Enqueued.  Enqueue a 'Set Region' command in + *       the other thread providing the new UUID of the region. + *       TFReqSetRegion carries the data. + * SR  - Set Region.  New region UUID is sent to the thread-local + *       collector. + * SME - Send Metrics Enqueued.  Enqueue a 'Send Metrics' command + *       including an ownership transfer of a cloned LLViewerAssetStats. + *       TFReqSendMetrics carries the data. + * SM  - Send Metrics.  Global metrics reporting operation.  Takes + *       the cloned stats from the command, merges it with the + *       thread's local stats, converts to LLSD and sends it on + *       to the grid. + * AM  - Agent Moved.  Agent has completed some sort of move to a + *       new region. + * TE  - Timer Expired.  Metrics timer has expired (on the order + *       of 10 minutes). + * CP  - CURL Post + * MSC - Modify Stats Collector.  State change in the thread-local + *       collector.  Typically a region change which affects the + *       global pointers used to find the 'current stats'. + * RSC - Read Stats Collector.  Extract collector data cloning it + *       (i.e. deep copy) when necessary. + * + */ +class LLTextureFetch::TFRequest // : public LLQueuedThread::QueuedRequest +{ +public: +	// Default ctors and assignment operator are correct. + +	virtual ~TFRequest() +		{} + +	// Patterned after QueuedRequest's method but expected behavior +	// is different.  Always expected to complete on the first call +	// and work dispatcher will assume the same and delete the +	// request after invocation. +	virtual bool doWork(LLTextureFetch * fetcher) = 0; +}; + +namespace  +{ + +/** + * @brief Implements a 'Set Region' cross-thread command. + * + * When an agent moves to a new region, subsequent metrics need + * to be binned into a new or existing stats collection in 1:1 + * relationship with the region.  We communicate this region + * change across the threads involved in the communication with + * this message. + * + * Corresponds to LLTextureFetch::commandSetRegion() + */ +class TFReqSetRegion : public LLTextureFetch::TFRequest +{ +public: +	TFReqSetRegion(U64 region_handle) +		: LLTextureFetch::TFRequest(), +		  mRegionHandle(region_handle) +		{} +	TFReqSetRegion & operator=(const TFReqSetRegion &);	// Not defined + +	virtual ~TFReqSetRegion() +		{} + +	virtual bool doWork(LLTextureFetch * fetcher); +		 +public: +	const U64 mRegionHandle; +}; + + +/** + * @brief Implements a 'Send Metrics' cross-thread command. + * + * This is the big operation.  The main thread gathers metrics + * for a period of minutes into LLViewerAssetStats and other + * objects then makes a snapshot of the data by cloning the + * collector.  This command transfers the clone, along with a few + * additional arguments (UUIDs), handing ownership to the + * TextureFetch thread.  It then merges its own data into the + * cloned copy, converts to LLSD and kicks off an HTTP POST of + * the resulting data to the currently active metrics collector. + * + * Corresponds to LLTextureFetch::commandSendMetrics() + */ +class TFReqSendMetrics : public LLTextureFetch::TFRequest +{ +public: +    /** +	 * Construct the 'Send Metrics' command to have the TextureFetch +	 * thread add and log metrics data. +	 * +	 * @param	caps_url		URL of a "ViewerMetrics" Caps target +	 *							to receive the data.  Does not have to +	 *							be associated with a particular region. +	 * +	 * @param	session_id		UUID of the agent's session. +	 * +	 * @param	agent_id		UUID of the agent.  (Being pure here...) +	 * +	 * @param	main_stats		Pointer to a clone of the main thread's +	 *							LLViewerAssetStats data.  Thread1 takes +	 *							ownership of the copy and disposes of it +	 *							when done. +	 */ +	TFReqSendMetrics(const std::string & caps_url, +					 const LLUUID & session_id, +					 const LLUUID & agent_id, +					 LLViewerAssetStats * main_stats) +		: LLTextureFetch::TFRequest(), +		  mCapsURL(caps_url), +		  mSessionID(session_id), +		  mAgentID(agent_id), +		  mMainStats(main_stats) +		{} +	TFReqSendMetrics & operator=(const TFReqSendMetrics &);	// Not defined + +	virtual ~TFReqSendMetrics(); + +	virtual bool doWork(LLTextureFetch * fetcher); +		 +public: +	const std::string mCapsURL; +	const LLUUID mSessionID; +	const LLUUID mAgentID; +	LLViewerAssetStats * mMainStats; +}; + +/* + * Examines the merged viewer metrics report and if found to be too long, + * will attempt to truncate it in some reasonable fashion. + * + * @param		max_regions		Limit of regions allowed in report. + * + * @param		metrics			Full, merged viewer metrics report. + * + * @returns		If data was truncated, returns true. + */ +bool truncate_viewer_metrics(int max_regions, LLSD & metrics); + +} // end of anonymous namespace + + +////////////////////////////////////////////////////////////////////////////// +  //static  const char* LLTextureFetchWorker::sStateDescs[] = {  	"INVALID", @@ -385,6 +626,9 @@ const char* LLTextureFetchWorker::sStateDescs[] = {  	"DONE",  }; +// static +volatile bool LLTextureFetch::svMetricsDataBreak(true);	// Start with a data break +  // called from MAIN THREAD  LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher, @@ -434,7 +678,8 @@ LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher,  	  mFirstPacket(0),  	  mLastPacket(-1),  	  mTotalPackets(0), -	  mImageCodec(IMG_CODEC_INVALID) +	  mImageCodec(IMG_CODEC_INVALID), +	  mMetricsStartTime(0)  {  	mCanUseNET = mUrl.empty() ; @@ -602,6 +847,7 @@ bool LLTextureFetchWorker::doWork(S32 param)  			return true; // abort  		}  	} +  	if(mImagePriority < F_ALMOST_ZERO)  	{  		if (mState == INIT || mState == LOAD_FROM_NETWORK || mState == LOAD_FROM_SIMULATOR) @@ -811,7 +1057,15 @@ bool LLTextureFetchWorker::doWork(S32 param)  			mRequestedDiscard = mDesiredDiscard;  			mSentRequest = QUEUED;  			mFetcher->addToNetworkQueue(this); +			if (! mMetricsStartTime) +			{ +				mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp(); +			} +			LLViewerAssetStatsFF::record_enqueue_thread1(LLViewerAssetType::AT_TEXTURE, +														 false, +														 LLImageBase::TYPE_AVATAR_BAKE == mType);  			setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); +			  			return false;  		}  		else @@ -820,6 +1074,12 @@ bool LLTextureFetchWorker::doWork(S32 param)  			//llassert_always(mFetcher->mNetworkQueue.find(mID) != mFetcher->mNetworkQueue.end());  			// Make certain this is in the network queue  			//mFetcher->addToNetworkQueue(this); +			//if (! mMetricsStartTime) +			//{ +			//   mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp(); +			//} +			//LLViewerAssetStatsFF::record_enqueue_thread1(LLViewerAssetType::AT_TEXTURE, false, +			//                                             LLImageBase::TYPE_AVATAR_BAKE == mType);  			//setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);  			return false;  		} @@ -843,11 +1103,30 @@ bool LLTextureFetchWorker::doWork(S32 param)  			}  			setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);  			mState = DECODE_IMAGE; -			mWriteToCacheState = SHOULD_WRITE ; +			mWriteToCacheState = SHOULD_WRITE; + +			if (mMetricsStartTime) +			{ +				LLViewerAssetStatsFF::record_response_thread1(LLViewerAssetType::AT_TEXTURE, +															  false, +															  LLImageBase::TYPE_AVATAR_BAKE == mType, +															  LLViewerAssetStatsFF::get_timestamp() - mMetricsStartTime); +				mMetricsStartTime = 0; +			} +			LLViewerAssetStatsFF::record_dequeue_thread1(LLViewerAssetType::AT_TEXTURE, +														 false, +														 LLImageBase::TYPE_AVATAR_BAKE == mType);  		}  		else  		{  			mFetcher->addToNetworkQueue(this); // failsafe +			if (! mMetricsStartTime) +			{ +				mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp(); +			} +			LLViewerAssetStatsFF::record_enqueue_thread1(LLViewerAssetType::AT_TEXTURE, +														 false, +														 LLImageBase::TYPE_AVATAR_BAKE == mType);  			setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);  		}  		return false; @@ -909,6 +1188,14 @@ bool LLTextureFetchWorker::doWork(S32 param)  				mState = WAIT_HTTP_REQ;	  				mFetcher->addToHTTPQueue(mID); +				if (! mMetricsStartTime) +				{ +					mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp(); +				} +				LLViewerAssetStatsFF::record_enqueue_thread1(LLViewerAssetType::AT_TEXTURE, +															 true, +															 LLImageBase::TYPE_AVATAR_BAKE == mType); +  				// Will call callbackHttpGet when curl request completes  				std::vector<std::string> headers;  				headers.push_back("Accept: image/x-j2c"); @@ -1523,7 +1810,7 @@ bool LLTextureFetchWorker::writeToCacheComplete()  //////////////////////////////////////////////////////////////////////////////  // public -LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* imagedecodethread, bool threaded) +LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* imagedecodethread, bool threaded, bool qa_mode)  	: LLWorkerThread("TextureFetch", threaded),  	  mDebugCount(0),  	  mDebugPause(FALSE), @@ -1535,8 +1822,10 @@ LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* image  	  mImageDecodeThread(imagedecodethread),  	  mTextureBandwidth(0),  	  mHTTPTextureBits(0), -	  mCurlGetRequest(NULL) +	  mCurlGetRequest(NULL), +	  mQAMode(qa_mode)  { +	mCurlPOSTRequestCount = 0;  	mMaxBandwidth = gSavedSettings.getF32("ThrottleBandwidthKBPS");  	mTextureInfo.setUpLogging(gSavedSettings.getBOOL("LogTextureDownloadsToViewerLog"), gSavedSettings.getBOOL("LogTextureDownloadsToSimulator"), gSavedSettings.getU32("TextureLoggingThreshold"));  } @@ -1545,6 +1834,13 @@ LLTextureFetch::~LLTextureFetch()  {  	clearDeleteList() ; +	while (! mCommands.empty()) +	{ +		TFRequest * req(mCommands.front()); +		mCommands.erase(mCommands.begin()); +		delete req; +	} +	  	// ~LLQueuedThread() called here  } @@ -1825,8 +2121,76 @@ bool LLTextureFetch::updateRequestPriority(const LLUUID& id, F32 priority)  	return res;  } +// Replicates and expands upon the base class's +// getPending() implementation.  getPending() and +// runCondition() replicate one another's logic to +// an extent and are sometimes used for the same +// function (deciding whether or not to sleep/pause +// a thread).  So the implementations need to stay +// in step, at least until this can be refactored and +// the redundancy eliminated. +// +// May be called from any thread + +//virtual +S32 LLTextureFetch::getPending() +{ +	S32 res; +	lockData(); +    { +        LLMutexLock lock(&mQueueMutex); +         +        res = mRequestQueue.size(); +        res += mCurlPOSTRequestCount; +        res += mCommands.size(); +    } +	unlockData(); +	return res; +} + +// virtual +bool LLTextureFetch::runCondition() +{ +	// Caller is holding the lock on LLThread's condition variable. +	 +	// LLQueuedThread, unlike its base class LLThread, makes this a +	// private method which is unfortunate.  I want to use it directly +	// but I'm going to have to re-implement the logic here (or change +	// declarations, which I don't want to do right now). +	// +	// Changes here may need to be reflected in getPending(). +	 +	bool have_no_commands(false); +	{ +		LLMutexLock lock(&mQueueMutex); +		 +		have_no_commands = mCommands.empty(); +	} +	 +    bool have_no_curl_requests(0 == mCurlPOSTRequestCount); +	 +	return ! (have_no_commands +			  && have_no_curl_requests +			  && (mRequestQueue.empty() && mIdleThread));		// From base class +} +  ////////////////////////////////////////////////////////////////////////////// +// MAIN THREAD (unthreaded envs), WORKER THREAD (threaded envs) +void LLTextureFetch::commonUpdate() +{ +	// Run a cross-thread command, if any. +	cmdDoWork(); +	 +	// Update Curl on same thread as mCurlGetRequest was constructed +	S32 processed = mCurlGetRequest->process(); +	if (processed > 0) +	{ +		lldebugs << "processed: " << processed << " messages." << llendl; +	} +} + +  // MAIN THREAD  //virtual  S32 LLTextureFetch::update(U32 max_time_ms) @@ -1852,12 +2216,7 @@ S32 LLTextureFetch::update(U32 max_time_ms)  	if (!mThreaded)  	{ -		// Update Curl on same thread as mCurlGetRequest was constructed -		S32 processed = mCurlGetRequest->process(); -		if (processed > 0) -		{ -			lldebugs << "processed: " << processed << " messages." << llendl; -		} +		commonUpdate();  	}  	return res; @@ -1912,12 +2271,7 @@ void LLTextureFetch::threadedUpdate()  	}  	process_timer.reset(); -	// Update Curl on same thread as mCurlGetRequest was constructed -	S32 processed = mCurlGetRequest->process(); -	if (processed > 0) -	{ -		lldebugs << "processed: " << processed << " messages." << llendl; -	} +	commonUpdate();  #if 0  	const F32 INFO_TIME = 1.0f;  @@ -2367,3 +2721,280 @@ void LLTextureFetch::dump()  	}  } +////////////////////////////////////////////////////////////////////////////// + +// cross-thread command methods + +void LLTextureFetch::commandSetRegion(U64 region_handle) +{ +	TFReqSetRegion * req = new TFReqSetRegion(region_handle); + +	cmdEnqueue(req); +} + +void LLTextureFetch::commandSendMetrics(const std::string & caps_url, +										const LLUUID & session_id, +										const LLUUID & agent_id, +										LLViewerAssetStats * main_stats) +{ +	TFReqSendMetrics * req = new TFReqSendMetrics(caps_url, session_id, agent_id, main_stats); + +	cmdEnqueue(req); +} + +void LLTextureFetch::commandDataBreak() +{ +	// The pedantically correct way to implement this is to create a command +	// request object in the above fashion and enqueue it.  However, this is +	// simple data of an advisorial not operational nature and this case +	// of shared-write access is tolerable. + +	LLTextureFetch::svMetricsDataBreak = true; +} + +void LLTextureFetch::cmdEnqueue(TFRequest * req) +{ +	lockQueue(); +	mCommands.push_back(req); +	unlockQueue(); + +	unpause(); +} + +LLTextureFetch::TFRequest * LLTextureFetch::cmdDequeue() +{ +	TFRequest * ret = 0; +	 +	lockQueue(); +	if (! mCommands.empty()) +	{ +		ret = mCommands.front(); +		mCommands.erase(mCommands.begin()); +	} +	unlockQueue(); + +	return ret; +} + +void LLTextureFetch::cmdDoWork() +{ +	if (mDebugPause) +	{ +		return;  // debug: don't do any work +	} + +	TFRequest * req = cmdDequeue(); +	if (req) +	{ +		// One request per pass should really be enough for this. +		req->doWork(this); +		delete req; +	} +} + + +////////////////////////////////////////////////////////////////////////////// + +// Private (anonymous) class methods implementing the command scheme. + +namespace +{ + +/** + * Implements the 'Set Region' command. + * + * Thread:  Thread1 (TextureFetch) + */ +bool +TFReqSetRegion::doWork(LLTextureFetch *) +{ +	LLViewerAssetStatsFF::set_region_thread1(mRegionHandle); + +	return true; +} + + +TFReqSendMetrics::~TFReqSendMetrics() +{ +	delete mMainStats; +	mMainStats = 0; +} + + +/** + * Implements the 'Send Metrics' command.  Takes over + * ownership of the passed LLViewerAssetStats pointer. + * + * Thread:  Thread1 (TextureFetch) + */ +bool +TFReqSendMetrics::doWork(LLTextureFetch * fetcher) +{ +	/* +	 * HTTP POST responder.  Doesn't do much but tries to +	 * detect simple breaks in recording the metrics stream. +	 * +	 * The 'volatile' modifiers don't indicate signals, +	 * mmap'd memory or threads, really.  They indicate that +	 * the referenced data is part of a pseudo-closure for +	 * this responder rather than being required for correct +	 * operation. +     * +     * We don't try very hard with the POST request.  We give +     * it one shot and that's more-or-less it.  With a proper +     * refactoring of the LLQueuedThread usage, these POSTs +     * could be put in a request object and made more reliable. +	 */ +	class lcl_responder : public LLCurl::Responder +	{ +	public: +		lcl_responder(LLTextureFetch * fetcher, +					  S32 expected_sequence, +                      volatile const S32 & live_sequence, +                      volatile bool & reporting_break, +					  volatile bool & reporting_started) +			: LLCurl::Responder(), +			  mFetcher(fetcher), +              mExpectedSequence(expected_sequence), +              mLiveSequence(live_sequence), +			  mReportingBreak(reporting_break), +			  mReportingStarted(reporting_started) +			{ +                mFetcher->incrCurlPOSTCount(); +            } +         +        ~lcl_responder() +            { +                mFetcher->decrCurlPOSTCount(); +            } + +		// virtual +		void error(U32 status_num, const std::string & reason) +			{ +                if (mLiveSequence == mExpectedSequence) +                { +                    mReportingBreak = true; +                } +				LL_WARNS("Texture") << "Break in metrics stream due to POST failure to metrics collection service.  Reason:  " +									<< reason << LL_ENDL; +			} + +		// virtual +		void result(const LLSD & content) +			{ +                if (mLiveSequence == mExpectedSequence) +                { +                    mReportingBreak = false; +                    mReportingStarted = true; +                } +			} + +	private: +		LLTextureFetch * mFetcher; +        S32 mExpectedSequence; +        volatile const S32 & mLiveSequence; +		volatile bool & mReportingBreak; +		volatile bool & mReportingStarted; + +	}; // class lcl_responder +	 +	if (! gViewerAssetStatsThread1) +		return true; + +	static volatile bool reporting_started(false); +	static volatile S32 report_sequence(0); +     +	// We've taken over ownership of the stats copy at this +	// point.  Get a working reference to it for merging here +	// but leave it in 'this'.  Destructor will rid us of it. +	LLViewerAssetStats & main_stats = *mMainStats; + +	// Merge existing stats into those from main, convert to LLSD +	main_stats.merge(*gViewerAssetStatsThread1); +	LLSD merged_llsd = main_stats.asLLSD(true); + +	// Add some additional meta fields to the content +	merged_llsd["session_id"] = mSessionID; +	merged_llsd["agent_id"] = mAgentID; +	merged_llsd["message"] = "ViewerAssetMetrics";					// Identifies the type of metrics +	merged_llsd["sequence"] = report_sequence;						// Sequence number +	merged_llsd["initial"] = ! reporting_started;					// Initial data from viewer +	merged_llsd["break"] = LLTextureFetch::svMetricsDataBreak;		// Break in data prior to this report +		 +	// Update sequence number +	if (S32_MAX == ++report_sequence) +		report_sequence = 0; + +	// Limit the size of the stats report if necessary. +	merged_llsd["truncated"] = truncate_viewer_metrics(10, merged_llsd); + +	if (! mCapsURL.empty()) +	{ +		LLCurlRequest::headers_t headers; +		fetcher->getCurlRequest().post(mCapsURL, +									   headers, +									   merged_llsd, +									   new lcl_responder(fetcher, +														 report_sequence, +                                                         report_sequence, +                                                         LLTextureFetch::svMetricsDataBreak, +														 reporting_started)); +	} +	else +	{ +		LLTextureFetch::svMetricsDataBreak = true; +	} + +	// In QA mode, Metrics submode, log the result for ease of testing +	if (fetcher->isQAMode()) +	{ +		LL_INFOS("Textures") << merged_llsd << LL_ENDL; +	} + +	gViewerAssetStatsThread1->reset(); + +	return true; +} + + +bool +truncate_viewer_metrics(int max_regions, LLSD & metrics) +{ +	static const LLSD::String reg_tag("regions"); +	static const LLSD::String duration_tag("duration"); +	 +	LLSD & reg_map(metrics[reg_tag]); +	if (reg_map.size() <= max_regions) +	{ +		return false; +	} + +	// Build map of region hashes ordered by duration +	typedef std::multimap<LLSD::Real, int> reg_ordered_list_t; +	reg_ordered_list_t regions_by_duration; + +	int ind(0); +	LLSD::array_const_iterator it_end(reg_map.endArray()); +	for (LLSD::array_const_iterator it(reg_map.beginArray()); it_end != it; ++it, ++ind) +	{ +		LLSD::Real duration = (*it)[duration_tag].asReal(); +		regions_by_duration.insert(reg_ordered_list_t::value_type(duration, ind)); +	} + +	// Build a replacement regions array with the longest-persistence regions +	LLSD new_region(LLSD::emptyArray()); +	reg_ordered_list_t::const_reverse_iterator it2_end(regions_by_duration.rend()); +	reg_ordered_list_t::const_reverse_iterator it2(regions_by_duration.rbegin()); +	for (int i(0); i < max_regions && it2_end != it2; ++i, ++it2) +	{ +		new_region.append(reg_map[it2->second]); +	} +	reg_map = new_region; +	 +	return true; +} + +} // end of anonymous namespace + + + diff --git a/indra/newview/lltexturefetch.h b/indra/newview/lltexturefetch.h index 796109df06..ad00a7ea36 100644 --- a/indra/newview/lltexturefetch.h +++ b/indra/newview/lltexturefetch.h @@ -33,6 +33,7 @@  #include "llworkerthread.h"  #include "llcurl.h"  #include "lltextureinfo.h" +#include "llapr.h"  class LLViewerTexture;  class LLTextureFetchWorker; @@ -40,6 +41,7 @@ class HTTPGetResponder;  class LLTextureCache;  class LLImageDecodeThread;  class LLHost; +class LLViewerAssetStats;  // Interface class  class LLTextureFetch : public LLWorkerThread @@ -48,9 +50,11 @@ class LLTextureFetch : public LLWorkerThread  	friend class HTTPGetResponder;  public: -	LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* imagedecodethread, bool threaded); +	LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* imagedecodethread, bool threaded, bool qa_mode);  	~LLTextureFetch(); +	class TFRequest; +	  	/*virtual*/ S32 update(U32 max_time_ms);	  	void shutDownTextureCacheThread() ; //called in the main thread after the TextureCacheThread shuts down.  	void shutDownImageDecodeThread() ;  //called in the main thread after the ImageDecodeThread shuts down. @@ -77,28 +81,77 @@ public:  	S32 getNumHTTPRequests() ;  	// Public for access by callbacks +    S32 getPending();  	void lockQueue() { mQueueMutex.lock(); }  	void unlockQueue() { mQueueMutex.unlock(); }  	LLTextureFetchWorker* getWorker(const LLUUID& id);  	LLTextureFetchWorker* getWorkerAfterLock(const LLUUID& id);  	LLTextureInfo* getTextureInfo() { return &mTextureInfo; } -	 + +	// Commands available to other threads to control metrics gathering operations. +	void commandSetRegion(U64 region_handle); +	void commandSendMetrics(const std::string & caps_url, +							const LLUUID & session_id, +							const LLUUID & agent_id, +							LLViewerAssetStats * main_stats); +	void commandDataBreak(); + +	LLCurlRequest & getCurlRequest()	{ return *mCurlGetRequest; } + +	bool isQAMode() const				{ return mQAMode; } + +	// Curl POST counter maintenance +	inline void incrCurlPOSTCount()		{ mCurlPOSTRequestCount++; } +	inline void decrCurlPOSTCount()		{ mCurlPOSTRequestCount--; } +  protected:  	void addToNetworkQueue(LLTextureFetchWorker* worker);  	void removeFromNetworkQueue(LLTextureFetchWorker* worker, bool cancel);  	void addToHTTPQueue(const LLUUID& id);  	void removeFromHTTPQueue(const LLUUID& id, S32 received_size = 0);  	void removeRequest(LLTextureFetchWorker* worker, bool cancel); -	// Called from worker thread (during doWork) -	void processCurlRequests();	 + +	// Overrides from the LLThread tree +	bool runCondition();  private:  	void sendRequestListToSimulators();  	/*virtual*/ void startThread(void);  	/*virtual*/ void endThread(void);  	/*virtual*/ void threadedUpdate(void); - +	void commonUpdate(); + +	// Metrics command helpers +	/** +	 * Enqueues a command request at the end of the command queue +	 * and wakes up the thread as needed. +	 * +	 * Takes ownership of the TFRequest object. +	 * +	 * Method locks the command queue. +	 */ +	void cmdEnqueue(TFRequest *); + +	/** +	 * Returns the first TFRequest object in the command queue or +	 * NULL if none is present. +	 * +	 * Caller acquires ownership of the object and must dispose of it. +	 * +	 * Method locks the command queue. +	 */ +	TFRequest * cmdDequeue(); + +	/** +	 * Processes the first command in the queue disposing of the +	 * request on completion.  Successive calls are needed to perform +	 * additional commands. +	 * +	 * Method locks the command queue. +	 */ +	void cmdDoWork(); +	  public:  	LLUUID mDebugID;  	S32 mDebugCount; @@ -107,7 +160,7 @@ public:  	S32 mBadPacketCount;  private: -	LLMutex mQueueMutex;        //to protect mRequestMap only +	LLMutex mQueueMutex;        //to protect mRequestMap and mCommands only  	LLMutex mNetworkQueueMutex; //to protect mNetworkQueue, mHTTPTextureQueue and mCancelQueue.  	LLTextureCache* mTextureCache; @@ -129,6 +182,29 @@ private:  	LLTextureInfo mTextureInfo;  	U32 mHTTPTextureBits; + +	// Out-of-band cross-thread command queue.  This command queue +	// is logically tied to LLQueuedThread's list of +	// QueuedRequest instances and so must be covered by the +	// same locks. +	typedef std::vector<TFRequest *> command_queue_t; +	command_queue_t mCommands; + +	// If true, modifies some behaviors that help with QA tasks. +	const bool mQAMode; + +	// Count of POST requests outstanding.  We maintain the count +	// indirectly in the CURL request responder's ctor and dtor and +	// use it when determining whether or not to sleep the thread.  Can't +	// use the LLCurl module's request counter as it isn't thread compatible. +	// *NOTE:  Don't mix Atomic and static, apr_initialize must be called first. +	LLAtomic32<S32> mCurlPOSTRequestCount; +	 +public: +	// A probabilistically-correct indicator that the current +	// attempt to log metrics follows a break in the metrics stream +	// reporting due to either startup or a problem POSTing data. +	static volatile bool svMetricsDataBreak;  };  #endif // LL_LLTEXTUREFETCH_H diff --git a/indra/newview/lltoastgroupnotifypanel.cpp b/indra/newview/lltoastgroupnotifypanel.cpp index 563c27c4d7..75178a6ef8 100644 --- a/indra/newview/lltoastgroupnotifypanel.cpp +++ b/indra/newview/lltoastgroupnotifypanel.cpp @@ -77,6 +77,7 @@ LLToastGroupNotifyPanel::LLToastGroupNotifyPanel(LLNotificationPtr& notification  	from << from_name << "/" << groupData.mName;  	LLTextBox* pTitleText = getChild<LLTextBox>("title");  	pTitleText->setValue(from.str()); +	pTitleText->setToolTip(from.str());  	//message subject  	const std::string& subject = payload["subject"].asString(); diff --git a/indra/newview/lltoastscripttextbox.cpp b/indra/newview/lltoastscripttextbox.cpp index c013f521cc..2529ec865a 100644 --- a/indra/newview/lltoastscripttextbox.cpp +++ b/indra/newview/lltoastscripttextbox.cpp @@ -46,11 +46,16 @@  const S32 LLToastScriptTextbox::DEFAULT_MESSAGE_MAX_LINE_COUNT= 7; -LLToastScriptTextbox::LLToastScriptTextbox(LLNotificationPtr& notification) -:	LLToastNotifyPanel(notification) +LLToastScriptTextbox::LLToastScriptTextbox(const LLNotificationPtr& notification) +:	LLToastPanel(notification)  {  	buildFromFile( "panel_notify_textbox.xml"); +	LLTextEditor* text_editorp = getChild<LLTextEditor>("text_editor_box"); +	text_editorp->setValue(notification->getMessage()); + +	getChild<LLButton>("ignore_btn")->setClickedCallback(boost::bind(&LLToastScriptTextbox::onClickIgnore, this)); +  	const LLSD& payload = notification->getPayload();  	//message body @@ -107,3 +112,10 @@ void LLToastScriptTextbox::onClickSubmit()  		llwarns << response << llendl;  	}  } + +void LLToastScriptTextbox::onClickIgnore() +{ +	LLSD response = mNotification->getResponseTemplate(); +	mNotification->respond(response); +	close(); +} diff --git a/indra/newview/lltoastscripttextbox.h b/indra/newview/lltoastscripttextbox.h index ae3b545e0a..8e69d8834d 100644 --- a/indra/newview/lltoastscripttextbox.h +++ b/indra/newview/lltoastscripttextbox.h @@ -30,13 +30,11 @@  #include "lltoastnotifypanel.h"  #include "llnotificationptr.h" -class LLButton; -  /**   * Toast panel for scripted llTextbox notifications.   */  class LLToastScriptTextbox -:	public LLToastNotifyPanel +:	public LLToastPanel  {  public:  	void close(); @@ -46,12 +44,15 @@ public:  	// Non-transient messages.  You can specify non-default button  	// layouts (like one for script dialogs) by passing various  	// numbers in for "layout". -	LLToastScriptTextbox(LLNotificationPtr& notification); +	LLToastScriptTextbox(const LLNotificationPtr& notification);  	/*virtual*/ ~LLToastScriptTextbox(); -protected: -	void onClickSubmit(); +  private: + +	void onClickSubmit(); +	void onClickIgnore(); +  	static const S32 DEFAULT_MESSAGE_MAX_LINE_COUNT;  }; diff --git a/indra/newview/lltoolmorph.cpp b/indra/newview/lltoolmorph.cpp index ca80a1db79..964b17d3a6 100644 --- a/indra/newview/lltoolmorph.cpp +++ b/indra/newview/lltoolmorph.cpp @@ -244,13 +244,13 @@ BOOL LLVisualParamHint::render()  //-----------------------------------------------------------------------------  // draw()  //----------------------------------------------------------------------------- -void LLVisualParamHint::draw() +void LLVisualParamHint::draw(F32 alpha)  {  	if (!mIsVisible) return;  	gGL.getTexUnit(0)->bind(this); -	gGL.color4f(1.f, 1.f, 1.f, 1.f); +	gGL.color4f(1.f, 1.f, 1.f, alpha);  	LLGLSUIDefault gls_ui;  	gGL.begin(LLRender::QUADS); diff --git a/indra/newview/lltoolmorph.h b/indra/newview/lltoolmorph.h index 59201233ae..a6889be151 100644 --- a/indra/newview/lltoolmorph.h +++ b/indra/newview/lltoolmorph.h @@ -68,7 +68,7 @@ public:  	BOOL					render();  	void					requestUpdate( S32 delay_frames ) {mNeedsUpdate = TRUE; mDelayFrames = delay_frames; }  	void					setUpdateDelayFrames( S32 delay_frames ) { mDelayFrames = delay_frames; } -	void					draw(); +	void					draw(F32 alpha);  	LLViewerVisualParam*	getVisualParam() { return mVisualParam; }  	F32						getVisualParamWeight() { return mVisualParamWeight; } diff --git a/indra/newview/llviewerassetstats.cpp b/indra/newview/llviewerassetstats.cpp new file mode 100644 index 0000000000..5ad7725b3e --- /dev/null +++ b/indra/newview/llviewerassetstats.cpp @@ -0,0 +1,619 @@ +/**  + * @file llviewerassetstats.cpp + * @brief  + * + * $LicenseInfo:firstyear=2010&license=viewergpl$ + *  + * Copyright (c) 2010, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llviewerassetstats.h" +#include "llregionhandle.h" + +#include "stdtypes.h" + +/* + * Classes and utility functions for per-thread and per-region + * asset and experiential metrics to be aggregated grid-wide. + * + * The basic metrics grouping is LLViewerAssetStats::PerRegionStats. + * This provides various counters and simple statistics for asset + * fetches binned into a few categories.  One of these is maintained + * for each region encountered and the 'current' region is available + * as a simple reference.  Each thread (presently two) interested + * in participating in these stats gets an instance of the + * LLViewerAssetStats class so that threads are completely + * independent. + * + * The idea of a current region is used for simplicity and speed + * of categorization.  Each metrics event could have taken a + * region uuid argument resulting in a suitable lookup.  Arguments + * against this design include: + * + *  -  Region uuid not trivially available to caller. + *  -  Cost (cpu, disruption in real work flow) too high. + *  -  Additional precision not really meaningful. + * + * By itself, the LLViewerAssetStats class is thread- and + * viewer-agnostic and can be used anywhere without assumptions + * of global pointers and other context.  For the viewer, + * a set of free functions are provided in the namespace + * LLViewerAssetStatsFF which *do* implement viewer-native + * policies about per-thread globals and will do correct + * defensive tests of same. + * + * References + * + * Project: + *   <TBD> + * + * Test Plan: + *   <TBD> + * + * Jiras: + *   <TBD> + * + * Unit Tests: + *   indra/newview/tests/llviewerassetstats_test.cpp + * + */ + + +// ------------------------------------------------------ +// Global data definitions +// ------------------------------------------------------ +LLViewerAssetStats * gViewerAssetStatsMain(0); +LLViewerAssetStats * gViewerAssetStatsThread1(0); + + +// ------------------------------------------------------ +// Local declarations +// ------------------------------------------------------ +namespace +{ + +static LLViewerAssetStats::EViewerAssetCategories +asset_type_to_category(const LLViewerAssetType::EType at, bool with_http, bool is_temp); + +} + +// ------------------------------------------------------ +// LLViewerAssetStats::PerRegionStats struct definition +// ------------------------------------------------------ +void +LLViewerAssetStats::PerRegionStats::reset() +{ +	for (int i(0); i < LL_ARRAY_SIZE(mRequests); ++i) +	{ +		mRequests[i].mEnqueued.reset(); +		mRequests[i].mDequeued.reset(); +		mRequests[i].mResponse.reset(); +	} +	mFPS.reset(); +	 +	mTotalTime = 0; +	mStartTimestamp = LLViewerAssetStatsFF::get_timestamp(); +} + + +void +LLViewerAssetStats::PerRegionStats::merge(const LLViewerAssetStats::PerRegionStats & src) +{ +	// mRegionHandle, mTotalTime, mStartTimestamp are left alone. +	 +	// mFPS +	if (src.mFPS.getCount() && mFPS.getCount()) +	{ +		mFPS.merge(src.mFPS); +	} + +	// Requests +	for (int i = 0; i < LL_ARRAY_SIZE(mRequests); ++i) +	{ +		mRequests[i].mEnqueued.merge(src.mRequests[i].mEnqueued); +		mRequests[i].mDequeued.merge(src.mRequests[i].mDequeued); +		mRequests[i].mResponse.merge(src.mRequests[i].mResponse); +	} +} + + +void +LLViewerAssetStats::PerRegionStats::accumulateTime(duration_t now) +{ +	mTotalTime += (now - mStartTimestamp); +	mStartTimestamp = now; +} + + +// ------------------------------------------------------ +// LLViewerAssetStats class definition +// ------------------------------------------------------ +LLViewerAssetStats::LLViewerAssetStats() +	: mRegionHandle(U64(0)) +{ +	reset(); +} + + +LLViewerAssetStats::LLViewerAssetStats(const LLViewerAssetStats & src) +	: mRegionHandle(src.mRegionHandle), +	  mResetTimestamp(src.mResetTimestamp) +{ +	const PerRegionContainer::const_iterator it_end(src.mRegionStats.end()); +	for (PerRegionContainer::const_iterator it(src.mRegionStats.begin()); it_end != it; ++it) +	{ +		mRegionStats[it->first] = new PerRegionStats(*it->second); +	} +	mCurRegionStats = mRegionStats[mRegionHandle]; +} + + +void +LLViewerAssetStats::reset() +{ +	// Empty the map of all region stats +	mRegionStats.clear(); + +	// If we have a current stats, reset it, otherwise, as at construction, +	// create a new one as we must always have a current stats block. +	if (mCurRegionStats) +	{ +		mCurRegionStats->reset(); +	} +	else +	{ +		mCurRegionStats = new PerRegionStats(mRegionHandle); +	} + +	// And add reference to map +	mRegionStats[mRegionHandle] = mCurRegionStats; + +	// Start timestamp consistent with per-region collector +	mResetTimestamp = mCurRegionStats->mStartTimestamp; +} + + +void +LLViewerAssetStats::setRegion(region_handle_t region_handle) +{ +	if (region_handle == mRegionHandle) +	{ +		// Already active, ignore. +		return; +	} + +	// Get duration for current set +	const duration_t now = LLViewerAssetStatsFF::get_timestamp(); +	mCurRegionStats->accumulateTime(now); + +	// Prepare new set +	PerRegionContainer::iterator new_stats = mRegionStats.find(region_handle); +	if (mRegionStats.end() == new_stats) +	{ +		// Haven't seen this region_id before, create a new block and make it current. +		mCurRegionStats = new PerRegionStats(region_handle); +		mRegionStats[region_handle] = mCurRegionStats; +	} +	else +	{ +		mCurRegionStats = new_stats->second; +	} +	mCurRegionStats->mStartTimestamp = now; +	mRegionHandle = region_handle; +} + + +void +LLViewerAssetStats::recordGetEnqueued(LLViewerAssetType::EType at, bool with_http, bool is_temp) +{ +	const EViewerAssetCategories eac(asset_type_to_category(at, with_http, is_temp)); +	 +	++(mCurRegionStats->mRequests[int(eac)].mEnqueued); +} +	 +void +LLViewerAssetStats::recordGetDequeued(LLViewerAssetType::EType at, bool with_http, bool is_temp) +{ +	const EViewerAssetCategories eac(asset_type_to_category(at, with_http, is_temp)); + +	++(mCurRegionStats->mRequests[int(eac)].mDequeued); +} + +void +LLViewerAssetStats::recordGetServiced(LLViewerAssetType::EType at, bool with_http, bool is_temp, duration_t duration) +{ +	const EViewerAssetCategories eac(asset_type_to_category(at, with_http, is_temp)); + +	mCurRegionStats->mRequests[int(eac)].mResponse.record(duration); +} + +void +LLViewerAssetStats::recordFPS(F32 fps) +{ +	mCurRegionStats->mFPS.record(fps); +} + +LLSD +LLViewerAssetStats::asLLSD(bool compact_output) +{ +	// Top-level tags +	static const LLSD::String tags[EVACCount] =  +		{ +			LLSD::String("get_texture_temp_http"), +			LLSD::String("get_texture_temp_udp"), +			LLSD::String("get_texture_non_temp_http"), +			LLSD::String("get_texture_non_temp_udp"), +			LLSD::String("get_wearable_udp"), +			LLSD::String("get_sound_udp"), +			LLSD::String("get_gesture_udp"), +			LLSD::String("get_other") +		}; + +	// Stats Group Sub-tags. +	static const LLSD::String enq_tag("enqueued"); +	static const LLSD::String deq_tag("dequeued"); +	static const LLSD::String rcnt_tag("resp_count"); +	static const LLSD::String rmin_tag("resp_min"); +	static const LLSD::String rmax_tag("resp_max"); +	static const LLSD::String rmean_tag("resp_mean"); + +	// MMM Group Sub-tags. +	static const LLSD::String cnt_tag("count"); +	static const LLSD::String min_tag("min"); +	static const LLSD::String max_tag("max"); +	static const LLSD::String mean_tag("mean"); + +	const duration_t now = LLViewerAssetStatsFF::get_timestamp(); +	mCurRegionStats->accumulateTime(now); + +	LLSD regions = LLSD::emptyArray(); +	for (PerRegionContainer::iterator it = mRegionStats.begin(); +		 mRegionStats.end() != it; +		 ++it) +	{ +		if (0 == it->first) +		{ +			// Never emit NULL UUID/handle in results. +			continue; +		} + +		PerRegionStats & stats = *it->second; +		 +		LLSD reg_stat = LLSD::emptyMap(); +		 +		for (int i = 0; i < LL_ARRAY_SIZE(tags); ++i) +		{ +			PerRegionStats::prs_group & group(stats.mRequests[i]); +			 +			if ((! compact_output) || +				group.mEnqueued.getCount() || +				group.mDequeued.getCount() || +				group.mResponse.getCount()) +			{ +				LLSD & slot = reg_stat[tags[i]]; +				slot = LLSD::emptyMap(); +				slot[enq_tag] = LLSD(S32(stats.mRequests[i].mEnqueued.getCount())); +				slot[deq_tag] = LLSD(S32(stats.mRequests[i].mDequeued.getCount())); +				slot[rcnt_tag] = LLSD(S32(stats.mRequests[i].mResponse.getCount())); +				slot[rmin_tag] = LLSD(F64(stats.mRequests[i].mResponse.getMin() * 1.0e-6)); +				slot[rmax_tag] = LLSD(F64(stats.mRequests[i].mResponse.getMax() * 1.0e-6)); +				slot[rmean_tag] = LLSD(F64(stats.mRequests[i].mResponse.getMean() * 1.0e-6)); +			} +		} + +		if ((! compact_output) || stats.mFPS.getCount()) +		{ +			LLSD & slot = reg_stat["fps"]; +			slot = LLSD::emptyMap(); +			slot[cnt_tag] = LLSD(S32(stats.mFPS.getCount())); +			slot[min_tag] = LLSD(F64(stats.mFPS.getMin())); +			slot[max_tag] = LLSD(F64(stats.mFPS.getMax())); +			slot[mean_tag] = LLSD(F64(stats.mFPS.getMean())); +		} + +		U32 grid_x(0), grid_y(0); +		grid_from_region_handle(it->first, &grid_x, &grid_y); +		reg_stat["grid_x"] = LLSD::Integer(grid_x); +		reg_stat["grid_y"] = LLSD::Integer(grid_y); +		reg_stat["duration"] = LLSD::Real(stats.mTotalTime * 1.0e-6);		 +		regions.append(reg_stat); +	} + +	LLSD ret = LLSD::emptyMap(); +	ret["regions"] = regions; +	ret["duration"] = LLSD::Real((now - mResetTimestamp) * 1.0e-6); +	 +	return ret; +} + +void +LLViewerAssetStats::merge(const LLViewerAssetStats & src) +{ +	// mRegionHandle, mCurRegionStats and mResetTimestamp are left untouched. +	// Just merge the stats bodies + +	const PerRegionContainer::const_iterator it_end(src.mRegionStats.end()); +	for (PerRegionContainer::const_iterator it(src.mRegionStats.begin()); it_end != it; ++it) +	{ +		PerRegionContainer::iterator dst(mRegionStats.find(it->first)); +		if (mRegionStats.end() == dst) +		{ +			// Destination is missing data, just make a private copy +			mRegionStats[it->first] = new PerRegionStats(*it->second); +		} +		else +		{ +			dst->second->merge(*it->second); +		} +	} +} + + +// ------------------------------------------------------ +// Global free-function definitions (LLViewerAssetStatsFF namespace) +// ------------------------------------------------------ + +namespace LLViewerAssetStatsFF +{ + +// +// Target thread is elaborated in the function name.  This could +// have been something 'templatey' like specializations iterated +// over a set of constants but with so few, this is clearer I think. +// +// As for the threads themselves... rather than do fine-grained +// locking as we gather statistics, this code creates a collector +// for each thread, allocated and run independently.  Logging +// happens at relatively infrequent intervals and at that time +// the data is sent to a single thread to be aggregated into +// a single entity with locks, thread safety and other niceties. +// +// A particularly fussy implementation would distribute the +// per-thread pointers across separate cache lines.  But that should +// be beyond current requirements. +// + +// 'main' thread - initial program thread + +void +set_region_main(LLViewerAssetStats::region_handle_t region_handle) +{ +	if (! gViewerAssetStatsMain) +		return; + +	gViewerAssetStatsMain->setRegion(region_handle); +} + +void +record_enqueue_main(LLViewerAssetType::EType at, bool with_http, bool is_temp) +{ +	if (! gViewerAssetStatsMain) +		return; + +	gViewerAssetStatsMain->recordGetEnqueued(at, with_http, is_temp); +} + +void +record_dequeue_main(LLViewerAssetType::EType at, bool with_http, bool is_temp) +{ +	if (! gViewerAssetStatsMain) +		return; + +	gViewerAssetStatsMain->recordGetDequeued(at, with_http, is_temp); +} + +void +record_response_main(LLViewerAssetType::EType at, bool with_http, bool is_temp, LLViewerAssetStats::duration_t duration) +{ +	if (! gViewerAssetStatsMain) +		return; + +	gViewerAssetStatsMain->recordGetServiced(at, with_http, is_temp, duration); +} + +void +record_fps_main(F32 fps) +{ +	if (! gViewerAssetStatsMain) +		return; + +	gViewerAssetStatsMain->recordFPS(fps); +} + + +// 'thread1' - should be for TextureFetch thread + +void +set_region_thread1(LLViewerAssetStats::region_handle_t region_handle) +{ +	if (! gViewerAssetStatsThread1) +		return; + +	gViewerAssetStatsThread1->setRegion(region_handle); +} + +void +record_enqueue_thread1(LLViewerAssetType::EType at, bool with_http, bool is_temp) +{ +	if (! gViewerAssetStatsThread1) +		return; + +	gViewerAssetStatsThread1->recordGetEnqueued(at, with_http, is_temp); +} + +void +record_dequeue_thread1(LLViewerAssetType::EType at, bool with_http, bool is_temp) +{ +	if (! gViewerAssetStatsThread1) +		return; + +	gViewerAssetStatsThread1->recordGetDequeued(at, with_http, is_temp); +} + +void +record_response_thread1(LLViewerAssetType::EType at, bool with_http, bool is_temp, LLViewerAssetStats::duration_t duration) +{ +	if (! gViewerAssetStatsThread1) +		return; + +	gViewerAssetStatsThread1->recordGetServiced(at, with_http, is_temp, duration); +} + + +void +init() +{ +	if (! gViewerAssetStatsMain) +	{ +		gViewerAssetStatsMain = new LLViewerAssetStats(); +	} +	if (! gViewerAssetStatsThread1) +	{ +		gViewerAssetStatsThread1 = new LLViewerAssetStats(); +	} +} + +void +cleanup() +{ +	delete gViewerAssetStatsMain; +	gViewerAssetStatsMain = 0; + +	delete gViewerAssetStatsThread1; +	gViewerAssetStatsThread1 = 0; +} + + +} // namespace LLViewerAssetStatsFF + + +// ------------------------------------------------------ +// Local function definitions +// ------------------------------------------------------ + +namespace +{ + +LLViewerAssetStats::EViewerAssetCategories +asset_type_to_category(const LLViewerAssetType::EType at, bool with_http, bool is_temp) +{ +	// For statistical purposes, we divide GETs into several +	// populations of asset fetches: +	//  - textures which are de-prioritized in the asset system +	//  - wearables (clothing, bodyparts) which directly affect +	//    user experiences when they log in +	//  - sounds +	//  - gestures +	//  - everything else. +	// +	llassert_always(26 == LLViewerAssetType::AT_COUNT); + +	// Multiple asset definitions are floating around so this requires some +	// maintenance and attention. +	static const LLViewerAssetStats::EViewerAssetCategories asset_to_bin_map[LLViewerAssetType::AT_COUNT] = +		{ +			LLViewerAssetStats::EVACTextureTempHTTPGet,			// (0) AT_TEXTURE +			LLViewerAssetStats::EVACSoundUDPGet,				// AT_SOUND +			LLViewerAssetStats::EVACOtherGet,					// AT_CALLINGCARD +			LLViewerAssetStats::EVACOtherGet,					// AT_LANDMARK +			LLViewerAssetStats::EVACOtherGet,					// AT_SCRIPT +			LLViewerAssetStats::EVACWearableUDPGet,				// AT_CLOTHING +			LLViewerAssetStats::EVACOtherGet,					// AT_OBJECT +			LLViewerAssetStats::EVACOtherGet,					// AT_NOTECARD +			LLViewerAssetStats::EVACOtherGet,					// AT_CATEGORY +			LLViewerAssetStats::EVACOtherGet,					// AT_ROOT_CATEGORY +			LLViewerAssetStats::EVACOtherGet,					// (10) AT_LSL_TEXT +			LLViewerAssetStats::EVACOtherGet,					// AT_LSL_BYTECODE +			LLViewerAssetStats::EVACOtherGet,					// AT_TEXTURE_TGA +			LLViewerAssetStats::EVACWearableUDPGet,				// AT_BODYPART +			LLViewerAssetStats::EVACOtherGet,					// AT_TRASH +			LLViewerAssetStats::EVACOtherGet,					// AT_SNAPSHOT_CATEGORY +			LLViewerAssetStats::EVACOtherGet,					// AT_LOST_AND_FOUND +			LLViewerAssetStats::EVACSoundUDPGet,				// AT_SOUND_WAV +			LLViewerAssetStats::EVACOtherGet,					// AT_IMAGE_TGA +			LLViewerAssetStats::EVACOtherGet,					// AT_IMAGE_JPEG +			LLViewerAssetStats::EVACGestureUDPGet,				// (20) AT_ANIMATION +			LLViewerAssetStats::EVACGestureUDPGet,				// AT_GESTURE +			LLViewerAssetStats::EVACOtherGet,					// AT_SIMSTATE +			LLViewerAssetStats::EVACOtherGet,					// AT_FAVORITE +			LLViewerAssetStats::EVACOtherGet,					// AT_LINK +			LLViewerAssetStats::EVACOtherGet,					// AT_LINK_FOLDER +#if 0 +			// When LLViewerAssetType::AT_COUNT == 49 +			LLViewerAssetStats::EVACOtherGet,					// AT_FOLDER_ENSEMBLE_START +			LLViewerAssetStats::EVACOtherGet,					//  +			LLViewerAssetStats::EVACOtherGet,					//  +			LLViewerAssetStats::EVACOtherGet,					//  +			LLViewerAssetStats::EVACOtherGet,					// (30) +			LLViewerAssetStats::EVACOtherGet,					//  +			LLViewerAssetStats::EVACOtherGet,					//  +			LLViewerAssetStats::EVACOtherGet,					//  +			LLViewerAssetStats::EVACOtherGet,					//  +			LLViewerAssetStats::EVACOtherGet,					//  +			LLViewerAssetStats::EVACOtherGet,					//  +			LLViewerAssetStats::EVACOtherGet,					//  +			LLViewerAssetStats::EVACOtherGet,					//  +			LLViewerAssetStats::EVACOtherGet,					//  +			LLViewerAssetStats::EVACOtherGet,					// (40) +			LLViewerAssetStats::EVACOtherGet,					//  +			LLViewerAssetStats::EVACOtherGet,					//  +			LLViewerAssetStats::EVACOtherGet,					//  +			LLViewerAssetStats::EVACOtherGet,					//  +			LLViewerAssetStats::EVACOtherGet,					// AT_FOLDER_ENSEMBLE_END +			LLViewerAssetStats::EVACOtherGet,					// AT_CURRENT_OUTFIT +			LLViewerAssetStats::EVACOtherGet,					// AT_OUTFIT +			LLViewerAssetStats::EVACOtherGet					// AT_MY_OUTFITS +#endif +		}; +	 +	if (at < 0 || at >= LLViewerAssetType::AT_COUNT) +	{ +		return LLViewerAssetStats::EVACOtherGet; +	} +	LLViewerAssetStats::EViewerAssetCategories ret(asset_to_bin_map[at]); +	if (LLViewerAssetStats::EVACTextureTempHTTPGet == ret) +	{ +		// Indexed with [is_temp][with_http] +		static const LLViewerAssetStats::EViewerAssetCategories texture_bin_map[2][2] = +			{ +				{ +					LLViewerAssetStats::EVACTextureNonTempUDPGet, +					LLViewerAssetStats::EVACTextureNonTempHTTPGet, +				}, +				{ +					LLViewerAssetStats::EVACTextureTempUDPGet, +					LLViewerAssetStats::EVACTextureTempHTTPGet, +				} +			}; + +		ret = texture_bin_map[is_temp][with_http]; +	} +	return ret; +} + +} // anonymous namespace diff --git a/indra/newview/llviewerassetstats.h b/indra/newview/llviewerassetstats.h new file mode 100644 index 0000000000..905ceefad5 --- /dev/null +++ b/indra/newview/llviewerassetstats.h @@ -0,0 +1,334 @@ +/**  + * @file llviewerassetstats.h + * @brief Client-side collection of asset request statistics + * + * $LicenseInfo:firstyear=2010&license=viewergpl$ + *  + * Copyright (c) 2010, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLVIEWERASSETSTATUS_H +#define	LL_LLVIEWERASSETSTATUS_H + + +#include "linden_common.h" + +#include "llpointer.h" +#include "llrefcount.h" +#include "llviewerassettype.h" +#include "llviewerassetstorage.h" +#include "llsimplestat.h" +#include "llsd.h" + +/** + * @class LLViewerAssetStats + * @brief Records performance aspects of asset access operations. + * + * This facility is derived from a very similar simulator-based + * one, LLSimAssetStats.  It's function is to count asset access + * operations and characterize response times.  Collected data + * are binned in several dimensions: + * + *  - Asset types collapsed into a few aggregated categories + *  - By simulator UUID + *  - By transport mechanism (HTTP vs MessageSystem) + *  - By persistence (temp vs non-temp) + * + * Statistics collected are fairly basic at this point: + * + *  - Counts of enqueue and dequeue operations + *  - Min/Max/Mean of asset transfer operations + * + * This collector differs from the simulator-based on in a + * number of ways: + * + *  - The front-end/back-end distinction doesn't exist in viewer + *    code + *  - Multiple threads must be safely accomodated in the viewer + * + * Access to results is by conversion to an LLSD with some standardized + * key names.  The intent of this structure is that it be emitted as + * standard syslog-based metrics formatting where it can be picked + * up by interested parties. + * + * For convenience, a set of free functions in namespace + * LLViewerAssetStatsFF is provided for conditional test-and-call + * operations. + */ +class LLViewerAssetStats +{ +public: +	enum EViewerAssetCategories +	{ +		EVACTextureTempHTTPGet,			//< Texture GETs - temp/baked, HTTP +		EVACTextureTempUDPGet,			//< Texture GETs - temp/baked, UDP +		EVACTextureNonTempHTTPGet,		//< Texture GETs - perm, HTTP +		EVACTextureNonTempUDPGet,		//< Texture GETs - perm, UDP +		EVACWearableUDPGet,				//< Wearable GETs +		EVACSoundUDPGet,				//< Sound GETs +		EVACGestureUDPGet,				//< Gesture GETs +		EVACOtherGet,					//< Other GETs +		 +		EVACCount						// Must be last +	}; + +	/** +	 * Type for duration and other time values in the metrics.  Selected +	 * for compatibility with the pre-existing timestamp on the texture +	 * fetcher class, LLTextureFetch. +	 */ +	typedef U64 duration_t; + +	/** +	 * Type for the region identifier used in stats.  Currently uses +	 * the region handle's type (a U64) rather than the regions's LLUUID +	 * as the latter isn't available immediately. +	 */ +	typedef U64 region_handle_t; + +	/** +	 * @brief Collected data for a single region visited by the avatar. +	 * +	 * Fairly simple, for each asset bin enumerated above a count +	 * of enqueue and dequeue operations and simple stats on response +	 * times for completed requests. +	 */ +	class PerRegionStats : public LLRefCount +	{ +	public: +		PerRegionStats(const region_handle_t region_handle) +			: LLRefCount(), +			  mRegionHandle(region_handle) +			{ +				reset(); +			} + +		PerRegionStats(const PerRegionStats & src) +			: LLRefCount(), +			  mRegionHandle(src.mRegionHandle), +			  mTotalTime(src.mTotalTime), +			  mStartTimestamp(src.mStartTimestamp), +			  mFPS(src.mFPS) +			{ +				for (int i = 0; i < LL_ARRAY_SIZE(mRequests); ++i) +				{ +					mRequests[i] = src.mRequests[i]; +				} +			} + +		// Default assignment and destructor are correct. +		 +		void reset(); + +		void merge(const PerRegionStats & src); +		 +		// Apply current running time to total and reset start point. +		// Return current timestamp as a convenience. +		void accumulateTime(duration_t now); +		 +	public: +		region_handle_t		mRegionHandle; +		duration_t			mTotalTime; +		duration_t			mStartTimestamp; +		LLSimpleStatMMM<>	mFPS; +		 +		struct prs_group +		{ +			LLSimpleStatCounter			mEnqueued; +			LLSimpleStatCounter			mDequeued; +			LLSimpleStatMMM<duration_t>	mResponse; +		} +		mRequests [EVACCount]; +	}; + +public: +	LLViewerAssetStats(); +	LLViewerAssetStats(const LLViewerAssetStats &); +	// Default destructor is correct. +	LLViewerAssetStats & operator=(const LLViewerAssetStats &);			// Not defined + +	// Clear all metrics data.  This leaves the currently-active region +	// in place but with zero'd data for all metrics.  All other regions +	// are removed from the collection map. +	void reset(); + +	// Set hidden region argument and establish context for subsequent +	// collection calls. +	void setRegion(region_handle_t region_handle); + +	// Asset GET Requests +	void recordGetEnqueued(LLViewerAssetType::EType at, bool with_http, bool is_temp); +	void recordGetDequeued(LLViewerAssetType::EType at, bool with_http, bool is_temp); +	void recordGetServiced(LLViewerAssetType::EType at, bool with_http, bool is_temp, duration_t duration); + +	// Frames-Per-Second Samples +	void recordFPS(F32 fps); + +	// Merge a source instance into a destination instance.  This is +	// conceptually an 'operator+=()' method: +	// - counts are added +	// - minimums are min'd +	// - maximums are max'd +	// - other scalars are ignored ('this' wins) +	// +	void merge(const LLViewerAssetStats & src); +	 +	// Retrieve current metrics for all visited regions (NULL region UUID/handle excluded) +    // Returned LLSD is structured as follows: +	// +	// &stats_group = { +	//   enqueued   : int, +	//   dequeued   : int, +	//   resp_count : int, +	//   resp_min   : float, +	//   resp_max   : float, +	//   resp_mean  : float +	// } +	// +	// &mmm_group = { +	//   count : int, +	//   min   : float, +	//   max   : float, +	//   mean  : float +	// } +	// +	// { +	//   duration: int +	//   regions: { +	//     $: {			// Keys are strings of the region's handle in hex +	//       duration:                 : int, +	//		 fps:					   : &mmm_group, +	//       get_texture_temp_http     : &stats_group, +	//       get_texture_temp_udp      : &stats_group, +	//       get_texture_non_temp_http : &stats_group, +	//       get_texture_non_temp_udp  : &stats_group, +	//       get_wearable_udp          : &stats_group, +	//       get_sound_udp             : &stats_group, +	//       get_gesture_udp           : &stats_group, +	//       get_other                 : &stats_group +	//     } +	//   } +	// } +	// +	// @param	compact_output		If true, omits from conversion any mmm_block +	//								or stats_block that would contain all zero data. +	//								Useful for transmission when the receiver knows +	//								what is expected and will assume zero for missing +	//								blocks. +	LLSD asLLSD(bool compact_output); + +protected: +	typedef std::map<region_handle_t, LLPointer<PerRegionStats> > PerRegionContainer; + +	// Region of the currently-active region.  Always valid but may +	// be zero after construction or when explicitly set.  Unchanged +	// by a reset() call. +	region_handle_t mRegionHandle; + +	// Pointer to metrics collection for currently-active region.  Always +	// valid and unchanged after reset() though contents will be changed. +	// Always points to a collection contained in mRegionStats. +	LLPointer<PerRegionStats> mCurRegionStats; + +	// Metrics data for all regions during one collection cycle +	PerRegionContainer mRegionStats; + +	// Time of last reset +	duration_t mResetTimestamp; +}; + + +/** + * Global stats collectors one for each independent thread where + * assets and other statistics are gathered.  The globals are + * expected to be created at startup time and then picked up by + * their respective threads afterwards.  A set of free functions + * are provided to access methods behind the globals while both + * minimally disrupting visual flow and supplying a description + * of intent. + * + * Expected thread assignments: + * + *  - Main:  main() program execution thread + *  - Thread1:  TextureFetch worker thread + */ +extern LLViewerAssetStats * gViewerAssetStatsMain; + +extern LLViewerAssetStats * gViewerAssetStatsThread1; + +namespace LLViewerAssetStatsFF +{ +/** + * @brief Allocation and deallocation of globals. + * + * init() should be called before threads are started that will access it though + * you'll likely get away with calling it afterwards.  cleanup() should only be + * called after threads are shutdown to prevent races on the global pointers. + */ +void init(); + +void cleanup(); + +/** + * We have many timers, clocks etc. in the runtime.  This is the + * canonical timestamp for these metrics which is compatible with + * the pre-existing timestamping in the texture fetcher. + */ +inline LLViewerAssetStats::duration_t get_timestamp() +{ +	return LLTimer::getTotalTime(); +} + +/** + * Region context, event and duration loggers for the Main thread. + */ +void set_region_main(LLViewerAssetStats::region_handle_t region_handle); + +void record_enqueue_main(LLViewerAssetType::EType at, bool with_http, bool is_temp); + +void record_dequeue_main(LLViewerAssetType::EType at, bool with_http, bool is_temp); + +void record_response_main(LLViewerAssetType::EType at, bool with_http, bool is_temp, +						  LLViewerAssetStats::duration_t duration); + +void record_fps_main(F32 fps); + + +/** + * Region context, event and duration loggers for Thread 1. + */ +void set_region_thread1(LLViewerAssetStats::region_handle_t region_handle); + +void record_enqueue_thread1(LLViewerAssetType::EType at, bool with_http, bool is_temp); + +void record_dequeue_thread1(LLViewerAssetType::EType at, bool with_http, bool is_temp); + +void record_response_thread1(LLViewerAssetType::EType at, bool with_http, bool is_temp, +						  LLViewerAssetStats::duration_t duration); + +} // namespace LLViewerAssetStatsFF + +#endif // LL_LLVIEWERASSETSTATUS_H diff --git a/indra/newview/llviewerassetstorage.cpp b/indra/newview/llviewerassetstorage.cpp index 2e7ef0fec3..36c8b42a52 100644 --- a/indra/newview/llviewerassetstorage.cpp +++ b/indra/newview/llviewerassetstorage.cpp @@ -33,6 +33,61 @@  #include "message.h"  #include "llagent.h" +#include "lltransfersourceasset.h" +#include "lltransfertargetvfile.h" +#include "llviewerassetstats.h" + +///---------------------------------------------------------------------------- +/// LLViewerAssetRequest +///---------------------------------------------------------------------------- + +/** + * @brief Local class to encapsulate asset fetch requests with a timestamp. + * + * Derived from the common LLAssetRequest class, this is currently used + * only for fetch/get operations and its only function is to wrap remote + * asset fetch requests so that they can be timed. + */ +class LLViewerAssetRequest : public LLAssetRequest +{ +public: +	LLViewerAssetRequest(const LLUUID &uuid, const LLAssetType::EType type) +		: LLAssetRequest(uuid, type), +		  mMetricsStartTime(0) +		{ +		} +	 +	LLViewerAssetRequest & operator=(const LLViewerAssetRequest &);	// Not defined +	// Default assignment operator valid +	 +	// virtual +	~LLViewerAssetRequest() +		{ +			recordMetrics(); +		} + +protected: +	void recordMetrics() +		{ +			if (mMetricsStartTime) +			{ +				// Okay, it appears this request was used for useful things.  Record +				// the expected dequeue and duration of request processing. +				LLViewerAssetStatsFF::record_dequeue_main(mType, false, false); +				LLViewerAssetStatsFF::record_response_main(mType, false, false, +														   (LLViewerAssetStatsFF::get_timestamp() +															- mMetricsStartTime)); +				mMetricsStartTime = 0; +			} +		} +	 +public: +	LLViewerAssetStats::duration_t		mMetricsStartTime; +}; + +///---------------------------------------------------------------------------- +/// LLViewerAssetStorage +///----------------------------------------------------------------------------  LLViewerAssetStorage::LLViewerAssetStorage(LLMessageSystem *msg, LLXferManager *xfer,  										   LLVFS *vfs, LLVFS *static_vfs,  @@ -258,3 +313,77 @@ void LLViewerAssetStorage::storeAssetData(  		}  	}  } + + +/** + * @brief Allocate and queue an asset fetch request for the viewer + * + * This is a nearly-verbatim copy of the base class's implementation + * with the following changes: + *  -  Use a locally-derived request class + *  -  Start timing for metrics when request is queued + * + * This is an unfortunate implementation choice but it's forced by + * current conditions.  A refactoring that might clean up the layers + * of responsibility or introduce factories or more virtualization + * of methods would enable a more attractive solution. + * + * If LLAssetStorage::_queueDataRequest changes, this must change + * as well. + */ + +// virtual +void LLViewerAssetStorage::_queueDataRequest( +	const LLUUID& uuid, +	LLAssetType::EType atype, +	LLGetAssetCallback callback, +	void *user_data, +	BOOL duplicate, +	BOOL is_priority) +{ +	if (mUpstreamHost.isOk()) +	{ +		// stash the callback info so we can find it after we get the response message +		LLViewerAssetRequest *req = new LLViewerAssetRequest(uuid, atype); +		req->mDownCallback = callback; +		req->mUserData = user_data; +		req->mIsPriority = is_priority; +		if (!duplicate) +		{ +			// Only collect metrics for non-duplicate requests.  Others  +			// are piggy-backing and will artificially lower averages. +			req->mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp(); +		} +		 +		mPendingDownloads.push_back(req); +	 +		if (!duplicate) +		{ +			// send request message to our upstream data provider +			// Create a new asset transfer. +			LLTransferSourceParamsAsset spa; +			spa.setAsset(uuid, atype); + +			// Set our destination file, and the completion callback. +			LLTransferTargetParamsVFile tpvf; +			tpvf.setAsset(uuid, atype); +			tpvf.setCallback(downloadCompleteCallback, req); + +			llinfos << "Starting transfer for " << uuid << llendl; +			LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(mUpstreamHost, LLTCT_ASSET); +			ttcp->requestTransfer(spa, tpvf, 100.f + (is_priority ? 1.f : 0.f)); + +			LLViewerAssetStatsFF::record_enqueue_main(atype, false, false); +		} +	} +	else +	{ +		// uh-oh, we shouldn't have gotten here +		llwarns << "Attempt to move asset data request upstream w/o valid upstream provider" << llendl; +		if (callback) +		{ +			callback(mVFS, uuid, atype, user_data, LL_ERR_CIRCUIT_GONE, LL_EXSTAT_NO_UPSTREAM); +		} +	} +} + diff --git a/indra/newview/llviewerassetstorage.h b/indra/newview/llviewerassetstorage.h index 6346b79f03..ca9b9943fa 100644 --- a/indra/newview/llviewerassetstorage.h +++ b/indra/newview/llviewerassetstorage.h @@ -63,6 +63,17 @@ public:  		bool is_priority = false,  		bool user_waiting=FALSE,  		F64 timeout=LL_ASSET_STORAGE_TIMEOUT); + +protected: +	using LLAssetStorage::_queueDataRequest; + +	// virtual +	void _queueDataRequest(const LLUUID& uuid, +						   LLAssetType::EType type, +						   void (*callback) (LLVFS *vfs, const LLUUID&, LLAssetType::EType, void *, S32, LLExtStat), +						   void *user_data, +						   BOOL duplicate, +						   BOOL is_priority);  };  #endif diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index 622d09c600..8c5a52c187 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -504,9 +504,10 @@ bool toggle_show_object_render_cost(const LLSD& newvalue)  void toggle_updater_service_active(LLControlVariable* control, const LLSD& new_value)  { -    if(new_value.asBoolean()) +    if(new_value.asInteger())      { -        LLUpdaterService().startChecking(); +		LLUpdaterService update_service; +		if(!update_service.isChecking()) update_service.startChecking();      }      else      { @@ -661,7 +662,7 @@ void settings_setup_listeners()  	gSavedSettings.getControl("ShowNavbarFavoritesPanel")->getSignal()->connect(boost::bind(&toggle_show_favorites_panel, _2));  	gSavedSettings.getControl("ShowMiniLocationPanel")->getSignal()->connect(boost::bind(&toggle_show_mini_location_panel, _2));  	gSavedSettings.getControl("ShowObjectRenderingCost")->getSignal()->connect(boost::bind(&toggle_show_object_render_cost, _2)); -	gSavedSettings.getControl("UpdaterServiceActive")->getSignal()->connect(&toggle_updater_service_active); +	gSavedSettings.getControl("UpdaterServiceSetting")->getSignal()->connect(&toggle_updater_service_active);  	gSavedSettings.getControl("ForceShowGrid")->getSignal()->connect(boost::bind(&handleForceShowGrid, _2));  	gSavedSettings.getControl("RenderTransparentWater")->getSignal()->connect(boost::bind(&handleRenderTransparentWaterChanged, _2));  } diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index f573f25efe..dca1e33e60 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -60,6 +60,7 @@  #include "llfloaterhardwaresettings.h"  #include "llfloaterhelpbrowser.h"  #include "llfloatermediabrowser.h" +#include "llfloaterwebcontent.h"  #include "llfloatermediasettings.h"  #include "llfloaterhud.h"  #include "llfloaterimagepreview.h" @@ -252,6 +253,7 @@ void LLViewerFloaterReg::registerFloaters()  	LLFloaterReg::add("voice_controls", "floater_voice_controls.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLCallFloater>);  	LLFloaterReg::add("voice_effect", "floater_voice_effect.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterVoiceEffect>); +	LLFloaterReg::add("web_content", "floater_web_content.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterWebContent>);	  	LLFloaterReg::add("whitelist_entry", "floater_whitelist_entry.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterWhiteListEntry>);	  	LLFloaterWindowSizeUtil::registerFloater();  	LLFloaterReg::add("world_map", "floater_world_map.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterWorldMap>);	 diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index fae4eb3c05..d3b6dcd86f 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -52,6 +52,7 @@  #include "llviewerregion.h"  #include "llwebsharing.h"	// For LLWebSharing::setOpenIDCookie(), *TODO: find a better way to do this!  #include "llfilepicker.h" +#include "llnotifications.h"  #include "llevent.h"		// LLSimpleListener  #include "llnotificationsutil.h" @@ -62,6 +63,7 @@  #include "llwindow.h"  #include "llfloatermediabrowser.h"	// for handling window close requests and geometry change requests in media browser windows. +#include "llfloaterwebcontent.h"	// for handling window close requests and geometry change requests in media browser windows.  #include <boost/bind.hpp>	// for SkinFolder listener  #include <boost/signals2.hpp> @@ -293,6 +295,7 @@ public:  LLPluginCookieStore *LLViewerMedia::sCookieStore = NULL;  LLURL LLViewerMedia::sOpenIDURL;  std::string LLViewerMedia::sOpenIDCookie; +LLPluginClassMedia* LLViewerMedia::sSpareBrowserMediaSource = NULL;  static LLViewerMedia::impl_list sViewerMediaImplList;  static LLViewerMedia::impl_id_map sViewerMediaTextureIDMap;  static LLTimer sMediaCreateTimer; @@ -742,6 +745,9 @@ void LLViewerMedia::updateMedia(void *dummy_arg)  	// Enable/disable the plugin read thread  	LLPluginProcessParent::setUseReadThread(gSavedSettings.getBOOL("PluginUseReadThread")); +	// HACK: we always try to keep a spare running webkit plugin around to improve launch times. +	createSpareBrowserMediaSource(); +	  	sAnyMediaShowing = false;  	sUpdatedCookies = getCookieStore()->getChangedCookies();  	if(!sUpdatedCookies.empty()) @@ -759,6 +765,12 @@ void LLViewerMedia::updateMedia(void *dummy_arg)  		pimpl->update();  		pimpl->calculateInterest();  	} +	 +	// Let the spare media source actually launch +	if(sSpareBrowserMediaSource) +	{ +		sSpareBrowserMediaSource->idle(); +	}  	// Sort the static instance list using our interest criteria  	sViewerMediaImplList.sort(priorityComparitor); @@ -1034,6 +1046,26 @@ bool LLViewerMedia::isParcelAudioPlaying()  	return (LLViewerMedia::hasParcelAudio() && gAudiop && LLAudioEngine::AUDIO_PLAYING == gAudiop->isInternetStreamPlaying());  } +void LLViewerMedia::onAuthSubmit(const LLSD& notification, const LLSD& response) +{ +	LLViewerMediaImpl *impl = LLViewerMedia::getMediaImplFromTextureID(notification["payload"]["media_id"]); +	if(impl) +	{ +		LLPluginClassMedia* media = impl->getMediaPlugin(); +		if(media) +		{ +			if (response["ok"]) +			{ +				media->sendAuthResponse(true, response["username"], response["password"]); +			} +			else +			{ +				media->sendAuthResponse(false, "", ""); +			} +		} +	} +} +  /////////////////////////////////////////////////////////////////////////////////////////  // static  void LLViewerMedia::clearAllCookies() @@ -1400,6 +1432,29 @@ void LLViewerMedia::proxyWindowClosed(const std::string &uuid)  	}  } +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::createSpareBrowserMediaSource() +{ +	if(!sSpareBrowserMediaSource) +	{ +		// If we don't have a spare browser media source, create one. +		// The null owner will keep the browser plugin from fully initializing  +		// (specifically, it keeps LLPluginClassMedia from negotiating a size change,  +		// which keeps MediaPluginWebkit::initBrowserWindow from doing anything until we have some necessary data, like the background color) +		sSpareBrowserMediaSource = LLViewerMediaImpl::newSourceFromMediaType("text/html", NULL, 0, 0); +	} +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +LLPluginClassMedia* LLViewerMedia::getSpareBrowserMediaSource()  +{ +	LLPluginClassMedia* result = sSpareBrowserMediaSource; +	sSpareBrowserMediaSource = NULL; +	return result;  +}; +  bool LLViewerMedia::hasInWorldMedia()  {  	if (sInWorldMediaDisabled) return false; @@ -1636,6 +1691,21 @@ void LLViewerMediaImpl::setMediaType(const std::string& media_type)  LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_type, LLPluginClassMediaOwner *owner /* may be NULL */, S32 default_width, S32 default_height, const std::string target)  {  	std::string plugin_basename = LLMIMETypes::implType(media_type); +	LLPluginClassMedia* media_source = NULL; +	 +	// HACK: we always try to keep a spare running webkit plugin around to improve launch times. +	if(plugin_basename == "media_plugin_webkit") +	{ +		media_source = LLViewerMedia::getSpareBrowserMediaSource(); +		if(media_source) +		{ +			media_source->setOwner(owner); +			media_source->setTarget(target); +			media_source->setSize(default_width, default_height); +						 +			return media_source; +		} +	}  	if(plugin_basename.empty())  	{ @@ -1673,7 +1743,7 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_  		}  		else  		{ -			LLPluginClassMedia* media_source = new LLPluginClassMedia(owner); +			media_source = new LLPluginClassMedia(owner);  			media_source->setSize(default_width, default_height);  			media_source->setUserDataPath(user_data_path);  			media_source->setLanguageCode(LLUI::getLanguage()); @@ -1753,6 +1823,22 @@ bool LLViewerMediaImpl::initializePlugin(const std::string& media_type)  		media_source->focus(mHasFocus);  		media_source->setBackgroundColor(mBackgroundColor); +		if(gSavedSettings.getBOOL("BrowserIgnoreSSLCertErrors")) +		{ +			media_source->ignore_ssl_cert_errors(true); +		} + +		// start by assuming the default CA file will be used +		std::string ca_path = gDirUtilp->getExpandedFilename( LL_PATH_APP_SETTINGS, "lindenlab.pem" ); +	 +		// default turned off so pick up the user specified path +		if( ! gSavedSettings.getBOOL("BrowserUseDefaultCAFile")) +		{ +			ca_path = gSavedSettings.getString("BrowserCAFilePath"); +		} +		// set the path to the CA.pem file +		media_source->addCertificateFilePath( ca_path ); +  		media_source->proxy_setup(gSavedSettings.getBOOL("BrowserProxyEnabled"), gSavedSettings.getString("BrowserProxyAddress"), gSavedSettings.getS32("BrowserProxyPort"));  		if(mClearCache) @@ -1849,6 +1935,18 @@ void LLViewerMediaImpl::setSize(int width, int height)  }  ////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::showNotification(LLNotificationPtr notify) +{ +	mNotification = notify; +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::hideNotification() +{ +	mNotification.reset(); +} + +//////////////////////////////////////////////////////////////////////////////////////////  void LLViewerMediaImpl::play()  {  	// If the media source isn't there, try to initialize it and load an URL. @@ -2850,7 +2948,6 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla  			LL_DEBUGS("Media") << "MEDIA_EVENT_CLICK_LINK_NOFOLLOW, uri is: " << plugin->getClickURL() << LL_ENDL;   			std::string url = plugin->getClickURL();  			LLURLDispatcher::dispatch(url, NULL, mTrustedBrowser); -  		}  		break;  		case MEDIA_EVENT_CLICK_LINK_HREF: @@ -2913,6 +3010,7 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla  		case LLViewerMediaObserver::MEDIA_EVENT_NAVIGATE_BEGIN:  		{  			LL_DEBUGS("Media") << "MEDIA_EVENT_NAVIGATE_BEGIN, uri is: " << plugin->getNavigateURI() << LL_ENDL; +			hideNotification();  			if(getNavState() == MEDIANAVSTATE_SERVER_SENT)  			{ @@ -3003,7 +3101,26 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla  			plugin->sendPickFileResponse(response);  		}  		break; -		 + + +		case LLViewerMediaObserver::MEDIA_EVENT_AUTH_REQUEST: +		{ +			LLNotification::Params auth_request_params; +			auth_request_params.name = "AuthRequest"; + +			// pass in host name and realm for site (may be zero length but will always exist) +			LLSD args; +			LLURL raw_url( plugin->getAuthURL().c_str() ); +			args["HOST_NAME"] = raw_url.getAuthority(); +			args["REALM"] = plugin->getAuthRealm(); +			auth_request_params.substitutions = args; + +			auth_request_params.payload = LLSD().with("media_id", mTextureId); +			auth_request_params.functor.function = boost::bind(&LLViewerMedia::onAuthSubmit, _1, _2); +			LLNotifications::instance().add(auth_request_params); +		}; +		break; +  		case LLViewerMediaObserver::MEDIA_EVENT_CLOSE_REQUEST:  		{  			std::string uuid = plugin->getClickUUID(); @@ -3019,6 +3136,7 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla  				// This close request is directed at another instance  				pass_through = false;  				LLFloaterMediaBrowser::closeRequest(uuid); +				LLFloaterWebContent::closeRequest(uuid);  			}  		}  		break; @@ -3038,6 +3156,7 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla  				// This request is directed at another instance  				pass_through = false;  				LLFloaterMediaBrowser::geometryChanged(uuid, plugin->getGeometryX(), plugin->getGeometryY(), plugin->getGeometryWidth(), plugin->getGeometryHeight()); +				LLFloaterWebContent::geometryChanged(uuid, plugin->getGeometryX(), plugin->getGeometryY(), plugin->getGeometryWidth(), plugin->getGeometryHeight());  			}  		}  		break; @@ -3521,6 +3640,11 @@ bool LLViewerMediaImpl::isInAgentParcel() const  	return result;  } +LLNotificationPtr LLViewerMediaImpl::getCurrentNotification() const +{ +	return mNotification; +} +  //////////////////////////////////////////////////////////////////////////////////////////  //  // static diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h index 4025a4484f..e2e342cc45 100644 --- a/indra/newview/llviewermedia.h +++ b/indra/newview/llviewermedia.h @@ -37,6 +37,7 @@  #include "llpluginclassmedia.h"  #include "v4color.h" +#include "llnotificationptr.h"  #include "llurl.h" @@ -130,6 +131,8 @@ public:  	static bool isParcelMediaPlaying();  	static bool isParcelAudioPlaying(); +	static void onAuthSubmit(const LLSD& notification, const LLSD& response); +  	// Clear all cookies for all plugins  	static void clearAllCookies(); @@ -155,6 +158,9 @@ public:  	static void proxyWindowOpened(const std::string &target, const std::string &uuid);  	static void proxyWindowClosed(const std::string &uuid); +	static void createSpareBrowserMediaSource(); +	static LLPluginClassMedia* getSpareBrowserMediaSource(); +	  private:  	static void setOpenIDCookie();  	static void onTeleportFinished(); @@ -162,6 +168,7 @@ private:  	static LLPluginCookieStore *sCookieStore;  	static LLURL sOpenIDURL;  	static std::string sOpenIDCookie; +	static LLPluginClassMedia* sSpareBrowserMediaSource;  };  // Implementation functions not exported into header file @@ -195,6 +202,9 @@ public:  	LLPluginClassMedia* getMediaPlugin() { return mMediaSource; }  	void setSize(int width, int height); +	void showNotification(LLNotificationPtr notify); +	void hideNotification(); +  	void play();  	void stop();  	void pause(); @@ -387,6 +397,9 @@ public:  	// Is this media in the agent's parcel?  	bool isInAgentParcel() const; +	// get currently active notification associated with this media instance +	LLNotificationPtr getCurrentNotification() const; +  private:  	bool isAutoPlayable() const;  	bool shouldShowBasedOnClass() const; @@ -444,7 +457,8 @@ private:  	bool mNavigateSuspendedDeferred;  	bool mTrustedBrowser;  	std::string mTarget; -	 +	LLNotificationPtr mNotification; +  private:  	BOOL mIsUpdated ;  	std::list< LLVOVolume* > mObjectList ; diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index e18b4ec414..9e16bf2fbb 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -7223,6 +7223,12 @@ void handle_web_browser_test(const LLSD& param)  	LLWeb::loadURLInternal(url);  } +void handle_web_content_test(const LLSD& param) +{ +	std::string url = param.asString(); +	LLWeb::loadWebURLInternal(url); +} +  void handle_buy_currency_test(void*)  {  	std::string url = @@ -7973,7 +7979,8 @@ void initialize_menus()  	view_listener_t::addMenu(new LLAdvancedDumpRegionObjectCache(), "Advanced.DumpRegionObjectCache");  	// Advanced > UI -	commit.add("Advanced.WebBrowserTest", boost::bind(&handle_web_browser_test, _2)); +	commit.add("Advanced.WebBrowserTest", boost::bind(&handle_web_browser_test,	_2));	// sigh! this one opens the MEDIA browser +	commit.add("Advanced.WebContentTest", boost::bind(&handle_web_content_test, _2));	// this one opens the Web Content floater  	view_listener_t::addMenu(new LLAdvancedBuyCurrencyTest(), "Advanced.BuyCurrencyTest");  	view_listener_t::addMenu(new LLAdvancedDumpSelectMgr(), "Advanced.DumpSelectMgr");  	view_listener_t::addMenu(new LLAdvancedDumpInventory(), "Advanced.DumpInventory"); diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index b7be3bc5b3..fda291f3c1 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -404,6 +404,8 @@ class LLFileTakeSnapshotToDisk : public view_listener_t  									   gSavedSettings.getBOOL("RenderUIInSnapshot"),  									   FALSE))  		{ +			gViewerWindow->playSnapshotAnimAndSound(); +			  			LLPointer<LLImageFormatted> formatted;  			switch(LLFloaterSnapshot::ESnapshotFormat(gSavedSettings.getS32("SnapshotFormat")))  			{ diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index b7f72a2e4c..7dc5d96689 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -171,6 +171,31 @@ const BOOL SCRIPT_QUESTION_IS_CAUTION[SCRIPT_PERMISSION_EOF] =  	FALSE	// ControlYourCamera  }; +// Extract channel and version from a string like "SL Web Viewer Beta 10.11.29.215604". +// (channel: "SL Web Viewer Beta", version: "10.11.29.215604") +static bool parse_version_info(const std::string& version_info, std::string& channel, std::string& ver) +{ +	size_t last_space = version_info.rfind(" "); +	channel = version_info; + +	if (last_space != std::string::npos) +	{ +		try +		{ +			ver = version_info.substr(last_space + 1); +			channel.replace(last_space, ver.length() + 1, ""); // strip version +		} +		catch (std::out_of_range) +		{ +			return false; +		} + +		return true; +	} + +	return false; +} +  bool friendship_offer_callback(const LLSD& notification, const LLSD& response)  {  	S32 option = LLNotificationsUtil::getSelectedOption(notification, response); @@ -3825,28 +3850,22 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**)  	if (!gLastVersionChannel.empty())  	{ -		// work out the URL for this server's Release Notes -		std::string url ="http://wiki.secondlife.com/wiki/Release_Notes/"; -		std::string server_version = version_channel; -		std::vector<std::string> s_vect; -		boost::algorithm::split(s_vect, server_version, isspace); -		for(U32 i = 0; i < s_vect.size(); i++) +		std::string url = regionp->getCapability("ServerReleaseNotes"); +		if (url.empty())  		{ -			if (i != (s_vect.size() - 1)) +			// The capability hasn't arrived yet or is not supported, +			// fall back to parsing server version channel. +			std::string channel, ver; +			if (!parse_version_info(version_channel, channel, ver))  			{ -				if(i != (s_vect.size() - 2)) -				{ -				   url += s_vect[i] + "_"; -				} -				else -				{ -					url += s_vect[i] + "/"; -				} -			} -			else -			{ -				url += s_vect[i].substr(0,4); +				llwarns << "Failed to parse server version channel (" << version_channel << ")" << llendl;  			} + +			url = gSavedSettings.getString("ReleaseNotesURL"); +			LLSD args; +			args["CHANNEL"] = LLWeb::escapeURL(channel); +			args["VERSION"] = LLWeb::escapeURL(ver); +			LLStringUtil::format(url, args);  		}  		LLSD args; @@ -6306,6 +6325,9 @@ bool handle_lure_callback(const LLSD& notification, const LLSD& response)  				payload["from_id"] = target_id;  				payload["SUPPRESS_TOAST"] = true;  				LLNotificationsUtil::add("TeleportOfferSent", args, payload); + +				// Add the recepient to the recent people list. +				LLRecentPeople::instance().add(target_id);  			}  		}  		gAgent.sendReliableMessage(); diff --git a/indra/newview/llviewerparcelmedia.cpp b/indra/newview/llviewerparcelmedia.cpp index 99e869dafc..40f0b43313 100644 --- a/indra/newview/llviewerparcelmedia.cpp +++ b/indra/newview/llviewerparcelmedia.cpp @@ -586,6 +586,18 @@ void LLViewerParcelMedia::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent  			LL_DEBUGS("Media") << "Media event:  MEDIA_EVENT_GEOMETRY_CHANGE, uuid is " << self->getClickUUID() << LL_ENDL;  		}  		break; + +		case MEDIA_EVENT_AUTH_REQUEST: +		{ +			LL_DEBUGS("Media") <<  "Media event:  MEDIA_EVENT_AUTH_REQUEST, url " << self->getAuthURL() << ", realm " << self->getAuthRealm() << LL_ENDL; +		} +		break; + +		case MEDIA_EVENT_LINK_HOVERED: +		{ +			LL_DEBUGS("Media") <<  "Media event:  MEDIA_EVENT_LINK_HOVERED, hover text is: " << self->getHoverText() << LL_ENDL; +		}; +		break;  	};  } diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index ca07e7c4cf..551ba18dd5 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -1414,6 +1414,7 @@ void LLViewerRegion::setSeedCapability(const std::string& url)  	capabilityNames.append("UpdateNotecardTaskInventory");  	capabilityNames.append("UpdateScriptTask");  	capabilityNames.append("UploadBakedTexture"); +	capabilityNames.append("ViewerMetrics");  	capabilityNames.append("ViewerStartAuction");  	capabilityNames.append("ViewerStats");  	capabilityNames.append("WebFetchInventoryDescendents"); diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index b8fd944321..5eeb02b080 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -186,11 +186,6 @@ public:  	/*virtual*/ std::string translateString(const char* tag,  					const std::map<std::string, std::string>& args); -	// signal on bottom tray width changed -	typedef boost::function<void (void)> bottom_tray_callback_t; -	typedef boost::signals2::signal<void (void)> bottom_tray_signal_t; -	bottom_tray_signal_t mOnBottomTrayWidthChanged; -	boost::signals2::connection setOnBottomTrayWidthChanged(bottom_tray_callback_t cb) { return mOnBottomTrayWidthChanged.connect(cb); }  	// signal on update of WorldView rect  	typedef boost::function<void (LLRect old_world_rect, LLRect new_world_rect)> world_rect_callback_t;  	typedef boost::signals2::signal<void (LLRect old_world_rect, LLRect new_world_rect)> world_rect_signal_t; diff --git a/indra/newview/llweb.cpp b/indra/newview/llweb.cpp index 6028a8fbea..b73017a51a 100644 --- a/indra/newview/llweb.cpp +++ b/indra/newview/llweb.cpp @@ -35,6 +35,7 @@  #include "llagent.h"  #include "llappviewer.h"  #include "llfloatermediabrowser.h" +#include "llfloaterwebcontent.h"  #include "llfloaterreg.h"  #include "lllogininstance.h"  #include "llparcel.h" @@ -95,6 +96,23 @@ void LLWeb::loadURL(const std::string& url, const std::string& target, const std  	}  } +// static +void LLWeb::loadWebURL(const std::string& url, const std::string& target, const std::string& uuid) +{ +	if(target == "_internal") +	{ +		// Force load in the internal browser, as if with a blank target. +		loadWebURLInternal(url, "", uuid); +	} +	else if (gSavedSettings.getBOOL("UseExternalBrowser") || (target == "_external")) +	{ +		loadURLExternal(url); +	} +	else +	{ +		loadWebURLInternal(url, target, uuid); +	} +}  // static  void LLWeb::loadURLInternal(const std::string &url, const std::string& target, const std::string& uuid) @@ -102,6 +120,13 @@ void LLWeb::loadURLInternal(const std::string &url, const std::string& target, c  	LLFloaterMediaBrowser::create(url, target, uuid);  } +// static +// Explicitly open a Web URL using the Web content floater +void LLWeb::loadWebURLInternal(const std::string &url, const std::string& target, const std::string& uuid) +{ +	LLFloaterWebContent::create(url, target, uuid); +} +  // static  void LLWeb::loadURLExternal(const std::string& url, const std::string& uuid) diff --git a/indra/newview/llweb.h b/indra/newview/llweb.h index 2915376583..dc5958e57f 100644 --- a/indra/newview/llweb.h +++ b/indra/newview/llweb.h @@ -57,6 +57,11 @@ public:  	static void loadURLExternal(const std::string& url, const std::string& uuid);  	static void loadURLExternal(const std::string& url, bool async, const std::string& uuid = LLStringUtil::null); +	// Explicitly open a Web URL using the Web content floater vs. the more general media browser +	static void loadWebURL(const std::string& url, const std::string& target, const std::string& uuid); +	static void loadWebURLInternal(const std::string &url, const std::string& target, const std::string& uuid); +	static void loadWebURLInternal(const std::string &url) { loadWebURLInternal(url, LLStringUtil::null, LLStringUtil::null); } +  	/// Returns escaped url (eg, " " to "%20") - used by all loadURL methods  	static std::string escapeURL(const std::string& url);  	/// Expands various strings like [LANG], [VERSION], etc. in a URL diff --git a/indra/newview/llworldmipmap.cpp b/indra/newview/llworldmipmap.cpp index be8298daab..74ed844376 100644 --- a/indra/newview/llworldmipmap.cpp +++ b/indra/newview/llworldmipmap.cpp @@ -181,8 +181,7 @@ LLPointer<LLViewerFetchedTexture> LLWorldMipmap::getObjectsTile(U32 grid_x, U32  LLPointer<LLViewerFetchedTexture> LLWorldMipmap::loadObjectsTile(U32 grid_x, U32 grid_y, S32 level)  {  	// Get the grid coordinates -	std::string imageurl = gSavedSettings.getString("MapServerURL") + llformat("map-%d-%d-%d-objects.jpg", level, grid_x, grid_y); - +	std::string imageurl = gSavedSettings.getString("CurrentMapServerURL") + llformat("map-%d-%d-%d-objects.jpg", level, grid_x, grid_y);  	// DO NOT COMMIT!! DEBUG ONLY!!!  	// Use a local jpeg for every tile to test map speed without S3 access diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index a51a096482..89611d8899 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -392,7 +392,7 @@ with the same filename but different name    <texture name="RadioButton_On_Disabled" file_name="widgets/RadioButton_On_Disabled.png" preload="true" /> -  <texture name="Refresh_Off" file_name="icons/Refresh_Off.png" preload="false" /> +  <texture name="Refresh_Off" file_name="icons/Refresh_Off.png" preload="true" />    <texture name="Resize_Corner" file_name="windows/Resize_Corner.png" preload="true" /> @@ -468,7 +468,7 @@ with the same filename but different name    <texture name="Stepper_Up_Off" file_name="widgets/Stepper_Up_Off.png" preload="false" />    <texture name="Stepper_Up_Press" file_name="widgets/Stepper_Up_Press.png" preload="false" /> -  <texture name="Stop_Off" file_name="icons/Stop_Off.png" preload="false" /> +  <texture name="Stop_Off" file_name="icons/Stop_Off.png" preload="true" />    <texture name="StopReload_Off" file_name="icons/StopReload_Off.png" preload="false" />    <texture name="StopReload_Over" file_name="icons/StopReload_Over.png" preload="false" /> diff --git a/indra/newview/skins/default/xui/en/floater_help_browser.xml b/indra/newview/skins/default/xui/en/floater_help_browser.xml index 837923bcf6..02e50ee584 100644 --- a/indra/newview/skins/default/xui/en/floater_help_browser.xml +++ b/indra/newview/skins/default/xui/en/floater_help_browser.xml @@ -36,7 +36,8 @@           user_resize="false"           width="620">              <web_browser -              trusted_content="true"  +             trusted_content="true"  +             initial_mime_type="text/html"                bottom="-25"               follows="left|right|top|bottom"               layout="topleft" diff --git a/indra/newview/skins/default/xui/en/floater_media_browser.xml b/indra/newview/skins/default/xui/en/floater_media_browser.xml index 49e835cce4..43729d7c9f 100644 --- a/indra/newview/skins/default/xui/en/floater_media_browser.xml +++ b/indra/newview/skins/default/xui/en/floater_media_browser.xml @@ -101,7 +101,7 @@               left_pad="5"               name="go"               top_delta="0" -             width="55"> +             width="50">  				<button.commit_callback  				function="MediaBrowser.Go" />  			</button> diff --git a/indra/newview/skins/default/xui/en/floater_web_content.xml b/indra/newview/skins/default/xui/en/floater_web_content.xml new file mode 100644 index 0000000000..2ad46824c2 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_web_content.xml @@ -0,0 +1,190 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
 +<floater
 +  legacy_header_height="18"
 +  can_resize="true"
 +  height="440"
 +  layout="topleft"
 +  min_height="140"
 +  min_width="467"
 +  name="floater_web_content"
 +  help_topic="floater_web_content"
 +  save_rect="true"
 +  auto_tile="true"
 +  title=""
 +  initial_mime_type="text/html"
 +  width="820">
 +  <layout_stack
 +    bottom="440"
 +    follows="left|right|top|bottom"
 +    layout="topleft"
 +    left="5"
 +    name="stack1"
 +    orientation="vertical"
 +    top="20"
 +    width="810">
 +    <layout_panel
 +      auto_resize="false"
 +      default_tab_group="1"
 +      height="22"
 +      layout="topleft"
 +      left="0"
 +      min_height="20"
 +      name="nav_controls"
 +      top="400"
 +      user_resize="false"
 +      width="800">
 +      <button
 +        image_overlay="Arrow_Left_Off"
 +		    image_disabled="PushButton_Disabled"
 +		    image_disabled_selected="PushButton_Disabled"
 +		    image_selected="PushButton_Selected"
 +		    image_unselected="PushButton_Off"
 +		    hover_glow_amount="0.15"
 +        tool_tip="Navigate back"
 +        follows="left|top"
 +        height="22"
 +        layout="topleft"
 +        left="1"
 +        name="back"
 +        top="0"
 +        width="22">
 +        <button.commit_callback
 +          function="WebContent.Back" />
 +      </button>
 +      <button
 +        image_overlay="Arrow_Right_Off"
 +		    image_disabled="PushButton_Disabled"
 +		    image_disabled_selected="PushButton_Disabled"
 +		    image_selected="PushButton_Selected"
 +		    image_unselected="PushButton_Off"
 +        tool_tip="Navigate forward"
 +        follows="left|top"
 +        height="22"
 +        layout="topleft"
 +        left="27"
 +        name="forward"
 +        top_delta="0"
 +        width="22">
 +        <button.commit_callback
 +          function="WebContent.Forward" />
 +      </button>
 +      <button
 +        image_overlay="Stop_Off"
 +		    image_disabled="PushButton_Disabled"
 +		    image_disabled_selected="PushButton_Disabled"
 +		    image_selected="PushButton_Selected"
 +		    image_unselected="PushButton_Off"
 +        tool_tip="Stop navigation"
 +        enabled="true"
 +        follows="left|top"
 +        height="22"
 +        layout="topleft"
 +        left="51"
 +        name="stop"
 +        top_delta="0"
 +        width="22">
 +        <button.commit_callback
 +          function="WebContent.Stop" />
 +      </button>
 +      <button
 +        image_overlay="Refresh_Off"
 +		    image_disabled="PushButton_Disabled"
 +		    image_disabled_selected="PushButton_Disabled"
 +		    image_selected="PushButton_Selected"
 +		    image_unselected="PushButton_Off"
 +        tool_tip="Reload page"
 +        follows="left|top"
 +        height="22"
 +        layout="topleft"
 +        left="51"
 +        name="reload"
 +        top_delta="0"
 +        width="22">
 +        <button.commit_callback
 +          function="WebContent.Reload" />
 +      </button>
 +      <combo_box
 +        allow_text_entry="true"
 +        follows="left|top|right"
 +        tab_group="1"
 +        height="22"
 +        layout="topleft"
 +        left_pad="4"
 +        max_chars="1024"
 +        name="address"
 +        combo_editor.select_on_focus="true"
 +        tool_tip="Enter URL here"
 +        top_delta="0"
 +        width="702">
 +        <combo_box.commit_callback
 +          function="WebContent.EnterAddress" />
 +      </combo_box>
 +      <icon
 +        name="media_secure_lock_flag"
 +        height="16"
 +        follows="top|right"
 +        image_name="Lock2"
 +        layout="topleft"
 +        left_delta="656"
 +        top_delta="2"
 +        visible="false" 
 +        tool_tip="Secured Browsing"
 +        width="16" />
 +      <button
 +        image_overlay="ExternalBrowser_Off"
 +		    image_disabled="PushButton_Disabled"
 +		    image_disabled_selected="PushButton_Disabled"
 +		    image_selected="PushButton_Selected"
 +		    image_unselected="PushButton_Off"
 +        tool_tip="Open current URL in your desktop browser"
 +        follows="right|top"
 +        enabled="true" 
 +        height="22"
 +        layout="topleft"
 +        name="popexternal"
 +        right="800"
 +        top_delta="-2"
 +        width="22">
 +        <button.commit_callback
 +          function="WebContent.PopExternal" />
 +      </button>
 +    </layout_panel>
 +    <layout_panel
 +      height="40"
 +      layout="topleft"
 +      left_delta="0"
 +      name="external_controls"
 +      top_delta="0"
 +      user_resize="false"
 +      width="540">
 +      <web_browser
 +        bottom="-22"
 +        follows="all"
 +        layout="topleft"
 +        left="0"
 +        name="webbrowser"
 +        top="0"/>
 +      <text
 +        type="string"
 +        length="100"
 +        follows="bottom|left"
 +        height="20"
 +        layout="topleft"
 +        left_delta="0"
 +        name="statusbartext"
 +        parse_urls="false"
 +        text_color="0.4 0.4 0.4 1" 
 +        top_pad="5"
 +        width="452"/>
 +      <progress_bar
 +        color_bar="0.3 1.0 0.3 1"
 +        follows="bottom|right"
 +        height="16"
 +        top_delta="-1"
 +        left_pad="24"
 +        layout="topleft"
 +        name="statusbarprogress"
 +        width="64"/>
 +    </layout_panel>
 +  </layout_stack>
 +</floater>
 diff --git a/indra/newview/skins/default/xui/en/floater_windlight_options.xml b/indra/newview/skins/default/xui/en/floater_windlight_options.xml index 85a5be369c..249ad95c41 100644 --- a/indra/newview/skins/default/xui/en/floater_windlight_options.xml +++ b/indra/newview/skins/default/xui/en/floater_windlight_options.xml @@ -594,6 +594,7 @@               left_delta="14"               top_pad="10"               name="SkyDayCycle" +             use_draw_context_alpha="false"               width="148" />              <slider               control_name="WLSunAngle" diff --git a/indra/newview/skins/default/xui/en/inspect_object.xml b/indra/newview/skins/default/xui/en/inspect_object.xml index eb2e7ea788..8d14c974b4 100644 --- a/indra/newview/skins/default/xui/en/inspect_object.xml +++ b/indra/newview/skins/default/xui/en/inspect_object.xml @@ -76,13 +76,24 @@ L$30,000    </text>    <!-- Overlapping buttons for all default actions.  Show "Buy" if    for sale, "Sit" if can sit, etc. --> +  <icon +   name="secure_browsing" +   image_name="Lock" +   left="0" +   visible="false" +   width="18" +   height="18" +   top="103" +   tool_tip="Secure Browsing" +   follows="left|top" />     <text     follows="all"     font="SansSerifSmall"     height="13"     name="object_media_url" -   width="220" -   top_pad="0" +   width="207" +   left_pad="2" +   top_delta="0"     max_length = "50"     use_ellipses="true">     http://www.superdupertest.com @@ -135,16 +146,6 @@ L$30,000     name="open_btn"     top_delta="0"     width="80" /> -  <icon -   name="secure_browsing" -   image_name="Lock" -   left_delta="80" -   visible="false" -   width="18" -   height="18" -   top_delta="0" -   tool_tip="Secure Browsing" -   follows="left|top" />   <!--  non-overlapping buttons here -->       <button @@ -153,7 +154,7 @@ L$30,000       label="More"       layout="topleft"       name="more_info_btn" -     left_delta="10" +     left_pad="10"       top_delta="0"       tab_stop="false"       width="80" /> diff --git a/indra/newview/skins/default/xui/en/menu_login.xml b/indra/newview/skins/default/xui/en/menu_login.xml index 4f982cc8e9..0d4a095e14 100644 --- a/indra/newview/skins/default/xui/en/menu_login.xml +++ b/indra/newview/skins/default/xui/en/menu_login.xml @@ -176,13 +176,19 @@               parameter="message_critical" />          </menu_item_call>          <menu_item_call -         label="Web Browser Test" +         label="Media Browser Test"           name="Web Browser Test">            <menu_item_call.on_click             function="Advanced.WebBrowserTest"             parameter="http://join.secondlife.com/"/>          </menu_item_call> -      <menu_item_separator/> +      <menu_item_call +       label="Web Content Floater Test" +       name="Web Content Floater Test"> +        <menu_item_call.on_click +         function="Advanced.WebContentTest" +         parameter="http://www.google.com"/> +      </menu_item_call>        <menu_item_check          label="Show Grid Picker"          name="Show Grid Picker" diff --git a/indra/newview/skins/default/xui/en/menu_mini_map.xml b/indra/newview/skins/default/xui/en/menu_mini_map.xml index 8fe89d3934..ea263d05ce 100644 --- a/indra/newview/skins/default/xui/en/menu_mini_map.xml +++ b/indra/newview/skins/default/xui/en/menu_mini_map.xml @@ -8,7 +8,7 @@   top="724"   visible="false"   width="128"> -    <menu_item_call +	<menu_item_call       label="Zoom Close"       name="Zoom Close">          <menu_item_call.on_click @@ -29,7 +29,14 @@           function="Minimap.Zoom"           parameter="far" />      </menu_item_call> -    <menu_item_separator /> +	<menu_item_call +     label="Zoom Default" +     name="Zoom Default"> +		<menu_item_call.on_click +         function="Minimap.Zoom" +         parameter="default" /> +	</menu_item_call> +	<menu_item_separator />      <menu_item_check         label="Rotate Map"         name="Rotate Map"> diff --git a/indra/newview/skins/default/xui/en/menu_place.xml b/indra/newview/skins/default/xui/en/menu_place.xml index 1b96eb51f0..288811d2f6 100644 --- a/indra/newview/skins/default/xui/en/menu_place.xml +++ b/indra/newview/skins/default/xui/en/menu_place.xml @@ -24,26 +24,4 @@           function="Places.OverflowMenu.Enable"           parameter="can_create_pick" />      </menu_item_call> -    <menu_item_separator -     layout="topleft"/> -    <menu_item_call -     enabled="false" -     label="Buy Pass" -     layout="topleft" -     name="pass"> -        <menu_item_call.on_click -         function="Places.OverflowMenu.Action" -         parameter="pass" /> -    </menu_item_call> -    <menu_item_separator -     layout="topleft"/> -    <menu_item_call -     enabled="false" -     label="Edit" -     layout="topleft" -     name="edit"> -        <menu_item_call.on_click -         function="Places.OverflowMenu.Action" -         parameter="edit" /> -    </menu_item_call>  </toggleable_menu> diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 907f68dc06..d997a262a8 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -976,6 +976,29 @@                   parameter="perm_prefs" />              </menu_item_call>          </menu> +        <menu_item_separator/> +        <menu_item_call +         enabled="false" +         label="Undo" +         name="Undo" +         shortcut="control|Z"> +            <on_click +             function="Edit.Undo" +             userdata="" /> +            <on_enable +             function="Edit.EnableUndo" /> +        </menu_item_call> +        <menu_item_call +         enabled="false" +         label="Redo" +         name="Redo" +         shortcut="control|Y"> +            <on_click +             function="Edit.Redo" +             userdata="" /> +            <on_enable +             function="Edit.EnableRedo" /> +        </menu_item_call>              </menu>      <menu       create_jump_keys="true" @@ -2623,13 +2646,21 @@                   parameter="BottomPanelNew" />              </menu_item_check>-->              <menu_item_call -             label="Web Browser Test" +             label="Media Browser Test"               name="Web Browser Test">                  <menu_item_call.on_click                   function="Advanced.WebBrowserTest"                   parameter="http://secondlife.com/app/search/slurls.html"/>              </menu_item_call> -            <menu_item_call +          <menu_item_call +           label="Web Content Browser" +           name="Web Content Browser" +           shortcut="control|alt|W"> +            <menu_item_call.on_click +             function="Advanced.WebContentTest" +             parameter="http://google.com"/> +          </menu_item_call> +          <menu_item_call               label="Dump SelectMgr"               name="Dump SelectMgr">                  <menu_item_call.on_click diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index b1fd579c6f..63c030b068 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -2901,12 +2901,80 @@ http://secondlife.com/download.       name="okbutton"       yestext="OK"/>    </notification> +    <notification -   icon="notifytip.tga" -   name="DownloadBackground" -   type="notifytip"> -An updated version of [APP_NAME] has been downloaded. -It will be applied the next time you restart [APP_NAME] +   icon="alertmodal.tga" +   name="FailedRequiredUpdateInstall" +   type="alertmodal"> +We were unable to install a required update.  +You will be unable to log in until [APP_NAME] has been updated. + +Please download and install the latest viewer from +http://secondlife.com/download. +    <usetemplate +     name="okbutton" +     yestext="Quit"/> +  </notification> + +  <notification +   icon="alertmodal.tga" +   name="UpdaterServiceNotRunning" +   type="alertmodal"> +There is a required update for your Second Life Installation. + +You may download this update from http://www.secondlife.com/downloads +or you can install it now. +    <usetemplate +     name="okcancelbuttons" +     notext="Quit Second Life" +     yestext="Download and install now"/> +  </notification> + +  <notification +   icon="notify.tga" +   name="DownloadBackgroundTip" +   type="notify"> +We have downloaded an update to your [APP_NAME] installation. +Version [VERSION] [[RELEASE_NOTES_FULL_URL] Information about this update] +    <usetemplate +     name="okcancelbuttons" +     notext="Later..." +     yestext="Install now and restart [APP_NAME]"/> +  </notification> + +  <notification + icon="alertmodal.tga" + name="DownloadBackgroundDialog" + type="alertmodal"> +We have downloaded an update to your [APP_NAME] installation. +Version [VERSION] [[RELEASE_NOTES_FULL_URL] Information about this update] +    <usetemplate +     name="okcancelbuttons" +     notext="Later..." +     yestext="Install now and restart [APP_NAME]"/> +  </notification> +   +  <notification + icon="alertmodal.tga" + name="RequiredUpdateDownloadedVerboseDialog" + type="alertmodal"> +We have downloaded a required software update. +Version [VERSION] + +We must restart [APP_NAME] to install the update. +    <usetemplate +     name="okbutton" +     yestext="OK"/> +  </notification> +   +  <notification + icon="alertmodal.tga" + name="RequiredUpdateDownloadedDialog" + type="alertmodal"> +We must restart [APP_NAME] to install the update. +    <usetemplate +     name="okbutton" +     yestext="OK"/>    </notification>    <notification @@ -5014,7 +5082,7 @@ If you want to view streaming media on parcels that support it you should go to     type="notify">  No Media Plugin was found to handle the "[MIME_TYPE]" mime type.  Media of this type will be unavailable.      <unique> -      <context key="[MIME_TYPE]"/> +      <context>MIME_TYPE</context>      </unique>    </notification> @@ -5943,7 +6011,7 @@ You may only select up to [MAX_SELECT] items from this list.  [NAME] is inviting you to a Voice Chat call.  Click Accept to join the call or Decline to decline the invitation. Click Block to block this caller.      <unique> -      <context key="NAME"/> +      <context>NAME</context>      </unique>      <form name="form">        <button @@ -5992,8 +6060,8 @@ Click Accept to join the call or Decline to decline the invitation. Click Block  [NAME] has joined a Voice Chat call with the group [GROUP].  Click Accept to join the call or Decline to decline the invitation. Click Block to block this caller.      <unique> -      <context key="NAME"/> -      <context key="GROUP"/> +      <context>NAME</context> +      <context>GROUP</context>      </unique>      <form name="form">        <button @@ -6018,7 +6086,7 @@ Click Accept to join the call or Decline to decline the invitation. Click Block  [NAME] has joined a voice chat call with a conference chat.  Click Accept to join the call or Decline to decline the invitation. Click Block to block this caller.      <unique> -      <context key="NAME"/> +      <context>NAME</context>      </unique>      <form name="form">        <button @@ -6043,7 +6111,7 @@ Click Accept to join the call or Decline to decline the invitation. Click Block  [NAME] is inviting you to a conference chat.  Click Accept to join the chat or Decline to decline the invitation. Click Block to block this caller.      <unique> -      <context key="NAME"/> +      <context>NAME</context>      </unique>      <form name="form">        <button @@ -6067,7 +6135,7 @@ Click Accept to join the chat or Decline to decline the invitation. Click Block     type="notifytip">  The voice call you are trying to join, [VOICE_CHANNEL_NAME], has reached maximum capacity. Please try again later.      <unique> -      <context key="VOICE_CHANNEL_NAME"/> +      <context>VOICE_CHANNEL_NAME</context>      </unique>    </notification> @@ -6085,7 +6153,7 @@ We're sorry.  This area has reached maximum capacity for voice conversation     type="notifytip">  You have been disconnected from [VOICE_CHANNEL_NAME].  You will now be reconnected to Nearby Voice Chat.      <unique> -      <context key="VOICE_CHANNEL_NAME"/> +      <context>VOICE_CHANNEL_NAME</context>      </unique>    </notification> @@ -6095,7 +6163,7 @@ You have been disconnected from [VOICE_CHANNEL_NAME].  You will now be reconnect     type="notifytip">  [VOICE_CHANNEL_NAME] has ended the call.  You will now be reconnected to Nearby Voice Chat.      <unique> -      <context key="VOICE_CHANNEL_NAME"/> +      <context>VOICE_CHANNEL_NAME</context>      </unique>    </notification> @@ -6105,7 +6173,7 @@ You have been disconnected from [VOICE_CHANNEL_NAME].  You will now be reconnect     type="notifytip">  [VOICE_CHANNEL_NAME] has declined your call.  You will now be reconnected to Nearby Voice Chat.      <unique> -      <context key="VOICE_CHANNEL_NAME"/> +      <context>VOICE_CHANNEL_NAME</context>      </unique>    </notification> @@ -6115,7 +6183,7 @@ You have been disconnected from [VOICE_CHANNEL_NAME].  You will now be reconnect     type="notifytip">  [VOICE_CHANNEL_NAME] is not available to take your call.  You will now be reconnected to Nearby Voice Chat.      <unique> -      <context key="VOICE_CHANNEL_NAME"/> +      <context>VOICE_CHANNEL_NAME</context>      </unique>    </notification> @@ -6125,7 +6193,7 @@ You have been disconnected from [VOICE_CHANNEL_NAME].  You will now be reconnect     type="notifytip">  Failed to connect to [VOICE_CHANNEL_NAME], please try again later.  You will now be reconnected to Nearby Voice Chat.      <unique> -      <context key="VOICE_CHANNEL_NAME"/> +      <context>VOICE_CHANNEL_NAME</context>      </unique>    </notification> @@ -6211,7 +6279,7 @@ Cannot enter parcel, you are not on the access list.     type="notifytip">  You do not have permission to connect to voice chat for [VOICE_CHANNEL_NAME].      <unique> -      <context key="VOICE_CHANNEL_NAME"/> +      <context>VOICE_CHANNEL_NAME</context>      </unique>    </notification> @@ -6221,7 +6289,7 @@ You do not have permission to connect to voice chat for [VOICE_CHANNEL_NAME].     type="notifytip">  An error has occurred while trying to connect to voice chat for [VOICE_CHANNEL_NAME].  Please try again later.      <unique> -      <context key="VOICE_CHANNEL_NAME"/> +      <context>VOICE_CHANNEL_NAME</context>      </unique>    </notification> @@ -6628,6 +6696,23 @@ Mute everyone?      </form>    </notification> +  <notification +  name="AuthRequest" +  type="browser"> +The site at '<nolink>[HOST_NAME]</nolink>' in realm '[REALM]' requires a user name and password. +    <form name="form"> +      <input name="username" type="text" text="User Name"/> +      <input name="password" type="password" text="Password    "/> +      <button default="true" +              index="0" +              name="ok" +              text="Submit"/> +      <button index="1" +              name="cancel" +              text="Cancel"/> +    </form> +  </notification> +    <global name="UnsupportedCPU">  - Your CPU speed does not meet the minimum requirements. diff --git a/indra/newview/skins/default/xui/en/panel_group_invite.xml b/indra/newview/skins/default/xui/en/panel_group_invite.xml index 15a3191bdf..cd834b61ce 100644 --- a/indra/newview/skins/default/xui/en/panel_group_invite.xml +++ b/indra/newview/skins/default/xui/en/panel_group_invite.xml @@ -94,7 +94,7 @@       left_pad="2"       name="cancel_button"       top_delta="0" -     width="70" /> +     width="65" />  	 <string   	 name="GroupInvitation">  	 Group Invitation diff --git a/indra/newview/skins/default/xui/en/panel_group_land_money.xml b/indra/newview/skins/default/xui/en/panel_group_land_money.xml index 1270a21710..61d6cbb2d0 100644 --- a/indra/newview/skins/default/xui/en/panel_group_land_money.xml +++ b/indra/newview/skins/default/xui/en/panel_group_land_money.xml @@ -117,7 +117,7 @@       name="map_button"       top_delta="-4"       left_pad="0" -     width="60" +     width="57"       enabled="false" />      <text       type="string" diff --git a/indra/newview/skins/default/xui/en/panel_login.xml b/indra/newview/skins/default/xui/en/panel_login.xml index e3cd61c5aa..257ed799da 100644 --- a/indra/newview/skins/default/xui/en/panel_login.xml +++ b/indra/newview/skins/default/xui/en/panel_login.xml @@ -12,11 +12,7 @@ top="600"       name="create_account_url">         http://join.secondlife.com/  </panel.string> -<panel.string -     name="real_url" translate="false"> -       http://secondlife.com/app/login/ -</panel.string> -    <string name="reg_in_client_url" translate="false"> +<string name="reg_in_client_url" translate="false">       http://secondlife.eniac15.lindenlab.com/reg-in-client/  </string>  <panel.string @@ -92,6 +88,7 @@ follows="left|bottom"    height="22"    max_length_bytes="16"  name="password_edit" +is_password="true"   select_on_focus="true"    top_pad="0"    width="135" /> diff --git a/indra/newview/skins/default/xui/en/panel_my_profile.xml b/indra/newview/skins/default/xui/en/panel_my_profile.xml index 1b41f602cd..5b8abaca6f 100644 --- a/indra/newview/skins/default/xui/en/panel_my_profile.xml +++ b/indra/newview/skins/default/xui/en/panel_my_profile.xml @@ -185,7 +185,7 @@                </expandable_text>              </panel>              <text -             follows="left|top" +             follows="left|top|right"               height="15"         font.style="BOLD"         font="SansSerifMedium" @@ -200,7 +200,7 @@               use_ellipses="true"           />              <text -             follows="left|top" +             follows="left|top|right"             font.style="BOLD"               height="10"               layout="topleft" @@ -213,7 +213,7 @@              <text_editor               allow_scroll="false"               bg_visible="false" -             follows="left|top" +             follows="left|top|right"               h_pad="0"               height="15"               layout="topleft" @@ -226,7 +226,7 @@               width="300"               word_wrap="true" />              <text -             follows="left|top" +             follows="left|top|right"         font.style="BOLD"               height="15"               layout="topleft" @@ -250,7 +250,7 @@              <text_editor              allow_scroll="false"              bg_visible="false" -            follows="left|top" +            follows="left|top|right"              h_pad="0"              height="28"              layout="topleft" @@ -266,7 +266,7 @@                Linden.              </text_editor>              <text -             follows="left|top" +             follows="left|top|right"         font.style="BOLD"               height="15"               layout="topleft" @@ -277,7 +277,7 @@               value="Partner:"               width="300" />              <panel -             follows="left|top" +             follows="left|top|right"               height="15"               layout="topleft"               left="10" @@ -285,7 +285,7 @@               top_pad="0"               width="300">                <text -               follows="left|top" +               follows="left|top|right"                 height="10"                 initial_value="(retrieving)"                 layout="topleft" @@ -297,7 +297,7 @@             width="300" />              </panel>              <text -             follows="left|top" +             follows="left|top|right"         font.style="BOLD"               height="13"               layout="topleft" diff --git a/indra/newview/skins/default/xui/en/panel_notify_textbox.xml b/indra/newview/skins/default/xui/en/panel_notify_textbox.xml index 4634eeed46..d5b6057233 100644 --- a/indra/newview/skins/default/xui/en/panel_notify_textbox.xml +++ b/indra/newview/skins/default/xui/en/panel_notify_textbox.xml @@ -1,7 +1,7 @@  <?xml version="1.0" encoding="utf-8" standalone="yes" ?>  <panel     background_visible="true" -   height="230" +   height="220"     label="instant_message"     layout="topleft"     left="0" @@ -14,55 +14,81 @@    <panel     bevel_style="none"     follows="left|right|top" -   height="150" +   height="185"     label="info_panel"     layout="topleft"     left="0"     name="info_panel"     top="0" -   width="305"> +   width="305">     +    <text_editor +     bg_readonly_color="0.0 0.0 0.0 0" +     enabled="false" +     follows="left|right|top|bottom" +     font="SansSerif" +     height="110"  +     layout="topleft" +     left="10" +     mouse_opaque="false" +     name="text_editor_box" +     read_only="true" +     text_color="white" +     text_readonly_color="white" +     top="10" +     width="285" +     wrap="true" +     parse_highlights="true" +     parse_urls="true"/>      <text_editor       parse_urls="true"       enabled="true"       follows="all" -     height="60" +     height="50"       layout="topleft" -     left="25" +     left="10"       max_length="250"       name="message"       parse_highlights="true"       read_only="false" -     top="40" +     top_pad="10"       type="string"       use_ellipses="true"       value="message" -     width="260" -     word_wrap="true" > +     width="285" +     word_wrap="true" +     parse_url="false" >      </text_editor> -     parse_urls="false" -    <button -     top="110" -     follows="top|left" -     height="20" -     label="Submit" -     layout="topleft" -     left="25" -     name="btn_submit" -     width="70" />    </panel>    <panel       background_visible="false"       follows="left|right|bottom" -     height="0"  +     height="25"        width="290"       label="control_panel"       layout="topleft"       left="10"       name="control_panel" -     top_pad="5"> +     top_pad="0">      <!--   	 Notes:  	 This panel holds the Ignore button and possibly other buttons of notification.        --> +    <button +     top="0" +     follows="top|left" +     height="20" +     label="Submit" +     layout="topleft" +     name="btn_submit" +     width="70" /> +    <button +     follows="top|right" +     height="20" +     label="Ignore" +     layout="topleft" +     left="215" +     name="ignore_btn" +     top="0" +     width="70" />    </panel>  </panel> diff --git a/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml b/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml index d6e4c56113..37aab059a9 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml @@ -82,7 +82,7 @@       control_name="AllowMultipleViewers"       follows="top|left"       height="15" -     label="Allow Multiple Viewer" +     label="Allow Multiple Viewers"       layout="topleft"       left="30"       name="allow_multiple_viewer_check" diff --git a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml index 584bd1ea9d..901a1257e0 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml @@ -142,7 +142,7 @@     layout="topleft"     left="80"     name="Cache location" -   top_delta="40" +   top_delta="20"     width="300">      Cache location:    </text> @@ -341,20 +341,41 @@     name="web_proxy_port"     top_delta="0"     width="145" /> - -  <check_box -    top_delta="2" -    enabled="true" -    follows="left|top" -    height="18" -    initial_value="true" -    control_name="UpdaterServiceActive" -    label="Automatically download and install [APP_NAME] updates" -    left="30" -    mouse_opaque="true" -    name="updater_service_active" -    radio_style="false" -    width="400" -    top_pad="10"/> - +  <text +     type="string" +     length="1" +     follows="left|top" +     height="10" +     layout="topleft" +     left="30" +     name="Software updates:" +     mouse_opaque="false" +     top_pad="5" +     width="300"> +    Software updates: +  </text> +  <combo_box +     control_name="UpdaterServiceSetting" +     follows="left|top" +     height="23" +     layout="topleft" +     left_delta="50" +	 top_pad="5" +     name="updater_service_combobox" +     width="300"> +        <combo_box.item +         label="Install automatically" +         name="Install_automatically" +         value="3" /> +      <!-- +        <combo_box.item +         label="Ask before installing" +         name="Install_ask" +         value="1" /> +      --> +        <combo_box.item +         label="Download and install updates manually" +         name="Install_manual" +         value="0" /> +  </combo_box>  </panel> 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 da366f30ae..f0ce8b849a 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_sound.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_sound.xml @@ -296,6 +296,7 @@  	<check_box  		name="media_auto_play_btn"  		control_name="ParcelMediaAutoPlayEnable" +		enabled_control="AudioStreamingMedia"  		value="true"  		follows="left|bottom|right"  		height="15" diff --git a/indra/newview/skins/default/xui/en/panel_profile.xml b/indra/newview/skins/default/xui/en/panel_profile.xml index 7caf425058..61e3bb354f 100644 --- a/indra/newview/skins/default/xui/en/panel_profile.xml +++ b/indra/newview/skins/default/xui/en/panel_profile.xml @@ -59,7 +59,7 @@           left="0"           name="profile_scroll"           opaque="true" -         height="527" +         height="400"           width="317"           top="0">            <panel diff --git a/indra/newview/skins/default/xui/en/panel_status_bar.xml b/indra/newview/skins/default/xui/en/panel_status_bar.xml index 2f52ca660b..d756dfb7de 100644 --- a/indra/newview/skins/default/xui/en/panel_status_bar.xml +++ b/indra/newview/skins/default/xui/en/panel_status_bar.xml @@ -51,7 +51,7 @@       height="18"       left="0"        name="balance" -     tool_tip="My Balance" +     tool_tip="Click to refresh your L$ balance"       v_pad="4"       top="0"       wrap="false"  diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index 51fba470cb..752bb6ed3a 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -1716,8 +1716,8 @@ integer llGetRegionAgentCount()  Returns the number of avatars in the region  	</string>  	<string name="LSLTipText_llTextBox" translate="false"> -llTextBox(key avatar, string message, integer chat_channel -Shows a dialog box on the avatar's screen with the message. +llTextBox(key avatar, string message, integer chat_channel) +Shows a window on the avatar's screen with the message.  It contains a text box for input, and if entered that text is chatted on chat_channel.  	</string>  	<string name="LSLTipText_llGetAgentLanguage" translate="false"> diff --git a/indra/newview/tests/lllogininstance_test.cpp b/indra/newview/tests/lllogininstance_test.cpp index 309e9e9ee3..9e321db889 100644 --- a/indra/newview/tests/lllogininstance_test.cpp +++ b/indra/newview/tests/lllogininstance_test.cpp @@ -40,6 +40,7 @@  #if defined(LL_WINDOWS)  #pragma warning(disable: 4355)      // using 'this' in base-class ctor initializer expr +#pragma warning(disable: 4702)      // disable 'unreachable code' so we can safely use skip().  #endif  // Constants @@ -68,6 +69,7 @@ static bool gDisconnectCalled = false;  #include "../llviewerwindow.h"  void LLViewerWindow::setShowProgress(BOOL show) {} +LLProgressView * LLViewerWindow::getProgressView(void) const { return 0; }  LLViewerWindow* gViewerWindow; @@ -185,6 +187,41 @@ const std::string &LLVersionInfo::getChannelAndVersion() { return VIEWERLOGIN_VE  const std::string &LLVersionInfo::getChannel() { return VIEWERLOGIN_CHANNEL; }  //----------------------------------------------------------------------------- +#include "../llappviewer.h" +void LLAppViewer::forceQuit(void) {} +LLAppViewer * LLAppViewer::sInstance = 0; + +//----------------------------------------------------------------------------- +#include "llnotificationsutil.h" +LLNotificationPtr LLNotificationsUtil::add(const std::string& name,  +					  const LLSD& substitutions,  +					  const LLSD& payload,  +					  boost::function<void (const LLSD&, const LLSD&)> functor) { return LLNotificationPtr((LLNotification*)0); } + + +//----------------------------------------------------------------------------- +#include "llupdaterservice.h" + +std::string const & LLUpdaterService::pumpName(void) +{ +	static std::string wakka = "wakka wakka wakka"; +	return wakka; +} +bool LLUpdaterService::updateReadyToInstall(void) { return false; } +void LLUpdaterService::initialize(const std::string& protocol_version, +				const std::string& url,  +				const std::string& path, +				const std::string& channel, +								  const std::string& version) {} + +void LLUpdaterService::setCheckPeriod(unsigned int seconds) {} +void LLUpdaterService::startChecking(bool install_if_ready) {} +void LLUpdaterService::stopChecking() {} +bool LLUpdaterService::isChecking() { return false; } +LLUpdaterService::eUpdaterState LLUpdaterService::getState() { return INITIAL; } +std::string LLUpdaterService::updatedVersion() { return ""; } + +//-----------------------------------------------------------------------------  #include "llnotifications.h"  #include "llfloaterreg.h"  static std::string gTOSType; @@ -198,6 +235,12 @@ LLFloater* LLFloaterReg::showInstance(const std::string& name, const LLSD& key,  	return NULL;  } +//---------------------------------------------------------------------------- +#include "../llprogressview.h" +void LLProgressView::setText(std::string const &){} +void LLProgressView::setPercent(float){} +void LLProgressView::setMessage(std::string const &){} +  //-----------------------------------------------------------------------------  // LLNotifications  class MockNotifications : public LLNotificationsInterface @@ -435,6 +478,8 @@ namespace tut      template<> template<>      void lllogininstance_object::test<3>()      { +		skip(); +		  		set_test_name("Test Mandatory Update User Accepts");  		// Part 1 - Mandatory Update, with User accepts response. @@ -462,6 +507,8 @@ namespace tut  	template<> template<>      void lllogininstance_object::test<4>()      { +		skip(); +		  		set_test_name("Test Mandatory Update User Decline");  		// Test connect with update needed. diff --git a/indra/newview/tests/llsimplestat_test.cpp b/indra/newview/tests/llsimplestat_test.cpp new file mode 100644 index 0000000000..60a8cac995 --- /dev/null +++ b/indra/newview/tests/llsimplestat_test.cpp @@ -0,0 +1,586 @@ +/**  + * @file llsimplestats_test.cpp + * @date 2010-10-22 + * @brief Test cases for some of llsimplestat.h + * + * $LicenseInfo:firstyear=2010&license=viewergpl$ + *  + * Copyright (c) 2010, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include <tut/tut.hpp> + +#include "lltut.h" +#include "../llsimplestat.h" +#include "llsd.h" +#include "llmath.h" + +// @brief Used as a pointer cast type to get access to LLSimpleStatCounter +class TutStatCounter: public LLSimpleStatCounter +{ +public: +	TutStatCounter();							// Not defined +	~TutStatCounter();							// Not defined +	void operator=(const TutStatCounter &);		// Not defined +	 +	void setRawCount(U32 c)				{ mCount = c; } +	U32 getRawCount() const				{ return mCount; } +}; + + +namespace tut +{ +	struct stat_counter_index +	{}; +	typedef test_group<stat_counter_index> stat_counter_index_t; +	typedef stat_counter_index_t::object stat_counter_index_object_t; +	tut::stat_counter_index_t tut_stat_counter_index("stat_counter_test"); + +	// Testing LLSimpleStatCounter's external interface +	template<> template<> +	void stat_counter_index_object_t::test<1>() +	{ +		LLSimpleStatCounter c1; +		ensure("Initialized counter is zero", (0 == c1.getCount())); + +		ensure("Counter increment return is 1", (1 == ++c1)); +		ensure("Counter increment return is 2", (2 == ++c1)); + +		ensure("Current counter is 2", (2 == c1.getCount())); + +		c1.reset(); +		ensure("Counter is 0 after reset", (0 == c1.getCount())); +		 +		ensure("Counter increment return is 1", (1 == ++c1)); +	} + +	// Testing LLSimpleStatCounter's internal state +	template<> template<> +	void stat_counter_index_object_t::test<2>() +	{ +		LLSimpleStatCounter c1; +		TutStatCounter * tc1 = (TutStatCounter *) &c1; +		 +		ensure("Initialized private counter is zero", (0 == tc1->getRawCount())); + +		++c1; +		++c1; +		 +		ensure("Current private counter is 2", (2 == tc1->getRawCount())); + +		c1.reset(); +		ensure("Raw counter is 0 after reset", (0 == tc1->getRawCount())); +	} + +	// Testing LLSimpleStatCounter's wrapping behavior +	template<> template<> +	void stat_counter_index_object_t::test<3>() +	{ +		LLSimpleStatCounter c1; +		TutStatCounter * tc1 = (TutStatCounter *) &c1; + +		tc1->setRawCount(U32_MAX); +		ensure("Initialized private counter is zero", (U32_MAX == c1.getCount())); + +		ensure("Increment of max value wraps to 0", (0 == ++c1)); +	} + +	// Testing LLSimpleStatMMM's external behavior +	template<> template<> +	void stat_counter_index_object_t::test<4>() +	{ +		LLSimpleStatMMM<> m1; +		typedef LLSimpleStatMMM<>::Value lcl_float; +		lcl_float zero(0); + +		// Freshly-constructed +		ensure("Constructed MMM<> has 0 count", (0 == m1.getCount())); +		ensure("Constructed MMM<> has 0 min", (zero == m1.getMin())); +		ensure("Constructed MMM<> has 0 max", (zero == m1.getMax())); +		ensure("Constructed MMM<> has 0 mean no div-by-zero", (zero == m1.getMean())); + +		// Single insert +		m1.record(1.0); +		ensure("Single insert MMM<> has 1 count", (1 == m1.getCount())); +		ensure("Single insert MMM<> has 1.0 min", (1.0 == m1.getMin())); +		ensure("Single insert MMM<> has 1.0 max", (1.0 == m1.getMax())); +		ensure("Single insert MMM<> has 1.0 mean", (1.0 == m1.getMean())); +		 +		// Second insert +		m1.record(3.0); +		ensure("2nd insert MMM<> has 2 count", (2 == m1.getCount())); +		ensure("2nd insert MMM<> has 1.0 min", (1.0 == m1.getMin())); +		ensure("2nd insert MMM<> has 3.0 max", (3.0 == m1.getMax())); +		ensure_approximately_equals("2nd insert MMM<> has 2.0 mean", m1.getMean(), lcl_float(2.0), 1); + +		// Third insert +		m1.record(5.0); +		ensure("3rd insert MMM<> has 3 count", (3 == m1.getCount())); +		ensure("3rd insert MMM<> has 1.0 min", (1.0 == m1.getMin())); +		ensure("3rd insert MMM<> has 5.0 max", (5.0 == m1.getMax())); +		ensure_approximately_equals("3rd insert MMM<> has 3.0 mean", m1.getMean(), lcl_float(3.0), 1); + +		// Fourth insert +		m1.record(1000000.0); +		ensure("4th insert MMM<> has 4 count", (4 == m1.getCount())); +		ensure("4th insert MMM<> has 1.0 min", (1.0 == m1.getMin())); +		ensure("4th insert MMM<> has 100000.0 max", (1000000.0 == m1.getMax())); +		ensure_approximately_equals("4th insert MMM<> has 250002.0 mean", m1.getMean(), lcl_float(250002.0), 1); + +		// Reset +		m1.reset(); +		ensure("Reset MMM<> has 0 count", (0 == m1.getCount())); +		ensure("Reset MMM<> has 0 min", (zero == m1.getMin())); +		ensure("Reset MMM<> has 0 max", (zero == m1.getMax())); +		ensure("Reset MMM<> has 0 mean no div-by-zero", (zero == m1.getMean())); +	} + +	// Testing LLSimpleStatMMM's response to large values +	template<> template<> +	void stat_counter_index_object_t::test<5>() +	{ +		LLSimpleStatMMM<> m1; +		typedef LLSimpleStatMMM<>::Value lcl_float; +		lcl_float zero(0); + +		// Insert overflowing values +		const lcl_float bignum(F32_MAX / 2); + +		m1.record(bignum); +		m1.record(bignum); +		m1.record(bignum); +		m1.record(bignum); +		m1.record(bignum); +		m1.record(bignum); +		m1.record(bignum); +		m1.record(zero); + +		ensure("Overflowed MMM<> has 8 count", (8 == m1.getCount())); +		ensure("Overflowed MMM<> has 0 min", (zero == m1.getMin())); +		ensure("Overflowed MMM<> has huge max", (bignum == m1.getMax())); +		ensure("Overflowed MMM<> has fetchable mean", (1.0 == m1.getMean() || true)); +		// We should be infinte but not interested in proving the IEEE standard here. +		LLSD sd1(m1.getMean()); +		// std::cout << "Thingy:  " << m1.getMean() << " and as LLSD:  " << sd1 << std::endl; +		ensure("Overflowed MMM<> produces LLSDable Real", (sd1.isReal())); +	} + +	// Testing LLSimpleStatMMM<F32>'s external behavior +	template<> template<> +	void stat_counter_index_object_t::test<6>() +	{ +		LLSimpleStatMMM<F32> m1; +		typedef LLSimpleStatMMM<F32>::Value lcl_float; +		lcl_float zero(0); + +		// Freshly-constructed +		ensure("Constructed MMM<F32> has 0 count", (0 == m1.getCount())); +		ensure("Constructed MMM<F32> has 0 min", (zero == m1.getMin())); +		ensure("Constructed MMM<F32> has 0 max", (zero == m1.getMax())); +		ensure("Constructed MMM<F32> has 0 mean no div-by-zero", (zero == m1.getMean())); + +		// Single insert +		m1.record(1.0); +		ensure("Single insert MMM<F32> has 1 count", (1 == m1.getCount())); +		ensure("Single insert MMM<F32> has 1.0 min", (1.0 == m1.getMin())); +		ensure("Single insert MMM<F32> has 1.0 max", (1.0 == m1.getMax())); +		ensure("Single insert MMM<F32> has 1.0 mean", (1.0 == m1.getMean())); +		 +		// Second insert +		m1.record(3.0); +		ensure("2nd insert MMM<F32> has 2 count", (2 == m1.getCount())); +		ensure("2nd insert MMM<F32> has 1.0 min", (1.0 == m1.getMin())); +		ensure("2nd insert MMM<F32> has 3.0 max", (3.0 == m1.getMax())); +		ensure_approximately_equals("2nd insert MMM<F32> has 2.0 mean", m1.getMean(), lcl_float(2.0), 1); + +		// Third insert +		m1.record(5.0); +		ensure("3rd insert MMM<F32> has 3 count", (3 == m1.getCount())); +		ensure("3rd insert MMM<F32> has 1.0 min", (1.0 == m1.getMin())); +		ensure("3rd insert MMM<F32> has 5.0 max", (5.0 == m1.getMax())); +		ensure_approximately_equals("3rd insert MMM<F32> has 3.0 mean", m1.getMean(), lcl_float(3.0), 1); + +		// Fourth insert +		m1.record(1000000.0); +		ensure("4th insert MMM<F32> has 4 count", (4 == m1.getCount())); +		ensure("4th insert MMM<F32> has 1.0 min", (1.0 == m1.getMin())); +		ensure("4th insert MMM<F32> has 1000000.0 max", (1000000.0 == m1.getMax())); +		ensure_approximately_equals("4th insert MMM<F32> has 250002.0 mean", m1.getMean(), lcl_float(250002.0), 1); + +		// Reset +		m1.reset(); +		ensure("Reset MMM<F32> has 0 count", (0 == m1.getCount())); +		ensure("Reset MMM<F32> has 0 min", (zero == m1.getMin())); +		ensure("Reset MMM<F32> has 0 max", (zero == m1.getMax())); +		ensure("Reset MMM<F32> has 0 mean no div-by-zero", (zero == m1.getMean())); +	} + +	// Testing LLSimpleStatMMM's response to large values +	template<> template<> +	void stat_counter_index_object_t::test<7>() +	{ +		LLSimpleStatMMM<F32> m1; +		typedef LLSimpleStatMMM<F32>::Value lcl_float; +		lcl_float zero(0); + +		// Insert overflowing values +		const lcl_float bignum(F32_MAX / 2); + +		m1.record(bignum); +		m1.record(bignum); +		m1.record(bignum); +		m1.record(bignum); +		m1.record(bignum); +		m1.record(bignum); +		m1.record(bignum); +		m1.record(zero); + +		ensure("Overflowed MMM<F32> has 8 count", (8 == m1.getCount())); +		ensure("Overflowed MMM<F32> has 0 min", (zero == m1.getMin())); +		ensure("Overflowed MMM<F32> has huge max", (bignum == m1.getMax())); +		ensure("Overflowed MMM<F32> has fetchable mean", (1.0 == m1.getMean() || true)); +		// We should be infinte but not interested in proving the IEEE standard here. +		LLSD sd1(m1.getMean()); +		// std::cout << "Thingy:  " << m1.getMean() << " and as LLSD:  " << sd1 << std::endl; +		ensure("Overflowed MMM<F32> produces LLSDable Real", (sd1.isReal())); +	} + +	// Testing LLSimpleStatMMM<F64>'s external behavior +	template<> template<> +	void stat_counter_index_object_t::test<8>() +	{ +		LLSimpleStatMMM<F64> m1; +		typedef LLSimpleStatMMM<F64>::Value lcl_float; +		lcl_float zero(0); + +		// Freshly-constructed +		ensure("Constructed MMM<F64> has 0 count", (0 == m1.getCount())); +		ensure("Constructed MMM<F64> has 0 min", (zero == m1.getMin())); +		ensure("Constructed MMM<F64> has 0 max", (zero == m1.getMax())); +		ensure("Constructed MMM<F64> has 0 mean no div-by-zero", (zero == m1.getMean())); + +		// Single insert +		m1.record(1.0); +		ensure("Single insert MMM<F64> has 1 count", (1 == m1.getCount())); +		ensure("Single insert MMM<F64> has 1.0 min", (1.0 == m1.getMin())); +		ensure("Single insert MMM<F64> has 1.0 max", (1.0 == m1.getMax())); +		ensure("Single insert MMM<F64> has 1.0 mean", (1.0 == m1.getMean())); +		 +		// Second insert +		m1.record(3.0); +		ensure("2nd insert MMM<F64> has 2 count", (2 == m1.getCount())); +		ensure("2nd insert MMM<F64> has 1.0 min", (1.0 == m1.getMin())); +		ensure("2nd insert MMM<F64> has 3.0 max", (3.0 == m1.getMax())); +		ensure_approximately_equals("2nd insert MMM<F64> has 2.0 mean", m1.getMean(), lcl_float(2.0), 1); + +		// Third insert +		m1.record(5.0); +		ensure("3rd insert MMM<F64> has 3 count", (3 == m1.getCount())); +		ensure("3rd insert MMM<F64> has 1.0 min", (1.0 == m1.getMin())); +		ensure("3rd insert MMM<F64> has 5.0 max", (5.0 == m1.getMax())); +		ensure_approximately_equals("3rd insert MMM<F64> has 3.0 mean", m1.getMean(), lcl_float(3.0), 1); + +		// Fourth insert +		m1.record(1000000.0); +		ensure("4th insert MMM<F64> has 4 count", (4 == m1.getCount())); +		ensure("4th insert MMM<F64> has 1.0 min", (1.0 == m1.getMin())); +		ensure("4th insert MMM<F64> has 1000000.0 max", (1000000.0 == m1.getMax())); +		ensure_approximately_equals("4th insert MMM<F64> has 250002.0 mean", m1.getMean(), lcl_float(250002.0), 1); + +		// Reset +		m1.reset(); +		ensure("Reset MMM<F64> has 0 count", (0 == m1.getCount())); +		ensure("Reset MMM<F64> has 0 min", (zero == m1.getMin())); +		ensure("Reset MMM<F64> has 0 max", (zero == m1.getMax())); +		ensure("Reset MMM<F64> has 0 mean no div-by-zero", (zero == m1.getMean())); +	} + +	// Testing LLSimpleStatMMM's response to large values +	template<> template<> +	void stat_counter_index_object_t::test<9>() +	{ +		LLSimpleStatMMM<F64> m1; +		typedef LLSimpleStatMMM<F64>::Value lcl_float; +		lcl_float zero(0); + +		// Insert overflowing values +		const lcl_float bignum(F64_MAX / 2); + +		m1.record(bignum); +		m1.record(bignum); +		m1.record(bignum); +		m1.record(bignum); +		m1.record(bignum); +		m1.record(bignum); +		m1.record(bignum); +		m1.record(zero); + +		ensure("Overflowed MMM<F64> has 8 count", (8 == m1.getCount())); +		ensure("Overflowed MMM<F64> has 0 min", (zero == m1.getMin())); +		ensure("Overflowed MMM<F64> has huge max", (bignum == m1.getMax())); +		ensure("Overflowed MMM<F64> has fetchable mean", (1.0 == m1.getMean() || true)); +		// We should be infinte but not interested in proving the IEEE standard here. +		LLSD sd1(m1.getMean()); +		// std::cout << "Thingy:  " << m1.getMean() << " and as LLSD:  " << sd1 << std::endl; +		ensure("Overflowed MMM<F64> produces LLSDable Real", (sd1.isReal())); +	} + +	// Testing LLSimpleStatMMM<U64>'s external behavior +	template<> template<> +	void stat_counter_index_object_t::test<10>() +	{ +		LLSimpleStatMMM<U64> m1; +		typedef LLSimpleStatMMM<U64>::Value lcl_int; +		lcl_int zero(0); + +		// Freshly-constructed +		ensure("Constructed MMM<U64> has 0 count", (0 == m1.getCount())); +		ensure("Constructed MMM<U64> has 0 min", (zero == m1.getMin())); +		ensure("Constructed MMM<U64> has 0 max", (zero == m1.getMax())); +		ensure("Constructed MMM<U64> has 0 mean no div-by-zero", (zero == m1.getMean())); + +		// Single insert +		m1.record(1); +		ensure("Single insert MMM<U64> has 1 count", (1 == m1.getCount())); +		ensure("Single insert MMM<U64> has 1 min", (1 == m1.getMin())); +		ensure("Single insert MMM<U64> has 1 max", (1 == m1.getMax())); +		ensure("Single insert MMM<U64> has 1 mean", (1 == m1.getMean())); +		 +		// Second insert +		m1.record(3); +		ensure("2nd insert MMM<U64> has 2 count", (2 == m1.getCount())); +		ensure("2nd insert MMM<U64> has 1 min", (1 == m1.getMin())); +		ensure("2nd insert MMM<U64> has 3 max", (3 == m1.getMax())); +		ensure("2nd insert MMM<U64> has 2 mean", (2 == m1.getMean())); + +		// Third insert +		m1.record(5); +		ensure("3rd insert MMM<U64> has 3 count", (3 == m1.getCount())); +		ensure("3rd insert MMM<U64> has 1 min", (1 == m1.getMin())); +		ensure("3rd insert MMM<U64> has 5 max", (5 == m1.getMax())); +		ensure("3rd insert MMM<U64> has 3 mean", (3 == m1.getMean())); + +		// Fourth insert +		m1.record(U64L(1000000000000)); +		ensure("4th insert MMM<U64> has 4 count", (4 == m1.getCount())); +		ensure("4th insert MMM<U64> has 1 min", (1 == m1.getMin())); +		ensure("4th insert MMM<U64> has 1000000000000ULL max", (U64L(1000000000000) == m1.getMax())); +		ensure("4th insert MMM<U64> has 250000000002ULL mean", (U64L( 250000000002) == m1.getMean())); + +		// Reset +		m1.reset(); +		ensure("Reset MMM<U64> has 0 count", (0 == m1.getCount())); +		ensure("Reset MMM<U64> has 0 min", (zero == m1.getMin())); +		ensure("Reset MMM<U64> has 0 max", (zero == m1.getMax())); +		ensure("Reset MMM<U64> has 0 mean no div-by-zero", (zero == m1.getMean())); +	} + +	// Testing LLSimpleStatMMM's response to large values +	template<> template<> +	void stat_counter_index_object_t::test<11>() +	{ +		LLSimpleStatMMM<U64> m1; +		typedef LLSimpleStatMMM<U64>::Value lcl_int; +		lcl_int zero(0); + +		// Insert overflowing values +		const lcl_int bignum(U64L(0xffffffffffffffff) / 2); + +		m1.record(bignum); +		m1.record(bignum); +		m1.record(bignum); +		m1.record(bignum); +		m1.record(bignum); +		m1.record(bignum); +		m1.record(bignum); +		m1.record(zero); + +		ensure("Overflowed MMM<U64> has 8 count", (8 == m1.getCount())); +		ensure("Overflowed MMM<U64> has 0 min", (zero == m1.getMin())); +		ensure("Overflowed MMM<U64> has huge max", (bignum == m1.getMax())); +		ensure("Overflowed MMM<U64> has fetchable mean", (zero == m1.getMean() || true)); +	} + +    // Testing LLSimpleStatCounter's merge() method +	template<> template<> +	void stat_counter_index_object_t::test<12>() +	{ +		LLSimpleStatCounter c1; +		LLSimpleStatCounter c2; + +		++c1; +		++c1; +		++c1; +		++c1; + +		++c2; +		++c2; +		c2.merge(c1); +		 +		ensure_equals("4 merged into 2 results in 6", 6, c2.getCount()); + +		ensure_equals("Source of merge is undamaged", 4, c1.getCount()); +	} + +    // Testing LLSimpleStatMMM's merge() method +	template<> template<> +	void stat_counter_index_object_t::test<13>() +	{ +		LLSimpleStatMMM<> m1; +		LLSimpleStatMMM<> m2; + +		m1.record(3.5); +		m1.record(4.5); +		m1.record(5.5); +		m1.record(6.5); + +		m2.record(5.0); +		m2.record(7.0); +		m2.record(9.0); +		 +		m2.merge(m1); + +		ensure_equals("Count after merge (p1)", 7, m2.getCount()); +		ensure_approximately_equals("Min after merge (p1)", F32(3.5), m2.getMin(), 22); +		ensure_approximately_equals("Max after merge (p1)", F32(9.0), m2.getMax(), 22); +		ensure_approximately_equals("Mean after merge (p1)", F32(41.000/7.000), m2.getMean(), 22); +		 + +		ensure_equals("Source count of merge is undamaged (p1)", 4, m1.getCount()); +		ensure_approximately_equals("Source min of merge is undamaged (p1)", F32(3.5), m1.getMin(), 22); +		ensure_approximately_equals("Source max of merge is undamaged (p1)", F32(6.5), m1.getMax(), 22); +		ensure_approximately_equals("Source mean of merge is undamaged (p1)", F32(5.0), m1.getMean(), 22); + +		m2.reset(); + +		m2.record(-22.0); +		m2.record(-1.0); +		m2.record(30.0); +		 +		m2.merge(m1); + +		ensure_equals("Count after merge (p2)", 7, m2.getCount()); +		ensure_approximately_equals("Min after merge (p2)", F32(-22.0), m2.getMin(), 22); +		ensure_approximately_equals("Max after merge (p2)", F32(30.0), m2.getMax(), 22); +		ensure_approximately_equals("Mean after merge (p2)", F32(27.000/7.000), m2.getMean(), 22); + +	} + +    // Testing LLSimpleStatMMM's merge() method when src contributes nothing +	template<> template<> +	void stat_counter_index_object_t::test<14>() +	{ +		LLSimpleStatMMM<> m1; +		LLSimpleStatMMM<> m2; + +		m2.record(5.0); +		m2.record(7.0); +		m2.record(9.0); +		 +		m2.merge(m1); + +		ensure_equals("Count after merge (p1)", 3, m2.getCount()); +		ensure_approximately_equals("Min after merge (p1)", F32(5.0), m2.getMin(), 22); +		ensure_approximately_equals("Max after merge (p1)", F32(9.0), m2.getMax(), 22); +		ensure_approximately_equals("Mean after merge (p1)", F32(7.000), m2.getMean(), 22); + +		ensure_equals("Source count of merge is undamaged (p1)", 0, m1.getCount()); +		ensure_approximately_equals("Source min of merge is undamaged (p1)", F32(0), m1.getMin(), 22); +		ensure_approximately_equals("Source max of merge is undamaged (p1)", F32(0), m1.getMax(), 22); +		ensure_approximately_equals("Source mean of merge is undamaged (p1)", F32(0), m1.getMean(), 22); + +		m2.reset(); + +		m2.record(-22.0); +		m2.record(-1.0); +		 +		m2.merge(m1); + +		ensure_equals("Count after merge (p2)", 2, m2.getCount()); +		ensure_approximately_equals("Min after merge (p2)", F32(-22.0), m2.getMin(), 22); +		ensure_approximately_equals("Max after merge (p2)", F32(-1.0), m2.getMax(), 22); +		ensure_approximately_equals("Mean after merge (p2)", F32(-11.5), m2.getMean(), 22); +	} + +    // Testing LLSimpleStatMMM's merge() method when dst contributes nothing +	template<> template<> +	void stat_counter_index_object_t::test<15>() +	{ +		LLSimpleStatMMM<> m1; +		LLSimpleStatMMM<> m2; + +		m1.record(5.0); +		m1.record(7.0); +		m1.record(9.0); +		 +		m2.merge(m1); + +		ensure_equals("Count after merge (p1)", 3, m2.getCount()); +		ensure_approximately_equals("Min after merge (p1)", F32(5.0), m2.getMin(), 22); +		ensure_approximately_equals("Max after merge (p1)", F32(9.0), m2.getMax(), 22); +		ensure_approximately_equals("Mean after merge (p1)", F32(7.000), m2.getMean(), 22); + +		ensure_equals("Source count of merge is undamaged (p1)", 3, m1.getCount()); +		ensure_approximately_equals("Source min of merge is undamaged (p1)", F32(5.0), m1.getMin(), 22); +		ensure_approximately_equals("Source max of merge is undamaged (p1)", F32(9.0), m1.getMax(), 22); +		ensure_approximately_equals("Source mean of merge is undamaged (p1)", F32(7.0), m1.getMean(), 22); + +		m1.reset(); +		m2.reset(); +		 +		m1.record(-22.0); +		m1.record(-1.0); +		 +		m2.merge(m1); + +		ensure_equals("Count after merge (p2)", 2, m2.getCount()); +		ensure_approximately_equals("Min after merge (p2)", F32(-22.0), m2.getMin(), 22); +		ensure_approximately_equals("Max after merge (p2)", F32(-1.0), m2.getMax(), 22); +		ensure_approximately_equals("Mean after merge (p2)", F32(-11.5), m2.getMean(), 22); +	} + +    // Testing LLSimpleStatMMM's merge() method when neither dst nor src contributes +	template<> template<> +	void stat_counter_index_object_t::test<16>() +	{ +		LLSimpleStatMMM<> m1; +		LLSimpleStatMMM<> m2; + +		m2.merge(m1); + +		ensure_equals("Count after merge (p1)", 0, m2.getCount()); +		ensure_approximately_equals("Min after merge (p1)", F32(0), m2.getMin(), 22); +		ensure_approximately_equals("Max after merge (p1)", F32(0), m2.getMax(), 22); +		ensure_approximately_equals("Mean after merge (p1)", F32(0), m2.getMean(), 22); + +		ensure_equals("Source count of merge is undamaged (p1)", 0, m1.getCount()); +		ensure_approximately_equals("Source min of merge is undamaged (p1)", F32(0), m1.getMin(), 22); +		ensure_approximately_equals("Source max of merge is undamaged (p1)", F32(0), m1.getMax(), 22); +		ensure_approximately_equals("Source mean of merge is undamaged (p1)", F32(0), m1.getMean(), 22); +	} +} diff --git a/indra/newview/tests/llviewerassetstats_test.cpp b/indra/newview/tests/llviewerassetstats_test.cpp new file mode 100644 index 0000000000..1bb4fb7c0c --- /dev/null +++ b/indra/newview/tests/llviewerassetstats_test.cpp @@ -0,0 +1,990 @@ +/**  + * @file llviewerassetstats_tut.cpp + * @date 2010-10-28 + * @brief Test cases for some of newview/llviewerassetstats.cpp + * + * $LicenseInfo:firstyear=2010&license=viewergpl$ + *  + * Copyright (c) 2010, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include <tut/tut.hpp> +#include <iostream> + +#include "lltut.h" +#include "../llviewerassetstats.h" +#include "lluuid.h" +#include "llsdutil.h" +#include "llregionhandle.h" + +static const char * all_keys[] =  +{ +	"duration", +	"fps", +	"get_other", +	"get_texture_temp_http", +	"get_texture_temp_udp", +	"get_texture_non_temp_http", +	"get_texture_non_temp_udp", +	"get_wearable_udp", +	"get_sound_udp", +	"get_gesture_udp" +}; + +static const char * resp_keys[] =  +{ +	"get_other", +	"get_texture_temp_http", +	"get_texture_temp_udp", +	"get_texture_non_temp_http", +	"get_texture_non_temp_udp", +	"get_wearable_udp", +	"get_sound_udp", +	"get_gesture_udp" +}; + +static const char * sub_keys[] = +{ +	"dequeued", +	"enqueued", +	"resp_count", +	"resp_max", +	"resp_min", +	"resp_mean" +}; + +static const char * mmm_resp_keys[] =  +{ +	"fps" +}; + +static const char * mmm_sub_keys[] = +{ +	"count", +	"max", +	"min", +	"mean" +}; + +static const LLUUID region1("4e2d81a3-6263-6ffe-ad5c-8ce04bee07e8"); +static const LLUUID region2("68762cc8-b68b-4e45-854b-e830734f2d4a"); +static const U64 region1_handle(0x0000040000003f00ULL); +static const U64 region2_handle(0x0000030000004200ULL); +static const std::string region1_handle_str("0000040000003f00"); +static const std::string region2_handle_str("0000030000004200"); + +#if 0 +static bool +is_empty_map(const LLSD & sd) +{ +	return sd.isMap() && 0 == sd.size(); +} + +static bool +is_single_key_map(const LLSD & sd, const std::string & key) +{ +	return sd.isMap() && 1 == sd.size() && sd.has(key); +} +#endif + +static bool +is_double_key_map(const LLSD & sd, const std::string & key1, const std::string & key2) +{ +	return sd.isMap() && 2 == sd.size() && sd.has(key1) && sd.has(key2); +} + +static bool +is_no_stats_map(const LLSD & sd) +{ +	return is_double_key_map(sd, "duration", "regions"); +} + +static bool +is_single_slot_array(const LLSD & sd, U64 region_handle) +{ +	U32 grid_x(0), grid_y(0); +	grid_from_region_handle(region_handle, &grid_x, &grid_y); +	 +	return (sd.isArray() && +			1 == sd.size() && +			sd[0].has("grid_x") && +			sd[0].has("grid_y") && +			sd[0]["grid_x"].isInteger() && +			sd[0]["grid_y"].isInteger() && +			grid_x == sd[0]["grid_x"].asInteger() && +			grid_y == sd[0]["grid_y"].asInteger()); +} + +static bool +is_double_slot_array(const LLSD & sd, U64 region_handle1, U64 region_handle2) +{ +	U32 grid_x1(0), grid_y1(0); +	U32 grid_x2(0), grid_y2(0); +	grid_from_region_handle(region_handle1, &grid_x1, &grid_y1); +	grid_from_region_handle(region_handle2, &grid_x2, &grid_y2); +	 +	return (sd.isArray() && +			2 == sd.size() && +			sd[0].has("grid_x") && +			sd[0].has("grid_y") && +			sd[0]["grid_x"].isInteger() && +			sd[0]["grid_y"].isInteger() && +			sd[1].has("grid_x") && +			sd[1].has("grid_y") && +			sd[1]["grid_x"].isInteger() && +			sd[1]["grid_y"].isInteger() && +			((grid_x1 == sd[0]["grid_x"].asInteger() && +			  grid_y1 == sd[0]["grid_y"].asInteger() && +			  grid_x2 == sd[1]["grid_x"].asInteger() && +			  grid_y2 == sd[1]["grid_y"].asInteger()) || +			 (grid_x1 == sd[1]["grid_x"].asInteger() && +			  grid_y1 == sd[1]["grid_y"].asInteger() && +			  grid_x2 == sd[0]["grid_x"].asInteger() && +			  grid_y2 == sd[0]["grid_y"].asInteger()))); +} + +static LLSD +get_region(const LLSD & sd, U64 region_handle1) +{ +	U32 grid_x(0), grid_y(0); +	grid_from_region_handle(region_handle1, &grid_x, &grid_y); + +	for (LLSD::array_const_iterator it(sd["regions"].beginArray()); +		 sd["regions"].endArray() != it; +		 ++it) +	{ +		if ((*it).has("grid_x") && +			(*it).has("grid_y") && +			(*it)["grid_x"].isInteger() && +			(*it)["grid_y"].isInteger() && +			(*it)["grid_x"].asInteger() == grid_x && +			(*it)["grid_y"].asInteger() == grid_y) +		{ +			return *it; +		} +	} +	return LLSD(); +} + +namespace tut +{ +	struct tst_viewerassetstats_index +	{}; +	typedef test_group<tst_viewerassetstats_index> tst_viewerassetstats_index_t; +	typedef tst_viewerassetstats_index_t::object tst_viewerassetstats_index_object_t; +	tut::tst_viewerassetstats_index_t tut_tst_viewerassetstats_index("tst_viewerassetstats_test"); + +	// Testing free functions without global stats allocated +	template<> template<> +	void tst_viewerassetstats_index_object_t::test<1>() +	{ +		// Check that helpers aren't bothered by missing global stats +		ensure("Global gViewerAssetStatsMain should be NULL", (NULL == gViewerAssetStatsMain)); + +		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, false, false); + +		LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_TEXTURE, false, false); + +		LLViewerAssetStatsFF::record_response_main(LLViewerAssetType::AT_GESTURE, false, false, 12300000ULL); +	} + +	// Create a non-global instance and check the structure +	template<> template<> +	void tst_viewerassetstats_index_object_t::test<2>() +	{ +		ensure("Global gViewerAssetStatsMain should be NULL", (NULL == gViewerAssetStatsMain)); + +		LLViewerAssetStats * it = new LLViewerAssetStats(); + +		ensure("Global gViewerAssetStatsMain should still be NULL", (NULL == gViewerAssetStatsMain)); + +		LLSD sd_full = it->asLLSD(false); + +		// Default (NULL) region ID doesn't produce LLSD results so should +		// get an empty map back from output +		ensure("Stat-less LLSD initially", is_no_stats_map(sd_full)); + +		// Once the region is set, we will get a response even with no data collection +		it->setRegion(region1_handle); +		sd_full = it->asLLSD(false); +		ensure("Correct single-key LLSD map root", is_double_key_map(sd_full, "duration", "regions")); +		ensure("Correct single-slot LLSD array regions", is_single_slot_array(sd_full["regions"], region1_handle)); +		 +		LLSD sd = sd_full["regions"][0]; + +		delete it; +			 +		// Check the structure of the LLSD +		for (int i = 0; i < LL_ARRAY_SIZE(all_keys); ++i) +		{ +			std::string line = llformat("Has '%s' key", all_keys[i]); +			ensure(line, sd.has(all_keys[i])); +		} + +		for (int i = 0; i < LL_ARRAY_SIZE(resp_keys); ++i) +		{ +			for (int j = 0; j < LL_ARRAY_SIZE(sub_keys); ++j) +			{ +				std::string line = llformat("Key '%s' has '%s' key", resp_keys[i], sub_keys[j]); +				ensure(line, sd[resp_keys[i]].has(sub_keys[j])); +			} +		} + +		for (int i = 0; i < LL_ARRAY_SIZE(mmm_resp_keys); ++i) +		{ +			for (int j = 0; j < LL_ARRAY_SIZE(mmm_sub_keys); ++j) +			{ +				std::string line = llformat("Key '%s' has '%s' key", mmm_resp_keys[i], mmm_sub_keys[j]); +				ensure(line, sd[mmm_resp_keys[i]].has(mmm_sub_keys[j])); +			} +		} +	} + +	// Create a non-global instance and check some content +	template<> template<> +	void tst_viewerassetstats_index_object_t::test<3>() +	{ +		LLViewerAssetStats * it = new LLViewerAssetStats(); +		it->setRegion(region1_handle); +		 +		LLSD sd = it->asLLSD(false); +		ensure("Correct single-key LLSD map root", is_double_key_map(sd, "regions", "duration")); +		ensure("Correct single-slot LLSD array regions", is_single_slot_array(sd["regions"], region1_handle)); +		sd = sd[0]; +		 +		delete it; + +		// Check a few points on the tree for content +		ensure("sd[get_texture_temp_http][dequeued] is 0", (0 == sd["get_texture_temp_http"]["dequeued"].asInteger())); +		ensure("sd[get_sound_udp][resp_min] is 0", (0.0 == sd["get_sound_udp"]["resp_min"].asReal())); +	} + +	// Create a global instance and verify free functions do something useful +	template<> template<> +	void tst_viewerassetstats_index_object_t::test<4>() +	{ +		gViewerAssetStatsMain = new LLViewerAssetStats(); +		LLViewerAssetStatsFF::set_region_main(region1_handle); + +		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, false, false); +		LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_TEXTURE, false, false); + +		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, false, false); +		LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, false, false); + +		LLSD sd = gViewerAssetStatsMain->asLLSD(false); +		ensure("Correct single-key LLSD map root", is_double_key_map(sd, "regions", "duration")); +		ensure("Correct single-slot LLSD array regions", is_single_slot_array(sd["regions"], region1_handle)); +		sd = sd["regions"][0]; +		 +		// Check a few points on the tree for content +		ensure("sd[get_texture_non_temp_udp][enqueued] is 1", (1 == sd["get_texture_non_temp_udp"]["enqueued"].asInteger())); +		ensure("sd[get_texture_temp_udp][enqueued] is 0", (0 == sd["get_texture_temp_udp"]["enqueued"].asInteger())); +		ensure("sd[get_texture_non_temp_http][enqueued] is 0", (0 == sd["get_texture_non_temp_http"]["enqueued"].asInteger())); +		ensure("sd[get_texture_temp_http][enqueued] is 0", (0 == sd["get_texture_temp_http"]["enqueued"].asInteger())); +		ensure("sd[get_gesture_udp][dequeued] is 0", (0 == sd["get_gesture_udp"]["dequeued"].asInteger())); + +		// Reset and check zeros... +		// Reset leaves current region in place +		gViewerAssetStatsMain->reset(); +		sd = gViewerAssetStatsMain->asLLSD(false)["regions"][region1_handle_str]; +		 +		delete gViewerAssetStatsMain; +		gViewerAssetStatsMain = NULL; + +		ensure("sd[get_texture_non_temp_udp][enqueued] is reset", (0 == sd["get_texture_non_temp_udp"]["enqueued"].asInteger())); +		ensure("sd[get_gesture_udp][dequeued] is reset", (0 == sd["get_gesture_udp"]["dequeued"].asInteger())); +	} + +	// Create two global instances and verify no interactions +	template<> template<> +	void tst_viewerassetstats_index_object_t::test<5>() +	{ +		gViewerAssetStatsThread1 = new LLViewerAssetStats(); +		gViewerAssetStatsMain = new LLViewerAssetStats(); +		LLViewerAssetStatsFF::set_region_main(region1_handle); + +		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, false, false); +		LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_TEXTURE, false, false); + +		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, false, false); +		LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, false, false); + +		LLSD sd = gViewerAssetStatsThread1->asLLSD(false); +		ensure("Other collector is empty", is_no_stats_map(sd)); +		sd = gViewerAssetStatsMain->asLLSD(false); +		ensure("Correct single-key LLSD map root", is_double_key_map(sd, "regions", "duration")); +		ensure("Correct single-slot LLSD array regions", is_single_slot_array(sd["regions"], region1_handle)); +		sd = sd["regions"][0]; +		 +		// Check a few points on the tree for content +		ensure("sd[get_texture_non_temp_udp][enqueued] is 1", (1 == sd["get_texture_non_temp_udp"]["enqueued"].asInteger())); +		ensure("sd[get_texture_temp_udp][enqueued] is 0", (0 == sd["get_texture_temp_udp"]["enqueued"].asInteger())); +		ensure("sd[get_texture_non_temp_http][enqueued] is 0", (0 == sd["get_texture_non_temp_http"]["enqueued"].asInteger())); +		ensure("sd[get_texture_temp_http][enqueued] is 0", (0 == sd["get_texture_temp_http"]["enqueued"].asInteger())); +		ensure("sd[get_gesture_udp][dequeued] is 0", (0 == sd["get_gesture_udp"]["dequeued"].asInteger())); + +		// Reset and check zeros... +		// Reset leaves current region in place +		gViewerAssetStatsMain->reset(); +		sd = gViewerAssetStatsMain->asLLSD(false)["regions"][0]; +		 +		delete gViewerAssetStatsMain; +		gViewerAssetStatsMain = NULL; +		delete gViewerAssetStatsThread1; +		gViewerAssetStatsThread1 = NULL; + +		ensure("sd[get_texture_non_temp_udp][enqueued] is reset", (0 == sd["get_texture_non_temp_udp"]["enqueued"].asInteger())); +		ensure("sd[get_gesture_udp][dequeued] is reset", (0 == sd["get_gesture_udp"]["dequeued"].asInteger())); +	} + +    // Check multiple region collection +	template<> template<> +	void tst_viewerassetstats_index_object_t::test<6>() +	{ +		gViewerAssetStatsMain = new LLViewerAssetStats(); + +		LLViewerAssetStatsFF::set_region_main(region1_handle); + +		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, false, false); +		LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_TEXTURE, false, false); + +		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, false, false); +		LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, false, false); + +		LLViewerAssetStatsFF::set_region_main(region2_handle); + +		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false); +		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false); +		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false); +		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false); + +		LLSD sd = gViewerAssetStatsMain->asLLSD(false); + +		// std::cout << sd << std::endl; +		 +		ensure("Correct double-key LLSD map root", is_double_key_map(sd, "duration", "regions")); +		ensure("Correct double-slot LLSD array regions", is_double_slot_array(sd["regions"], region1_handle, region2_handle)); +		LLSD sd1 = get_region(sd, region1_handle); +		LLSD sd2 = get_region(sd, region2_handle); +		ensure("Region1 is present in results", sd1.isMap()); +		ensure("Region2 is present in results", sd2.isMap()); +		 +		// Check a few points on the tree for content +		ensure_equals("sd1[get_texture_non_temp_udp][enqueued] is 1", sd1["get_texture_non_temp_udp"]["enqueued"].asInteger(), 1); +		ensure_equals("sd1[get_texture_temp_udp][enqueued] is 0", sd1["get_texture_temp_udp"]["enqueued"].asInteger(), 0); +		ensure_equals("sd1[get_texture_non_temp_http][enqueued] is 0", sd1["get_texture_non_temp_http"]["enqueued"].asInteger(), 0); +		ensure_equals("sd1[get_texture_temp_http][enqueued] is 0", sd1["get_texture_temp_http"]["enqueued"].asInteger(), 0); +		ensure_equals("sd1[get_gesture_udp][dequeued] is 0", sd1["get_gesture_udp"]["dequeued"].asInteger(), 0); + +		// Check a few points on the tree for content +		ensure("sd2[get_gesture_udp][enqueued] is 4", (4 == sd2["get_gesture_udp"]["enqueued"].asInteger())); +		ensure("sd2[get_gesture_udp][dequeued] is 0", (0 == sd2["get_gesture_udp"]["dequeued"].asInteger())); +		ensure("sd2[get_texture_non_temp_udp][enqueued] is 0", (0 == sd2["get_texture_non_temp_udp"]["enqueued"].asInteger())); + +		// Reset and check zeros... +		// Reset leaves current region in place +		gViewerAssetStatsMain->reset(); +		sd = gViewerAssetStatsMain->asLLSD(false); +		ensure("Correct single-key LLSD map root", is_double_key_map(sd, "regions", "duration")); +		ensure("Correct single-slot LLSD array regions (p2)", is_single_slot_array(sd["regions"], region2_handle)); +		sd2 = sd["regions"][0]; +		 +		delete gViewerAssetStatsMain; +		gViewerAssetStatsMain = NULL; + +		ensure("sd2[get_texture_non_temp_udp][enqueued] is reset", (0 == sd2["get_texture_non_temp_udp"]["enqueued"].asInteger())); +		ensure("sd2[get_gesture_udp][enqueued] is reset", (0 == sd2["get_gesture_udp"]["enqueued"].asInteger())); +	} + +    // Check multiple region collection jumping back-and-forth between regions +	template<> template<> +	void tst_viewerassetstats_index_object_t::test<7>() +	{ +		gViewerAssetStatsMain = new LLViewerAssetStats(); + +		LLViewerAssetStatsFF::set_region_main(region1_handle); + +		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, false, false); +		LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_TEXTURE, false, false); + +		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, false, false); +		LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, false, false); + +		LLViewerAssetStatsFF::set_region_main(region2_handle); + +		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false); +		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false); +		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false); +		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false); + +		LLViewerAssetStatsFF::set_region_main(region1_handle); + +		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, true, true); +		LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_TEXTURE, true, true); + +		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, false, false); +		LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, false, false); + +		LLViewerAssetStatsFF::set_region_main(region2_handle); + +		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false); +		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false); +		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false); +		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false); + +		LLSD sd = gViewerAssetStatsMain->asLLSD(false); + +		ensure("Correct double-key LLSD map root", is_double_key_map(sd, "duration", "regions")); +		ensure("Correct double-slot LLSD array regions", is_double_slot_array(sd["regions"], region1_handle, region2_handle)); +		LLSD sd1 = get_region(sd, region1_handle); +		LLSD sd2 = get_region(sd, region2_handle); +		ensure("Region1 is present in results", sd1.isMap()); +		ensure("Region2 is present in results", sd2.isMap()); +		 +		// Check a few points on the tree for content +		ensure("sd1[get_texture_non_temp_udp][enqueued] is 1", (1 == sd1["get_texture_non_temp_udp"]["enqueued"].asInteger())); +		ensure("sd1[get_texture_temp_udp][enqueued] is 0", (0 == sd1["get_texture_temp_udp"]["enqueued"].asInteger())); +		ensure("sd1[get_texture_non_temp_http][enqueued] is 0", (0 == sd1["get_texture_non_temp_http"]["enqueued"].asInteger())); +		ensure("sd1[get_texture_temp_http][enqueued] is 1", (1 == sd1["get_texture_temp_http"]["enqueued"].asInteger())); +		ensure("sd1[get_gesture_udp][dequeued] is 0", (0 == sd1["get_gesture_udp"]["dequeued"].asInteger())); + +		// Check a few points on the tree for content +		ensure("sd2[get_gesture_udp][enqueued] is 8", (8 == sd2["get_gesture_udp"]["enqueued"].asInteger())); +		ensure("sd2[get_gesture_udp][dequeued] is 0", (0 == sd2["get_gesture_udp"]["dequeued"].asInteger())); +		ensure("sd2[get_texture_non_temp_udp][enqueued] is 0", (0 == sd2["get_texture_non_temp_udp"]["enqueued"].asInteger())); + +		// Reset and check zeros... +		// Reset leaves current region in place +		gViewerAssetStatsMain->reset(); +		sd = gViewerAssetStatsMain->asLLSD(false); +		ensure("Correct single-key LLSD map root", is_double_key_map(sd, "duration", "regions")); +		ensure("Correct single-slot LLSD array regions (p2)", is_single_slot_array(sd["regions"], region2_handle)); +		sd2 = get_region(sd, region2_handle); +		ensure("Region2 is present in results", sd2.isMap()); +		 +		delete gViewerAssetStatsMain; +		gViewerAssetStatsMain = NULL; + +		ensure_equals("sd2[get_texture_non_temp_udp][enqueued] is reset", sd2["get_texture_non_temp_udp"]["enqueued"].asInteger(), 0); +		ensure_equals("sd2[get_gesture_udp][enqueued] is reset", sd2["get_gesture_udp"]["enqueued"].asInteger(), 0); +	} + +	// Non-texture assets ignore transport and persistence flags +	template<> template<> +	void tst_viewerassetstats_index_object_t::test<8>() +	{ +		gViewerAssetStatsThread1 = new LLViewerAssetStats(); +		gViewerAssetStatsMain = new LLViewerAssetStats(); +		LLViewerAssetStatsFF::set_region_main(region1_handle); + +		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, false, false); +		LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_TEXTURE, false, false); + +		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, false, false); +		LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, false, false); + +		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, false, true); +		LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, false, true); + +		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, true, false); +		LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, true, false); + +		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, true, true); +		LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, true, true); + +		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_LSL_BYTECODE, false, false); + +		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_LSL_BYTECODE, false, true); + +		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_LSL_BYTECODE, true, false); + +		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + +		LLSD sd = gViewerAssetStatsThread1->asLLSD(false); +		ensure("Other collector is empty", is_no_stats_map(sd)); +		sd = gViewerAssetStatsMain->asLLSD(false); +		ensure("Correct single-key LLSD map root", is_double_key_map(sd, "regions", "duration")); +		ensure("Correct single-slot LLSD array regions", is_single_slot_array(sd["regions"], region1_handle)); +		sd = get_region(sd, region1_handle); +		ensure("Region1 is present in results", sd.isMap()); +		 +		// Check a few points on the tree for content +		ensure("sd[get_gesture_udp][enqueued] is 0", (0 == sd["get_gesture_udp"]["enqueued"].asInteger())); +		ensure("sd[get_gesture_udp][dequeued] is 0", (0 == sd["get_gesture_udp"]["dequeued"].asInteger())); + +		ensure("sd[get_wearable_udp][enqueued] is 4", (4 == sd["get_wearable_udp"]["enqueued"].asInteger())); +		ensure("sd[get_wearable_udp][dequeued] is 4", (4 == sd["get_wearable_udp"]["dequeued"].asInteger())); + +		ensure("sd[get_other][enqueued] is 4", (4 == sd["get_other"]["enqueued"].asInteger())); +		ensure("sd[get_other][dequeued] is 0", (0 == sd["get_other"]["dequeued"].asInteger())); + +		// Reset and check zeros... +		// Reset leaves current region in place +		gViewerAssetStatsMain->reset(); +		sd = get_region(gViewerAssetStatsMain->asLLSD(false), region1_handle); +		ensure("Region1 is present in results", sd.isMap()); +		 +		delete gViewerAssetStatsMain; +		gViewerAssetStatsMain = NULL; +		delete gViewerAssetStatsThread1; +		gViewerAssetStatsThread1 = NULL; + +		ensure_equals("sd[get_texture_non_temp_udp][enqueued] is reset", sd["get_texture_non_temp_udp"]["enqueued"].asInteger(), 0); +		ensure_equals("sd[get_gesture_udp][dequeued] is reset", sd["get_gesture_udp"]["dequeued"].asInteger(), 0); +	} + + +	// LLViewerAssetStats::merge() basic functions work +	template<> template<> +	void tst_viewerassetstats_index_object_t::test<9>() +	{ +		LLViewerAssetStats s1; +		LLViewerAssetStats s2; + +		s1.setRegion(region1_handle); +		s2.setRegion(region1_handle); + +		s1.recordGetServiced(LLViewerAssetType::AT_TEXTURE, true, true, 5000000); +		s1.recordGetServiced(LLViewerAssetType::AT_TEXTURE, true, true, 6000000); +		s1.recordGetServiced(LLViewerAssetType::AT_TEXTURE, true, true, 8000000); +		s1.recordGetServiced(LLViewerAssetType::AT_TEXTURE, true, true, 7000000); +		s1.recordGetServiced(LLViewerAssetType::AT_TEXTURE, true, true, 9000000); +		 +		s2.recordGetServiced(LLViewerAssetType::AT_TEXTURE, true, true, 2000000); +		s2.recordGetServiced(LLViewerAssetType::AT_TEXTURE, true, true, 3000000); +		s2.recordGetServiced(LLViewerAssetType::AT_TEXTURE, true, true, 4000000); + +		s2.merge(s1); + +		LLSD s2_llsd = get_region(s2.asLLSD(false), region1_handle); +		ensure("Region1 is present in results", s2_llsd.isMap()); +		 +		ensure_equals("count after merge", s2_llsd["get_texture_temp_http"]["resp_count"].asInteger(), 8); +		ensure_approximately_equals("min after merge", s2_llsd["get_texture_temp_http"]["resp_min"].asReal(), 2.0, 22); +		ensure_approximately_equals("max after merge", s2_llsd["get_texture_temp_http"]["resp_max"].asReal(), 9.0, 22); +		ensure_approximately_equals("max after merge", s2_llsd["get_texture_temp_http"]["resp_mean"].asReal(), 5.5, 22); +	} + +	// LLViewerAssetStats::merge() basic functions work without corrupting source data +	template<> template<> +	void tst_viewerassetstats_index_object_t::test<10>() +	{ +		LLViewerAssetStats s1; +		LLViewerAssetStats s2; + +		s1.setRegion(region1_handle); +		s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + +		s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + +		s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 23289200); +		s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 282900); + +		 +		s2.setRegion(region2_handle); +		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + +		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + +		s2.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 6500000); +		s2.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 10000); + +		{ +			s2.merge(s1); +			 +			LLSD src = s1.asLLSD(false); +			LLSD dst = s2.asLLSD(false); + +			ensure_equals("merge src has single region", src["regions"].size(), 1); +			ensure_equals("merge dst has dual regions", dst["regions"].size(), 2); +			 +			// Remove time stamps, they're a problem +			src.erase("duration"); +			src["regions"][0].erase("duration"); +			dst.erase("duration"); +			dst["regions"][0].erase("duration"); +			dst["regions"][1].erase("duration"); + +			LLSD s1_llsd = get_region(src, region1_handle); +			ensure("Region1 is present in src", s1_llsd.isMap()); +			LLSD s2_llsd = get_region(dst, region1_handle); +			ensure("Region1 is present in dst", s2_llsd.isMap()); + +			ensure("result from src is in dst", llsd_equals(s1_llsd, s2_llsd)); +		} + +		s1.setRegion(region1_handle); +		s2.setRegion(region1_handle); +		s1.reset(); +		s2.reset(); +		 +		s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + +		s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + +		s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 23289200); +		s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 282900); + +		 +		s2.setRegion(region1_handle); +		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + +		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + +		s2.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 6500000); +		s2.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 10000); + +		{ +			s2.merge(s1); +			 +			LLSD src = s1.asLLSD(false); +			LLSD dst = s2.asLLSD(false); + +			ensure_equals("merge src has single region (p2)", src["regions"].size(), 1); +			ensure_equals("merge dst has single region (p2)", dst["regions"].size(), 1); + +			// Remove time stamps, they're a problem +			src.erase("duration"); +			src["regions"][0].erase("duration"); +			dst.erase("duration"); +			dst["regions"][0].erase("duration"); +			 +			LLSD s1_llsd = get_region(src, region1_handle); +			ensure("Region1 is present in src", s1_llsd.isMap()); +			LLSD s2_llsd = get_region(dst, region1_handle); +			ensure("Region1 is present in dst", s2_llsd.isMap()); + +			ensure_equals("src counts okay (enq)", s1_llsd["get_other"]["enqueued"].asInteger(), 4); +			ensure_equals("src counts okay (deq)", s1_llsd["get_other"]["dequeued"].asInteger(), 4); +			ensure_equals("src resp counts okay", s1_llsd["get_other"]["resp_count"].asInteger(), 2); +			ensure_approximately_equals("src respmin okay", s1_llsd["get_other"]["resp_min"].asReal(), 0.2829, 20); +			ensure_approximately_equals("src respmax okay", s1_llsd["get_other"]["resp_max"].asReal(), 23.2892, 20); +			 +			ensure_equals("dst counts okay (enq)", s2_llsd["get_other"]["enqueued"].asInteger(), 12); +			ensure_equals("src counts okay (deq)", s2_llsd["get_other"]["dequeued"].asInteger(), 11); +			ensure_equals("dst resp counts okay", s2_llsd["get_other"]["resp_count"].asInteger(), 4); +			ensure_approximately_equals("dst respmin okay", s2_llsd["get_other"]["resp_min"].asReal(), 0.010, 20); +			ensure_approximately_equals("dst respmax okay", s2_llsd["get_other"]["resp_max"].asReal(), 23.2892, 20); +		} +	} + + +    // Maximum merges are interesting when one side contributes nothing +	template<> template<> +	void tst_viewerassetstats_index_object_t::test<11>() +	{ +		LLViewerAssetStats s1; +		LLViewerAssetStats s2; + +		s1.setRegion(region1_handle); +		s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + +		s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + +		// Want to test negative numbers here but have to work in U64 +		s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 0); +		s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 0); +		s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 0); + +		s2.setRegion(region1_handle); +		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + +		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + +		{ +			s2.merge(s1); +			 +			LLSD src = s1.asLLSD(false); +			LLSD dst = s2.asLLSD(false); + +			ensure_equals("merge src has single region", src["regions"].size(), 1); +			ensure_equals("merge dst has single region", dst["regions"].size(), 1); +			 +			// Remove time stamps, they're a problem +			src.erase("duration"); +			src["regions"][0].erase("duration"); +			dst.erase("duration"); +			dst["regions"][0].erase("duration"); + +			LLSD s2_llsd = get_region(dst, region1_handle); +			ensure("Region1 is present in dst", s2_llsd.isMap()); +			 +			ensure_equals("dst counts come from src only", s2_llsd["get_other"]["resp_count"].asInteger(), 3); + +			ensure_approximately_equals("dst maximum with count 0 does not contribute to merged maximum", +										s2_llsd["get_other"]["resp_max"].asReal(), F64(0.0), 20); +		} + +		// Other way around +		s1.setRegion(region1_handle); +		s2.setRegion(region1_handle); +		s1.reset(); +		s2.reset(); + +		s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + +		s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + +		// Want to test negative numbers here but have to work in U64 +		s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 0); +		s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 0); +		s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 0); + +		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + +		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + +		{ +			s1.merge(s2); +			 +			LLSD src = s2.asLLSD(false); +			LLSD dst = s1.asLLSD(false); + +			ensure_equals("merge src has single region", src["regions"].size(), 1); +			ensure_equals("merge dst has single region", dst["regions"].size(), 1); +			 +			// Remove time stamps, they're a problem +			src.erase("duration"); +			src["regions"][0].erase("duration"); +			dst.erase("duration"); +			dst["regions"][0].erase("duration"); + +			LLSD s2_llsd = get_region(dst, region1_handle); +			ensure("Region1 is present in dst", s2_llsd.isMap()); + +			ensure_equals("dst counts come from src only (flipped)", s2_llsd["get_other"]["resp_count"].asInteger(), 3); + +			ensure_approximately_equals("dst maximum with count 0 does not contribute to merged maximum (flipped)", +										s2_llsd["get_other"]["resp_max"].asReal(), F64(0.0), 20); +		} +	} + +    // Minimum merges are interesting when one side contributes nothing +	template<> template<> +	void tst_viewerassetstats_index_object_t::test<12>() +	{ +		LLViewerAssetStats s1; +		LLViewerAssetStats s2; + +		s1.setRegion(region1_handle); +		s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + +		s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + +		s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 3800000); +		s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 2700000); +		s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 2900000); + +		s2.setRegion(region1_handle); +		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + +		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + +		{ +			s2.merge(s1); +			 +			LLSD src = s1.asLLSD(false); +			LLSD dst = s2.asLLSD(false); + +			ensure_equals("merge src has single region", src["regions"].size(), 1); +			ensure_equals("merge dst has single region", dst["regions"].size(), 1); +			 +			// Remove time stamps, they're a problem +			src.erase("duration"); +			src["regions"][0].erase("duration"); +			dst.erase("duration"); +			dst["regions"][0].erase("duration"); + +			LLSD s2_llsd = get_region(dst, region1_handle); +			ensure("Region1 is present in dst", s2_llsd.isMap()); + +			ensure_equals("dst counts come from src only", s2_llsd["get_other"]["resp_count"].asInteger(), 3); + +			ensure_approximately_equals("dst minimum with count 0 does not contribute to merged minimum", +										s2_llsd["get_other"]["resp_min"].asReal(), F64(2.7), 20); +		} + +		// Other way around +		s1.setRegion(region1_handle); +		s2.setRegion(region1_handle); +		s1.reset(); +		s2.reset(); + +		s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + +		s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + +		s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 3800000); +		s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 2700000); +		s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 2900000); + +		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + +		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); +		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + +		{ +			s1.merge(s2); +			 +			LLSD src = s2.asLLSD(false); +			LLSD dst = s1.asLLSD(false); + +			ensure_equals("merge src has single region", src["regions"].size(), 1); +			ensure_equals("merge dst has single region", dst["regions"].size(), 1); +			 +			// Remove time stamps, they're a problem +			src.erase("duration"); +			src["regions"][0].erase("duration"); +			dst.erase("duration"); +			dst["regions"][0].erase("duration"); + +			LLSD s2_llsd = get_region(dst, region1_handle); +			ensure("Region1 is present in dst", s2_llsd.isMap()); + +			ensure_equals("dst counts come from src only (flipped)", s2_llsd["get_other"]["resp_count"].asInteger(), 3); + +			ensure_approximately_equals("dst minimum with count 0 does not contribute to merged minimum (flipped)", +										s2_llsd["get_other"]["resp_min"].asReal(), F64(2.7), 20); +		} +	} + +} diff --git a/indra/newview/tests/llworldmap_test.cpp b/indra/newview/tests/llworldmap_test.cpp index b976ac5ea9..acc6e814bc 100644 --- a/indra/newview/tests/llworldmap_test.cpp +++ b/indra/newview/tests/llworldmap_test.cpp @@ -25,13 +25,16 @@   * $/LicenseInfo$   */ -// Precompiled header: almost always required for newview cpp files -#include "../llviewerprecompiledheaders.h" -// Class to test -#include "../llworldmap.h"  // Dependencies -#include "../llviewerimagelist.h" +#include "linden_common.h" +#include "llapr.h" +#include "llsingleton.h" +#include "lltrans.h" +#include "lluistring.h" +#include "../llviewertexture.h"  #include "../llworldmapmessage.h" +// Class to test +#include "../llworldmap.h"  // Tut header  #include "../test/lltut.h" @@ -44,34 +47,29 @@  // * A simulator for a class can be implemented here. Please comment and document thoroughly.  // Stub image calls -LLViewerImageList::LLViewerImageList() { } -LLViewerImageList::~LLViewerImageList() { } -LLViewerImageList gImageList; -LLViewerImage* LLViewerImageList::getImage(const LLUUID &image_id, -												   BOOL usemipmaps, -												   BOOL level_immediate, -												   LLGLint internal_format, -												   LLGLenum primary_format, -												   LLHost request_from_host) -{ return NULL; } -void LLViewerImage::setBoostLevel(S32 level) { } -void LLImageGL::setAddressMode(LLTexUnit::eTextureAddressMode mode) { } +void LLViewerTexture::setBoostLevel(S32 ) { } +void LLViewerTexture::setAddressMode(LLTexUnit::eTextureAddressMode ) { } +LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTexture(const LLUUID&, BOOL, LLViewerTexture::EBoostLevel, S8, +																  LLGLint, LLGLenum, LLHost ) { return NULL; }  // Stub related map calls  LLWorldMapMessage::LLWorldMapMessage() { }  LLWorldMapMessage::~LLWorldMapMessage() { }  void LLWorldMapMessage::sendItemRequest(U32 type, U64 handle) { }  void LLWorldMapMessage::sendMapBlockRequest(U16 min_x, U16 min_y, U16 max_x, U16 max_y, bool return_nonexistent) { } +  LLWorldMipmap::LLWorldMipmap() { }  LLWorldMipmap::~LLWorldMipmap() { }  void LLWorldMipmap::reset() { }  void LLWorldMipmap::dropBoostLevels() { }  void LLWorldMipmap::equalizeBoostLevels() { } -LLPointer<LLViewerImage> LLWorldMipmap::getObjectsTile(U32 grid_x, U32 grid_y, S32 level, bool load) -{ return NULL; } +LLPointer<LLViewerFetchedTexture> LLWorldMipmap::getObjectsTile(U32 grid_x, U32 grid_y, S32 level, bool load) { return NULL; }  // Stub other stuff -BOOL gPacificDaylightTime; +std::string LLTrans::getString(const std::string &, const LLStringUtil::format_map_t& ) { return std::string("test_trans"); } +void LLUIString::updateResult() const { } +void LLUIString::setArg(const std::string& , const std::string& ) { } +void LLUIString::assign(const std::string& ) { }  // End Stubbing  // ------------------------------------------------------------------------------------------- @@ -237,7 +235,7 @@ namespace tut  		// Test 9 : setLandForSaleImage() / getLandForSaleImage()  		LLUUID id;  		mSim->setLandForSaleImage(id); -		LLPointer<LLViewerImage> image = mSim->getLandForSaleImage(); +		LLPointer<LLViewerFetchedTexture> image = mSim->getLandForSaleImage();  		ensure("LLSimInfo::getLandForSaleImage() test failed", image.isNull());  		// Test 10 : isPG()  		mSim->setAccess(SIM_ACCESS_PG); @@ -370,7 +368,7 @@ namespace tut   		}  		// Test 7 : getObjectsTile()  		try { -			LLPointer<LLViewerImage> image = mWorld->getObjectsTile((U32)(X_WORLD_TEST/REGION_WIDTH_METERS), (U32)(Y_WORLD_TEST/REGION_WIDTH_METERS), 1); +			LLPointer<LLViewerFetchedTexture> image = mWorld->getObjectsTile((U32)(X_WORLD_TEST/REGION_WIDTH_METERS), (U32)(Y_WORLD_TEST/REGION_WIDTH_METERS), 1);  			ensure("LLWorldMap::getObjectsTile() failed", image.isNull());  		} catch (...) {  			fail("LLWorldMap::getObjectsTile() test failed with exception"); diff --git a/indra/newview/tests/llworldmipmap_test.cpp b/indra/newview/tests/llworldmipmap_test.cpp index 54887ae219..4c0959d1a9 100644 --- a/indra/newview/tests/llworldmipmap_test.cpp +++ b/indra/newview/tests/llworldmipmap_test.cpp @@ -25,12 +25,12 @@   * $/LicenseInfo$   */ -// Precompiled header: almost always required for newview cpp files -#include "../llviewerprecompiledheaders.h" +// Dependencies +#include "linden_common.h" +#include "../llviewertexture.h" +#include "../llviewercontrol.h"  // Class to test  #include "../llworldmipmap.h" -// Dependencies -#include "../llviewerimagelist.h"  // Tut header  #include "../test/lltut.h" @@ -42,19 +42,14 @@  // * Do not make any assumption as to how those classes or methods work (i.e. don't copy/paste code)  // * A simulator for a class can be implemented here. Please comment and document thoroughly. -LLViewerImageList::LLViewerImageList() { } -LLViewerImageList::~LLViewerImageList() { } - -LLViewerImageList gImageList; +void LLViewerTexture::setBoostLevel(S32 ) { } +LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTextureFromUrl(const std::string&, BOOL, LLViewerTexture::EBoostLevel, S8,  +																		 LLGLint, LLGLenum, const LLUUID& ) { return NULL; } -LLViewerImage* LLViewerImageList::getImageFromUrl(const std::string& url, -												   BOOL usemipmaps, -												   BOOL level_immediate, -												   LLGLint internal_format, -												   LLGLenum primary_format,  -												   const LLUUID& force_id) -{ return NULL; } -void LLViewerImage::setBoostLevel(S32 level) { } +LLControlGroup::LLControlGroup(const std::string& name) : LLInstanceTracker<LLControlGroup, std::string>(name) { } +LLControlGroup::~LLControlGroup() { } +std::string LLControlGroup::getString(const std::string& ) { return std::string("test_url"); } +LLControlGroup gSavedSettings("test_settings");  // End Stubbing  // ------------------------------------------------------------------------------------------- diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 6c77f8ec38..338c62b9fb 100644 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -255,12 +255,6 @@ class WindowsManifest(ViewerManifest):              self.enable_crt_manifest_check() -            # Get kdu dll, continue if missing. -            try: -                self.path('llkdu.dll', dst='llkdu.dll') -            except RuntimeError: -                print "Skipping llkdu.dll" -              # Get llcommon and deps. If missing assume static linkage and continue.              try:                  self.path('llcommon.dll') @@ -625,21 +619,21 @@ class DarwinManifest(ViewerManifest):                  libdir = "../../libraries/universal-darwin/lib_release"                  dylibs = {} -                # need to get the kdu dll from any of the build directories as well -                for lib in "llkdu", "llcommon": -                    libfile = "lib%s.dylib" % lib -                    try: -                        self.path(self.find_existing_file(os.path.join(os.pardir, -                                                                       lib, -                                                                       self.args['configuration'], -                                                                       libfile), -                                                          os.path.join(libdir, libfile)), -                                  dst=libfile) -                    except RuntimeError: -                        print "Skipping %s" % libfile -                        dylibs[lib] = False -                    else: -                        dylibs[lib] = True +                # Need to get the llcommon dll from any of the build directories as well +                lib = "llcommon" +                libfile = "lib%s.dylib" % lib +                try: +                    self.path(self.find_existing_file(os.path.join(os.pardir, +                                                                    lib, +                                                                    self.args['configuration'], +                                                                    libfile), +                                                      os.path.join(libdir, libfile)), +                                                      dst=libfile) +                except RuntimeError: +                    print "Skipping %s" % libfile +                    dylibs[lib] = False +                else: +                    dylibs[lib] = True                  if dylibs["llcommon"]:                      for libfile in ("libapr-1.0.3.7.dylib", @@ -931,15 +925,6 @@ class Linux_i686Manifest(LinuxManifest):      def construct(self):          super(Linux_i686Manifest, self).construct() -        # install either the libllkdu we just built, or a prebuilt one, in -        # decreasing order of preference.  for linux package, this goes to bin/ -        try: -            self.path(self.find_existing_file('../llkdu/libllkdu.so', -                '../../libraries/i686-linux/lib_release_client/libllkdu.so'), -                  dst='bin/libllkdu.so') -        except: -            print "Skipping libllkdu.so - not found" -          if self.prefix("../../libraries/i686-linux/lib_release_client", dst="lib"):              self.path("libapr-1.so.0")              self.path("libaprutil-1.so.0") @@ -956,12 +941,6 @@ class Linux_i686Manifest(LinuxManifest):              self.path("libopenal.so", "libopenal.so.1")              self.path("libopenal.so", "libvivoxoal.so.1") # vivox's sdk expects this soname              try: -                    self.path("libkdu.so") -                    pass -            except: -                    print "Skipping libkdu.so - not found" -                    pass -            try:                      self.path("libfmod-3.75.so")                      pass              except: | 
