diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 000000000..44cbbb60f --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,166 @@ +stages: + - build + - deploy + +variables: + VIEWER_USE_CRASHPAD: "TRUE" + VIEWER_CRASHPAD_URL: $SENTRY_DSN + +.win_build: &win_build + stage: build + tags: + - autobuild + - windows + before_script: + - pipenv install + script: + - If ($env:VIEWER_CHANNEL_TYPE -eq 'Project') + { + $env:VIEWER_CHANNEL_CODENAME = $env:CI_COMMIT_REF_NAME[8..100] -join '' + } + - pipenv run autobuild configure -c Release -- -DUSE_FMODSTUDIO=ON -DUSE_NVAPI=ON -DUSE_LTO=ON -DVS_DISABLE_FATAL_WARNINGS=ON + - pipenv run autobuild build -c Release --no-configure + - If ($env:VIEWER_USE_CRASHPAD -eq 'TRUE') { + - Push-Location .\build-vc-*\newview\Release\ + - sentry-cli upload-dif --include-sources singularity-bin.exe singularity-bin.pdb crashpad_handler.exe crashpad_handler.pdb fmod.dll libcrypto-1_1.dll libcrypto-1_1.pdb libssl-1_1.dll libssl-1_1.pdb libcrypto-1_1-x64.dll libcrypto-1_1-x64.pdb libssl-1_1-x64.dll libssl-1_1-x64.pdb vcruntime140.dll msvcp140.dll libhunspell.dll libhunspell.pdb glod.dll + - Pop-Location } + artifacts: + name: "$env:CI_COMMIT_REF_NAME-$env:CI_COMMIT_SHORT_SHA" + expire_in: 2 week + paths: + - build-vc-*/newview/Release/build_data.json + - build-vc-*/newview/Release/singularity-bin.pdb + - build-vc-*/newview/Release/Singularity_*_Setup.exe + +.beta_rules: &beta_rules + only: + - /^.*-beta$/ + except: + - branches + +.release_rules: &release_rules + only: + - /^.*-release$/ + except: + - branches + +build:master:windows32: + <<: *win_build + interruptible: true + variables: + AUTOBUILD_ADDRSIZE: 32 + VIEWER_CHANNEL_TYPE: Test + VIEWER_USE_CRASHPAD: "FALSE" + only: + - schedules + +build:master:windows64: + <<: *win_build + interruptible: true + variables: + AUTOBUILD_ADDRSIZE: 64 + VIEWER_CHANNEL_TYPE: Test + VIEWER_USE_CRASHPAD: "FALSE" + only: + - schedules + +build:project:windows32: + <<: *win_build + interruptible: true + variables: + AUTOBUILD_ADDRSIZE: 32 + VIEWER_CHANNEL_TYPE: Project + VIEWER_USE_CRASHPAD: "FALSE" + only: + - /^project-.*$/ + +build:project:windows64: + <<: *win_build + interruptible: true + variables: + AUTOBUILD_ADDRSIZE: 64 + VIEWER_CHANNEL_TYPE: Project + only: + - /^project-.*$/ + +build:beta:windows32: + <<: *win_build + variables: + AUTOBUILD_ADDRSIZE: 32 + VIEWER_CHANNEL_TYPE: Beta + VIEWER_USE_CRASHPAD: "FALSE" + <<: *beta_rules + +build:beta:windows64: + <<: *win_build + variables: + AUTOBUILD_ADDRSIZE: 64 + VIEWER_CHANNEL_TYPE: Beta + <<: *beta_rules + +build:release:windows32: + <<: *win_build + variables: + AUTOBUILD_ADDRSIZE: 32 + VIEWER_CHANNEL_TYPE: Release + VIEWER_USE_CRASHPAD: "FALSE" + <<: *release_rules + +build:release:windows64: + <<: *win_build + variables: + AUTOBUILD_ADDRSIZE: 64 + VIEWER_CHANNEL_TYPE: Release + <<: *release_rules + +.deploy_template: &deploy_template + stage: deploy + tags: + - autobuild + - windows + script: + - $BuildData = Get-Content .\build-vc-64\newview\Release\build_data.json | ConvertFrom-Json + - $BuildChannelVersion = $BuildData."Channel" + ' ' + $BuildData."Version" + - $UploadDestViewerDir = $BuildChannelVersion.ToLower().Replace(" ", "/") + - $UploadDestURL = "https://pkg.alchemyviewer.org/repository/viewer/${UploadDestViewerDir}" + + - $UploadParams = @{ UseBasicParsing = $true; + Method = "PUT"; + Headers = @{ + ContentType = "application/x-executable"; + Authorization = "Basic $([System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes("$env:AUTOBUILD_HTTP_USER`:$env:AUTOBUILD_HTTP_PASS")))"; }; + Verbose = $true; }; + + - Push-Location .\build-vc-32\newview\Release\ + - $FileNameWin32 = Get-ChildItem -Path . -Name -Include Singularity_*_Setup.exe + - Invoke-WebRequest @UploadParams -InFile .\$FileNameWin32 -Uri "${UploadDestURL}/${FileNameWin32}" + - Pop-Location + + - Push-Location .\build-vc-64\newview\Release\ + - $FileNameWin64 = Get-ChildItem -Path . -Name -Include Singularity_*_Setup.exe + - Invoke-WebRequest @UploadParams -InFile .\$FileNameWin64 -Uri "${UploadDestURL}/${FileNameWin64}" + - Pop-Location + + - sentry-cli releases new $BuildChannelVersion + - sentry-cli releases set-commits --auto $BuildChannelVersion + - sentry-cli releases finalize $BuildChannelVersion + when: manual + +deploy_project: + <<: *deploy_template + environment: + name: qa + only: + - /^project-.*$/ + +deploy_beta: + <<: *deploy_template + environment: + name: staging + <<: *beta_rules + +deploy_release: + <<: *deploy_template + environment: + name: production + <<: *release_rules diff --git a/Pipfile b/Pipfile index 03b834648..81e20cec2 100644 --- a/Pipfile +++ b/Pipfile @@ -8,7 +8,7 @@ name = "pypi" [packages] llbase = "*" certifi = "*" -autobuild = {hg = "https://bitbucket.org/alchemyviewer/autobuild-1.1"} +autobuild = {git = "https://git.alchemyviewer.org/alchemy/autobuild.git"} [requires] python_version = "2.7" diff --git a/autobuild.xml b/autobuild.xml index f5f17ea95..5d3f1a881 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -410,11 +410,11 @@ archive hash - 849f515d4d77162c15614ebff8599c13 + 4614b29cc98021cf1770a8290171602b hash_algorithm md5 url - https://pkg.alchemyviewer.org/repository/autobuild-external/crashpad/windows/crashpad-365c520b.6-windows-6.tar.bz2 + https://pkg.alchemyviewer.org/repository/autobuild-external/crashpad/windows/crashpad-ce32d093.7-windows-7.tar.bz2 name windows @@ -424,18 +424,18 @@ archive hash - 7ea820b6a2cfa172f47d673c07dfa62c + d801461b7a6a40fffab828aa1e01e3e6 hash_algorithm md5 url - https://pkg.alchemyviewer.org/repository/autobuild-external/crashpad/windows64/crashpad-365c520b.6-windows64-6.tar.bz2 + https://pkg.alchemyviewer.org/repository/autobuild-external/crashpad/windows64/crashpad-ce32d093.7-windows64-7.tar.bz2 name windows64 version - 365c520b.6 + ce32d093.7 curl @@ -664,11 +664,11 @@ archive hash - 06746b78827e9a0c6b666bd2528d36ad + 695efb6fc548a56dc4ff34e8d9a37bfb hash_algorithm md5 url - https://bitbucket.org/SingularityViewer/libraries/downloads/dullahan-1.1.1320_73.1.12%252Bgee4b49f%252Bchromium-73.0.3683.75-linux64-192030536.tar.bz2 + https://bitbucket.org/router_gray/3p-dullahan/downloads/dullahan-1.3.202002250830_79.1.38_gecefb59_chromium-79.0.3945.130-linux64-200580406.tar.bz2 name linux64 @@ -678,9 +678,11 @@ archive hash - e19b664ad8cf9e7f4a7bf649d28faa76 + 1b278ff2535f428ea6536683d096fdd0 + hash_algorithm + md5 url - https://bitbucket.org/SingularityViewer/libraries/downloads/dullahan-1.1.1320_73.1.12+gee4b49f+chromium-73.0.3683.75-windows-191102212.tar.bz2 + https://pkg.alchemyviewer.org/repository/autobuild-external/dullahan/windows/dullahan-1.3.201911222116_78.3.7_gea7ef34_chromium-78.0.3904.108-windows-2.tar.bz2 name windows @@ -690,18 +692,18 @@ archive hash - 414190fd1ce3876ee3efc682b06ae65c + b9346fea7643b10308c7bd9a769ef5f7 hash_algorithm md5 url - http://depot.alchemyviewer.org/pub/packages/windows64/msvc-1920/dullahan-1.1.1320_73.1.12-gee4b49f-chromium-73.0.3683.75-windows64-190871757.tar.bz2 + https://pkg.alchemyviewer.org/repository/autobuild-external/dullahan/windows64/dullahan-1.3.201911222103_78.3.7_gea7ef34_chromium-78.0.3904.108-windows64-2.tar.bz2 name windows64 version - 1.1.1320_73.1.12+gee4b49f+chromium-73.0.3683.75 + 1.3.201911222103_78.3.7_gea7ef34_chromium-78.0.3904.108 elfio @@ -816,7 +818,7 @@ fmodstudio copyright - FMOD Studio, copyright (c) Firelight Technologies Pty, Ltd., 2012-2019. + FMOD Studio, Copyright (c) Firelight Technologies Pty Ltd. description FMOD Studio audio system library license @@ -874,11 +876,11 @@ archive hash - 54dbd41322a08a1fc333ca6d96af5502 + ccd495598894c8e2e541a348015ee3f0 hash_algorithm md5 url - /opt/devel/secondlife/pkg/fmodstudio-2.00.02.191991250-linux64-191991250.tar.bz2 + /opt/devel/fmodstudio-2.00.07.200182252-linux64-200182252.tar.bz2 name linux64 @@ -888,11 +890,11 @@ archive hash - e0e87e0423fa42e4d2997b47b92eac6e + d32efb193ffcd73bcba4875ddfd17bf0 hash_algorithm md5 url - https://pkg.alchemyviewer.org/repository/autobuild-internal/fmodstudio/windows/fmodstudio-2.00.03.192211030-windows-192211030.tar.bz2 + https://pkg.alchemyviewer.org/repository/autobuild-internal/fmodstudio/windows/fmodstudio-2.00.07.4-windows-4.tar.bz2 name windows @@ -902,18 +904,18 @@ archive hash - c2e55e1bfef7e066a0e40867a64b4cce + 0604fd6b53ceaf14ce04d0de1bea51b8 hash_algorithm md5 url - https://pkg.alchemyviewer.org/repository/autobuild-internal/fmodstudio/windows64/fmodstudio-2.00.03.192211029-windows64-192211029.tar.bz2 + https://pkg.alchemyviewer.org/repository/autobuild-internal/fmodstudio/windows64/fmodstudio-2.00.07.4-windows64-4.tar.bz2 name windows64 version - 2.00.03.192211300 + 2.00.07.4 fonts @@ -996,7 +998,7 @@ freetype copyright - Copyright 2006-2017 by David Turner, Robert Wilhelm, and Werner Lemberg. + Copyright 2006-2018 by David Turner, Robert Wilhelm, and Werner Lemberg. description Font rendering library license @@ -2506,7 +2508,7 @@ vlc-bin copyright - Copyright (C) 1998-2016 VLC authors and VideoLAN + Copyright (C) 1998-2020 VLC authors and VideoLAN license GPL2 license_file @@ -2544,9 +2546,9 @@ archive hash - add560654a53cb1c554044a4fac3c718 + 3ff1d097e4f9b8f864a639aff974a506 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/12144/71458/vlc_bin-2.2.8.511703-windows-511703.tar.bz2 + https://pkg.alchemyviewer.org/repository/autobuild-external/vlc-bin/windows/vlc_bin-3.0.8.189-windows-189.tar.bz2 name windows @@ -2556,16 +2558,16 @@ archive hash - 94bf04b49acc1e1bf2c06e2232f8a083 + b890b109b526cc6ad211eadefed83316 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/12145/71463/vlc_bin-2.2.8.511703-windows64-511703.tar.bz2 + https://pkg.alchemyviewer.org/repository/autobuild-external/vlc-bin/windows64/vlc_bin-3.0.8.189-windows64-189.tar.bz2 name windows64 version - 2.2.8.511703 + 3.0.8.189 xmlrpc-epi @@ -2771,7 +2773,7 @@ options -DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo - -DWORD_SIZE:STRING=$AUTOBUILD_ADDRSIZE + -DADDRESS_SIZE:STRING=$AUTOBUILD_ADDRSIZE -DROOT_PROJECT_NAME:STRING=Singularity -DINSTALL_PROPRIETARY=FALSE @@ -2792,7 +2794,7 @@ options -DCMAKE_BUILD_TYPE:STRING=Release - -DWORD_SIZE:STRING=$AUTOBUILD_ADDRSIZE + -DADDRESS_SIZE:STRING=$AUTOBUILD_ADDRSIZE -DROOT_PROJECT_NAME:STRING=Singularity -DINSTALL_PROPRIETARY=FALSE @@ -2943,7 +2945,7 @@ -G Ninja - -DWORD_SIZE:STRING=64 + -DADDRESS_SIZE:STRING=64 default @@ -2968,7 +2970,7 @@ -G Ninja - -DWORD_SIZE:STRING=64 + -DADDRESS_SIZE:STRING=64 name @@ -2981,7 +2983,7 @@ windows build_directory - build-vc${AUTOBUILD_WIN_VSVER|161}-$AUTOBUILD_ADDRSIZE + build-vc-$AUTOBUILD_ADDRSIZE configurations RelWithDebInfo @@ -3040,6 +3042,7 @@ /p:Configuration=Release /p:Platform=${AUTOBUILD_WIN_VSPLATFORM|NOTWIN} /t:Build + /p:PreferredToolArchitecture=x64 /p:useenv=true /verbosity:normal /m @@ -3067,7 +3070,7 @@ name - windows64 + windows version_file diff --git a/indra/CMakeLists.txt b/indra/CMakeLists.txt index 6b5c80cf0..3bcd9e161 100644 --- a/indra/CMakeLists.txt +++ b/indra/CMakeLists.txt @@ -3,12 +3,7 @@ # cmake_minimum_required should appear before any # other commands to guarantee full compatibility # with the version specified -## prior to 2.8, the add_custom_target commands used in setting the version did not work correctly -if(WIN32) - cmake_minimum_required(VERSION 3.4 FATAL_ERROR) -else() - cmake_minimum_required(VERSION 2.8.8 FATAL_ERROR) -endif() +cmake_minimum_required(VERSION 3.14 FATAL_ERROR) set(ROOT_PROJECT_NAME "Singularity" CACHE STRING "The root project/makefile/solution name. Defaults to Singularity.") @@ -16,11 +11,6 @@ project(${ROOT_PROJECT_NAME}) set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") -include(Variables) -include(00-Common) -include(BuildVersion) -include(CTest) - set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED ON) @@ -29,6 +19,11 @@ if (NOT CMAKE_BUILD_TYPE) "Build type. One of: Debug Release RelWithDebInfo" FORCE) endif (NOT CMAKE_BUILD_TYPE) +include(Variables) +include(00-Common) +include(BuildVersion) +include(CTest) + add_subdirectory(deps) add_subdirectory(cmake) @@ -65,8 +60,10 @@ add_subdirectory(${LIBS_OPEN_PREFIX}plugins) add_subdirectory(${VIEWER_PREFIX}newview/statemachine) add_subdirectory(${VIEWER_PREFIX}newview) -add_dependencies(viewer ${VIEWER_BRANDING_ID}-bin) +add_dependencies(viewer ${VIEWER_BINARY_NAME}) + if (WINDOWS) - set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT ${VIEWER_BRANDING_ID}-bin) + set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + PROPERTY VS_STARTUP_PROJECT ${VIEWER_BINARY_NAME}) endif (WINDOWS) diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake index 6dddeed57..653c72412 100644 --- a/indra/cmake/00-Common.cmake +++ b/indra/cmake/00-Common.cmake @@ -39,9 +39,9 @@ if (WINDOWS) "${CMAKE_C_FLAGS_RELEASE} ${LL_C_FLAGS} /O2 /Zi /MD /MP /fp:fast" CACHE STRING "C compiler release options" FORCE) - if (WORD_SIZE EQUAL 32) + if (ADDRESS_SIZE EQUAL 32) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /LARGEADDRESSAWARE") - endif (WORD_SIZE EQUAL 32) + endif (ADDRESS_SIZE EQUAL 32) if (FULL_DEBUG_SYMS OR USE_CRASHPAD) set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /DEBUG:FULL") @@ -103,9 +103,9 @@ if (WINDOWS) ) endif (USE_LTO) - if (WORD_SIZE EQUAL 32) + if (ADDRESS_SIZE EQUAL 32) add_compile_options(/arch:SSE2) - endif (WORD_SIZE EQUAL 32) + endif (ADDRESS_SIZE EQUAL 32) if (NOT DISABLE_FATAL_WARNINGS) add_definitions(/WX) @@ -292,13 +292,13 @@ if (LINUX OR DARWIN) set(CMAKE_C_FLAGS "${UNIX_WARNINGS} ${CMAKE_C_FLAGS}") set(CMAKE_CXX_FLAGS "${UNIX_CXX_WARNINGS} ${CMAKE_CXX_FLAGS}") - if (WORD_SIZE EQUAL 32) + if (ADDRESS_SIZE EQUAL 32) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32") - elseif (WORD_SIZE EQUAL 64) + elseif (ADDRESS_SIZE EQUAL 64) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m64") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m64") - endif (WORD_SIZE EQUAL 32) + endif (ADDRESS_SIZE EQUAL 32) endif (LINUX OR DARWIN) diff --git a/indra/cmake/ConfigurePkgConfig.cmake b/indra/cmake/ConfigurePkgConfig.cmake index afbc36d63..a2d5b31e2 100644 --- a/indra/cmake/ConfigurePkgConfig.cmake +++ b/indra/cmake/ConfigurePkgConfig.cmake @@ -6,17 +6,17 @@ SET(DEBUG_PKG_CONFIG "YES") IF("$ENV{PKG_CONFIG_LIBDIR}" STREQUAL "") # Guess at architecture-specific system library paths. - if (WORD_SIZE EQUAL 32) + if (ADDRESS_SIZE EQUAL 32) SET(PKG_CONFIG_NO_MULTI_GUESS /usr/lib32 /usr/lib) SET(PKG_CONFIG_NO_MULTI_LOCAL_GUESS /usr/local/lib32 /usr/local/lib) SET(PKG_CONFIG_MULTI_GUESS /usr/lib/i386-linux-gnu) SET(PKG_CONFIG_MULTI_LOCAL_GUESS /usr/local/lib/i386-linux-gnu) - else (WORD_SIZE EQUAL 32) + else (ADDRESS_SIZE EQUAL 32) SET(PKG_CONFIG_NO_MULTI_GUESS /usr/lib64 /usr/lib) SET(PKG_CONFIG_NO_MULTI_LOCAL_GUESS /usr/local/lib64 /usr/local/lib) SET(PKG_CONFIG_MULTI_GUESS /usr/lib/x86_64-linux-gnu) SET(PKG_CONFIG_MULTI_LOCAL_GUESS /usr/local/lib/x86_64-linux-gnu) - endif (WORD_SIZE EQUAL 32) + endif (ADDRESS_SIZE EQUAL 32) # Use DPKG architecture, if available. IF (${DPKG_ARCH}) diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake index abe2a6f2a..00a9f33e9 100644 --- a/indra/cmake/Copy3rdPartyLibs.cmake +++ b/indra/cmake/Copy3rdPartyLibs.cmake @@ -13,10 +13,6 @@ include(LLCommon) # set up platform specific lists of files that need to be copied ################################################################### if(WINDOWS) - set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP TRUE) - set(CMAKE_INSTALL_UCRT_LIBRARIES TRUE) - include(InstallRequiredSystemLibrariesAL) - set(SHARED_LIB_STAGING_DIR_DEBUG "${SHARED_LIB_STAGING_DIR}/Debug") set(SHARED_LIB_STAGING_DIR_RELWITHDEBINFO "${SHARED_LIB_STAGING_DIR}/RelWithDebInfo") set(SHARED_LIB_STAGING_DIR_RELEASE "${SHARED_LIB_STAGING_DIR}/Release") @@ -82,39 +78,19 @@ if(WINDOWS) endif(ADDRESS_SIZE EQUAL 64) if(NOT DISABLE_TCMALLOC) - set(debug_files ${debug_files} libtcmalloc_minimal-debug.dll) - set(release_files ${release_files} libtcmalloc_minimal.dll) + list(APPEND debug_files libtcmalloc_minimal-debug.dll) + list(APPEND release_files libtcmalloc_minimal.dll) endif(NOT DISABLE_TCMALLOC) if(OPENAL) - set(debug_files ${debug_files} alut.dll OpenAL32.dll) - set(release_files ${release_files} alut.dll OpenAL32.dll) + list(APPEND debug_files alut.dll OpenAL32.dll) + list(APPEND release_files alut.dll OpenAL32.dll) endif(OPENAL) - if (FMODSTUDIO) - set(debug_files ${debug_files} fmodL.dll) - set(release_files ${release_files} fmod.dll) - endif (FMODSTUDIO) - - foreach(redistfullfile IN LISTS CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS) - get_filename_component(redistfilepath ${redistfullfile} DIRECTORY ) - get_filename_component(redistfilename ${redistfullfile} NAME) - copy_if_different( - ${redistfilepath} - "${SHARED_LIB_STAGING_DIR_RELEASE}" - out_targets - ${redistfilename} - ) - set(third_party_targets ${third_party_targets} ${out_targets}) - - copy_if_different( - ${redistfilepath} - "${SHARED_LIB_STAGING_DIR_RELWITHDEBINFO}" - out_targets - ${redistfilename} - ) - set(third_party_targets ${third_party_targets} ${out_targets}) - endforeach() + if (USE_FMODSTUDIO) + list(APPEND debug_files fmodL.dll) + list(APPEND release_files fmod.dll) + endif (USE_FMODSTUDIO) elseif(DARWIN) set(SHARED_LIB_STAGING_DIR_DEBUG "${SHARED_LIB_STAGING_DIR}/Debug/Resources") @@ -191,13 +167,13 @@ elseif(LINUX) ) if (USE_TCMALLOC) - set(release_files ${release_files} "libtcmalloc_minimal.so") + list(APPEND release_files "libtcmalloc_minimal.so") endif (USE_TCMALLOC) - if (FMODSTUDIO) - set(debug_files ${debug_files} "libfmodL.so") - set(release_files ${release_files} "libfmod.so") - endif (FMODSTUDIO) + if (USE_FMODSTUDIO) + list(APPEND debug_files "libfmodL.so") + list(APPEND release_files "libfmod.so") + endif (USE_FMODSTUDIO) else(WINDOWS) message(STATUS "WARNING: unrecognized platform for staging 3rd party libs, skipping...") diff --git a/indra/cmake/FMODSTUDIO.cmake b/indra/cmake/FMODSTUDIO.cmake index 2f8691c27..83ac0ac9c 100644 --- a/indra/cmake/FMODSTUDIO.cmake +++ b/indra/cmake/FMODSTUDIO.cmake @@ -1,7 +1,7 @@ # -*- cmake -*- include(Variables) -if (FMODSTUDIO) +if (USE_FMODSTUDIO) use_prebuilt_binary(fmodstudio) if(WINDOWS) set(lib_suffix .dll) @@ -31,7 +31,7 @@ if (FMODSTUDIO) ) set(FMODSTUDIO_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/fmodstudio) -endif(FMODSTUDIO) +endif(USE_FMODSTUDIO) if(FMOD_LIBRARY_RELEASE AND FMODSTUDIO_INCLUDE_DIR) set(FMOD ON) @@ -41,7 +41,7 @@ if(FMOD_LIBRARY_RELEASE AND FMODSTUDIO_INCLUDE_DIR) else (FMOD_LIBRARY_RELEASE AND FMODSTUDIO_INCLUDE_DIR) message(STATUS "No support for FMOD Studio audio (need to set FMODSTUDIO_SDK_DIR?)") set(FMOD OFF) - set(FMODSTUDIO OFF) + set(USE_FMODSTUDIO OFF) endif (FMOD_LIBRARY_RELEASE AND FMODSTUDIO_INCLUDE_DIR) if (FMOD) diff --git a/indra/cmake/GooglePerfTools.cmake b/indra/cmake/GooglePerfTools.cmake index 49ff3f5eb..d951bc55e 100644 --- a/indra/cmake/GooglePerfTools.cmake +++ b/indra/cmake/GooglePerfTools.cmake @@ -2,16 +2,16 @@ include(Prebuilt) -if(WORD_SIZE EQUAL 64) +if(ADDRESS_SIZE EQUAL 64) set(DISABLE_TCMALLOC TRUE) -endif(WORD_SIZE EQUAL 64) +endif(ADDRESS_SIZE EQUAL 64) if (STANDALONE) include(FindGooglePerfTools) else (STANDALONE) - if (LINUX OR WINDOWS AND NOT WORD_SIZE EQUAL 64) + if (LINUX OR WINDOWS AND NOT ADDRESS_SIZE EQUAL 64) use_prebuilt_binary(gperftools) - endif (LINUX OR WINDOWS AND NOT WORD_SIZE EQUAL 64) + endif (LINUX OR WINDOWS AND NOT ADDRESS_SIZE EQUAL 64) if (WINDOWS AND NOT DISABLE_TCMALLOC) set(TCMALLOC_LIBRARIES libtcmalloc_minimal.lib) set(TCMALLOC_LINKER_FLAGS "/INCLUDE:\"__tcmalloc\"") diff --git a/indra/cmake/InstallRequiredSystemLibrariesAL.cmake b/indra/cmake/InstallRequiredSystemLibrariesAL.cmake deleted file mode 100644 index 0498da38c..000000000 --- a/indra/cmake/InstallRequiredSystemLibrariesAL.cmake +++ /dev/null @@ -1,741 +0,0 @@ -# Distributed under the OSI-approved BSD 3-Clause License. See accompanying -# file Copyright.txt or https://cmake.org/licensing for details. - -#[=======================================================================[.rst: -InstallRequiredSystemLibraries ------------------------------- - -Include this module to search for compiler-provided system runtime -libraries and add install rules for them. Some optional variables -may be set prior to including the module to adjust behavior: - -``CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS`` - Specify additional runtime libraries that may not be detected. - After inclusion any detected libraries will be appended to this. - -``CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP`` - Set to TRUE to skip calling the :command:`install(PROGRAMS)` command to - allow the includer to specify its own install rule, using the value of - ``CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS`` to get the list of libraries. - -``CMAKE_INSTALL_DEBUG_LIBRARIES`` - Set to TRUE to install the debug runtime libraries when available - with MSVC tools. - -``CMAKE_INSTALL_DEBUG_LIBRARIES_ONLY`` - Set to TRUE to install only the debug runtime libraries with MSVC - tools even if the release runtime libraries are also available. - -``CMAKE_INSTALL_UCRT_LIBRARIES`` - Set to TRUE to install the Windows Universal CRT libraries for - app-local deployment (e.g. to Windows XP). This is meaningful - only with MSVC from Visual Studio 2015 or higher. - - One may set a ``CMAKE_WINDOWS_KITS_10_DIR`` *environment variable* - to an absolute path to tell CMake to look for Windows 10 SDKs in - a custom location. The specified directory is expected to contain - ``Redist/ucrt/DLLs/*`` directories. - -``CMAKE_INSTALL_MFC_LIBRARIES`` - Set to TRUE to install the MSVC MFC runtime libraries. - -``CMAKE_INSTALL_OPENMP_LIBRARIES`` - Set to TRUE to install the MSVC OpenMP runtime libraries - -``CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION`` - Specify the :command:`install(PROGRAMS)` command ``DESTINATION`` - option. If not specified, the default is ``bin`` on Windows - and ``lib`` elsewhere. - -``CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS`` - Set to TRUE to disable warnings about required library files that - do not exist. (For example, Visual Studio Express editions may - not provide the redistributable files.) - -``CMAKE_INSTALL_SYSTEM_RUNTIME_COMPONENT`` - Specify the :command:`install(PROGRAMS)` command ``COMPONENT`` - option. If not specified, no such option will be used. -#]=======================================================================] - -cmake_policy(PUSH) -cmake_policy(SET CMP0054 NEW) # if() quoted variables not dereferenced - -set(_IRSL_HAVE_Intel FALSE) -set(_IRSL_HAVE_MSVC FALSE) -foreach(LANG IN ITEMS C CXX Fortran) - if("${CMAKE_${LANG}_COMPILER_ID}" STREQUAL "Intel") - if(NOT _IRSL_HAVE_Intel) - get_filename_component(_Intel_basedir "${CMAKE_${LANG}_COMPILER}" PATH) - if(CMAKE_SIZEOF_VOID_P EQUAL 8) - set(_Intel_archdir intel64) - else() - set(_Intel_archdir x86) - endif() - set(_Intel_compiler_ver ${CMAKE_${LANG}_COMPILER_VERSION}) - if(WIN32) - get_filename_component(_Intel_redistdir "${_Intel_basedir}/../../redist/${_Intel_archdir}/compiler" ABSOLUTE) - elseif(APPLE) - get_filename_component(_Intel_redistdir "${_Intel_basedir}/../../compiler/lib" ABSOLUTE) - else() - if(EXISTS "${_Intel_basedir}/../lib/${_Intel_archdir}_lin") - get_filename_component(_Intel_redistdir "${_Intel_basedir}/../lib/${_Intel_archdir}" ABSOLUTE) - else() - get_filename_component(_Intel_redistdir "${_Intel_basedir}/../../compiler/lib/${_Intel_archdir}_lin" ABSOLUTE) - endif() - endif() - set(_IRSL_HAVE_Intel TRUE) - endif() - elseif("${CMAKE_${LANG}_COMPILER_ID}" STREQUAL "MSVC") - set(_IRSL_HAVE_MSVC TRUE) - endif() -endforeach() - -if(MSVC) - file(TO_CMAKE_PATH "$ENV{SYSTEMROOT}" SYSTEMROOT) - - if(CMAKE_CL_64) - if(MSVC_VERSION GREATER 1599) - # VS 10 and later: - set(CMAKE_MSVC_ARCH x64) - else() - # VS 9 and earlier: - set(CMAKE_MSVC_ARCH amd64) - endif() - else() - set(CMAKE_MSVC_ARCH x86) - endif() - - get_filename_component(devenv_dir "${CMAKE_MAKE_PROGRAM}" PATH) - get_filename_component(base_dir "${devenv_dir}/../.." ABSOLUTE) - - if(MSVC_VERSION EQUAL 1300) - set(__install__libs - "${SYSTEMROOT}/system32/msvcp70.dll" - "${SYSTEMROOT}/system32/msvcr70.dll" - ) - endif() - - if(MSVC_VERSION EQUAL 1310) - set(__install__libs - "${SYSTEMROOT}/system32/msvcp71.dll" - "${SYSTEMROOT}/system32/msvcr71.dll" - ) - endif() - - if(MSVC_TOOLSET_VERSION EQUAL 80) - # Find the runtime library redistribution directory. - get_filename_component(msvc_install_dir - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\8.0;InstallDir]" ABSOLUTE) - if(DEFINED MSVC80_REDIST_DIR AND EXISTS "${MSVC80_REDIST_DIR}") - set(MSVC_REDIST_DIR "${MSVC80_REDIST_DIR}") # use old cache entry - endif() - find_path(MSVC_REDIST_DIR NAMES ${CMAKE_MSVC_ARCH}/Microsoft.VC80.CRT/Microsoft.VC80.CRT.manifest - PATHS - "${msvc_install_dir}/../../VC/redist" - "${base_dir}/VC/redist" - ) - mark_as_advanced(MSVC_REDIST_DIR) - set(MSVC_CRT_DIR "${MSVC_REDIST_DIR}/${CMAKE_MSVC_ARCH}/Microsoft.VC80.CRT") - - # Install the manifest that allows DLLs to be loaded from the - # directory containing the executable. - if(NOT CMAKE_INSTALL_DEBUG_LIBRARIES_ONLY) - set(__install__libs - "${MSVC_CRT_DIR}/Microsoft.VC80.CRT.manifest" - "${MSVC_CRT_DIR}/msvcm80.dll" - "${MSVC_CRT_DIR}/msvcp80.dll" - "${MSVC_CRT_DIR}/msvcr80.dll" - ) - else() - set(__install__libs) - endif() - - if(CMAKE_INSTALL_DEBUG_LIBRARIES) - set(MSVC_CRT_DIR - "${MSVC_REDIST_DIR}/Debug_NonRedist/${CMAKE_MSVC_ARCH}/Microsoft.VC80.DebugCRT") - set(__install__libs ${__install__libs} - "${MSVC_CRT_DIR}/Microsoft.VC80.DebugCRT.manifest" - "${MSVC_CRT_DIR}/msvcm80d.dll" - "${MSVC_CRT_DIR}/msvcp80d.dll" - "${MSVC_CRT_DIR}/msvcr80d.dll" - ) - endif() - endif() - - if(MSVC_TOOLSET_VERSION EQUAL 90) - # Find the runtime library redistribution directory. - get_filename_component(msvc_install_dir - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\9.0;InstallDir]" ABSOLUTE) - get_filename_component(msvc_express_install_dir - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\9.0;InstallDir]" ABSOLUTE) - if(DEFINED MSVC90_REDIST_DIR AND EXISTS "${MSVC90_REDIST_DIR}") - set(MSVC_REDIST_DIR "${MSVC90_REDIST_DIR}") # use old cache entry - endif() - find_path(MSVC_REDIST_DIR NAMES ${CMAKE_MSVC_ARCH}/Microsoft.VC90.CRT/Microsoft.VC90.CRT.manifest - PATHS - "${msvc_install_dir}/../../VC/redist" - "${msvc_express_install_dir}/../../VC/redist" - "${base_dir}/VC/redist" - ) - mark_as_advanced(MSVC_REDIST_DIR) - set(MSVC_CRT_DIR "${MSVC_REDIST_DIR}/${CMAKE_MSVC_ARCH}/Microsoft.VC90.CRT") - - # Install the manifest that allows DLLs to be loaded from the - # directory containing the executable. - if(NOT CMAKE_INSTALL_DEBUG_LIBRARIES_ONLY) - set(__install__libs - "${MSVC_CRT_DIR}/Microsoft.VC90.CRT.manifest" - "${MSVC_CRT_DIR}/msvcm90.dll" - "${MSVC_CRT_DIR}/msvcp90.dll" - "${MSVC_CRT_DIR}/msvcr90.dll" - ) - else() - set(__install__libs) - endif() - - if(CMAKE_INSTALL_DEBUG_LIBRARIES) - set(MSVC_CRT_DIR - "${MSVC_REDIST_DIR}/Debug_NonRedist/${CMAKE_MSVC_ARCH}/Microsoft.VC90.DebugCRT") - set(__install__libs ${__install__libs} - "${MSVC_CRT_DIR}/Microsoft.VC90.DebugCRT.manifest" - "${MSVC_CRT_DIR}/msvcm90d.dll" - "${MSVC_CRT_DIR}/msvcp90d.dll" - "${MSVC_CRT_DIR}/msvcr90d.dll" - ) - endif() - endif() - - set(MSVC_REDIST_NAME "") - set(_MSVC_DLL_VERSION "") - set(_MSVC_IDE_VERSION "") - if(MSVC_VERSION GREATER_EQUAL 2000) - message(WARNING "MSVC ${MSVC_VERSION} not yet supported.") - elseif(MSVC_VERSION_VERSION GREATER_EQUAL 143) - message(WARNING "MSVC toolset v${MSVC_VERSION_VERSION} not yet supported.") - elseif(MSVC_TOOLSET_VERSION EQUAL 142) - set(MSVC_REDIST_NAME VC142) - set(_MSVC_DLL_VERSION 140) - set(_MSVC_IDE_VERSION 16) - if(MSVC_VERSION EQUAL 1920) - # VS2019 named this differently prior to update 1. - set(MSVC_REDIST_NAME VC141) - endif() - elseif(MSVC_TOOLSET_VERSION EQUAL 141) - set(MSVC_REDIST_NAME VC141) - set(_MSVC_DLL_VERSION 140) - set(_MSVC_IDE_VERSION 15) - if(MSVC_VERSION EQUAL 1910) - # VS2017 named this differently prior to update 3. - set(MSVC_REDIST_NAME VC150) - endif() - elseif(MSVC_TOOLSET_VERSION) - set(MSVC_REDIST_NAME VC${MSVC_TOOLSET_VERSION}) - math(EXPR _MSVC_DLL_VERSION "${MSVC_TOOLSET_VERSION} / 10 * 10") - math(EXPR _MSVC_IDE_VERSION "${MSVC_TOOLSET_VERSION} / 10") - endif() - - set(_MSVCRT_DLL_VERSION "") - set(_MSVCRT_IDE_VERSION "") - if(_MSVC_IDE_VERSION GREATER_EQUAL 10) - set(_MSVCRT_DLL_VERSION "${_MSVC_DLL_VERSION}") - set(_MSVCRT_IDE_VERSION "${_MSVC_IDE_VERSION}") - endif() - - if(_MSVCRT_DLL_VERSION) - set(v "${_MSVCRT_DLL_VERSION}") - set(vs "${_MSVCRT_IDE_VERSION}") - - # Find the runtime library redistribution directory. - if(vs VERSION_LESS 15 AND DEFINED MSVC${vs}_REDIST_DIR AND EXISTS "${MSVC${vs}_REDIST_DIR}") - set(MSVC_REDIST_DIR "${MSVC${vs}_REDIST_DIR}") # use old cache entry - endif() - if(NOT vs VERSION_LESS 15) - set(_vs_redist_paths "") - cmake_host_system_information(RESULT _vs_dir QUERY VS_${vs}_DIR) # undocumented query - if(IS_DIRECTORY "${_vs_dir}") - file(GLOB _vs_redist_paths "${_vs_dir}/VC/Redist/MSVC/*") - endif() - unset(_vs_dir) - else() - get_filename_component(_vs_dir - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\${vs}.0;InstallDir]" ABSOLUTE) - set(programfilesx86 "ProgramFiles(x86)") - set(_vs_redist_paths - "${_vs_dir}/../../VC/redist" - "${base_dir}/VC/redist" - "$ENV{ProgramFiles}/Microsoft Visual Studio ${vs}.0/VC/redist" - "$ENV{${programfilesx86}}/Microsoft Visual Studio ${vs}.0/VC/redist" - ) - unset(_vs_dir) - unset(programfilesx86) - endif() - find_path(MSVC_REDIST_DIR NAMES ${CMAKE_MSVC_ARCH}/Microsoft.${MSVC_REDIST_NAME}.CRT PATHS ${_vs_redist_paths}) - unset(_vs_redist_paths) - mark_as_advanced(MSVC_REDIST_DIR) - set(MSVC_CRT_DIR "${MSVC_REDIST_DIR}/${CMAKE_MSVC_ARCH}/Microsoft.${MSVC_REDIST_NAME}.CRT") - - if(NOT CMAKE_INSTALL_DEBUG_LIBRARIES_ONLY) - set(__install__libs - "${MSVC_CRT_DIR}/msvcp${v}.dll" - ) - if(NOT vs VERSION_LESS 14) - file(GLOB __msvcr_dlls "${MSVC_CRT_DIR}/*.dll") - list(APPEND __install__libs ${__msvcr_dlls}) - else() - list(APPEND __install__libs "${MSVC_CRT_DIR}/msvcr${v}.dll") - endif() - else() - set(__install__libs) - endif() - - if(CMAKE_INSTALL_DEBUG_LIBRARIES) - set(MSVC_CRT_DIR - "${MSVC_REDIST_DIR}/Debug_NonRedist/${CMAKE_MSVC_ARCH}/Microsoft.${MSVC_REDIST_NAME}.DebugCRT") - set(__install__libs ${__install__libs} - "${MSVC_CRT_DIR}/msvcp${v}d.dll" - ) - if(NOT vs VERSION_LESS 14) - list(APPEND __install__libs - "${MSVC_CRT_DIR}/vcruntime${v}d.dll" - "${MSVC_CRT_DIR}/concrt${v}d.dll" - ) - else() - list(APPEND __install__libs "${MSVC_CRT_DIR}/msvcr${v}d.dll") - endif() - endif() - - if(CMAKE_INSTALL_UCRT_LIBRARIES AND NOT vs VERSION_LESS 14) - # Find the Windows Kits directory. - get_filename_component(windows_kits_dir - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots;KitsRoot10]" ABSOLUTE) - set(programfilesx86 "ProgramFiles(x86)") - if(";${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION};$ENV{UCRTVersion};$ENV{WindowsSDKVersion};" MATCHES [=[;(10\.[0-9.]+)[;\]]=]) - set(__ucrt_version "${CMAKE_MATCH_1}/") - else() - set(__ucrt_version "") - endif() - find_path(WINDOWS_KITS_DIR - NAMES - Redist/${__ucrt_version}ucrt/DLLs/${CMAKE_MSVC_ARCH}/ucrtbase.dll - Redist/ucrt/DLLs/${CMAKE_MSVC_ARCH}/ucrtbase.dll - PATHS - $ENV{CMAKE_WINDOWS_KITS_10_DIR} - "${windows_kits_dir}" - "$ENV{ProgramFiles}/Windows Kits/10" - "$ENV{${programfilesx86}}/Windows Kits/10" - ) - mark_as_advanced(WINDOWS_KITS_DIR) - - # Glob the list of UCRT DLLs. - if(NOT CMAKE_INSTALL_DEBUG_LIBRARIES_ONLY) - if(EXISTS "${WINDOWS_KITS_DIR}/Redist/${__ucrt_version}ucrt/DLLs/${CMAKE_MSVC_ARCH}/ucrtbase.dll") - file(GLOB __ucrt_dlls "${WINDOWS_KITS_DIR}/Redist/${__ucrt_version}ucrt/DLLs/${CMAKE_MSVC_ARCH}/*.dll") - else() - file(GLOB __ucrt_dlls "${WINDOWS_KITS_DIR}/Redist/ucrt/DLLs/${CMAKE_MSVC_ARCH}/*.dll") - endif() - list(APPEND __install__libs ${__ucrt_dlls}) - endif() - if(CMAKE_INSTALL_DEBUG_LIBRARIES) - if(EXISTS "${WINDOWS_KITS_DIR}/bin/${__ucrt_version}${CMAKE_MSVC_ARCH}/ucrt/ucrtbased.dll") - file(GLOB __ucrt_dlls "${WINDOWS_KITS_DIR}/bin/${__ucrt_version}${CMAKE_MSVC_ARCH}/ucrt/*.dll") - else() - file(GLOB __ucrt_dlls "${WINDOWS_KITS_DIR}/bin/${CMAKE_MSVC_ARCH}/ucrt/*.dll") - endif() - list(APPEND __install__libs ${__ucrt_dlls}) - endif() - endif() - endif() - - if(CMAKE_INSTALL_MFC_LIBRARIES) - if(MSVC_VERSION EQUAL 1300) - set(__install__libs ${__install__libs} - "${SYSTEMROOT}/system32/mfc70.dll" - ) - endif() - - if(MSVC_VERSION EQUAL 1310) - set(__install__libs ${__install__libs} - "${SYSTEMROOT}/system32/mfc71.dll" - ) - endif() - - if(MSVC_VERSION EQUAL 1400) - if(CMAKE_INSTALL_DEBUG_LIBRARIES) - set(MSVC_MFC_DIR - "${MSVC_REDIST_DIR}/Debug_NonRedist/${CMAKE_MSVC_ARCH}/Microsoft.VC80.DebugMFC") - set(__install__libs ${__install__libs} - "${MSVC_MFC_DIR}/Microsoft.VC80.DebugMFC.manifest" - "${MSVC_MFC_DIR}/mfc80d.dll" - "${MSVC_MFC_DIR}/mfc80ud.dll" - "${MSVC_MFC_DIR}/mfcm80d.dll" - "${MSVC_MFC_DIR}/mfcm80ud.dll" - ) - endif() - - set(MSVC_MFC_DIR "${MSVC_REDIST_DIR}/${CMAKE_MSVC_ARCH}/Microsoft.VC80.MFC") - # Install the manifest that allows DLLs to be loaded from the - # directory containing the executable. - if(NOT CMAKE_INSTALL_DEBUG_LIBRARIES_ONLY) - set(__install__libs ${__install__libs} - "${MSVC_MFC_DIR}/Microsoft.VC80.MFC.manifest" - "${MSVC_MFC_DIR}/mfc80.dll" - "${MSVC_MFC_DIR}/mfc80u.dll" - "${MSVC_MFC_DIR}/mfcm80.dll" - "${MSVC_MFC_DIR}/mfcm80u.dll" - ) - endif() - - # include the language dll's for vs8 as well as the actual dll's - set(MSVC_MFCLOC_DIR "${MSVC_REDIST_DIR}/${CMAKE_MSVC_ARCH}/Microsoft.VC80.MFCLOC") - # Install the manifest that allows DLLs to be loaded from the - # directory containing the executable. - set(__install__libs ${__install__libs} - "${MSVC_MFCLOC_DIR}/Microsoft.VC80.MFCLOC.manifest" - "${MSVC_MFCLOC_DIR}/mfc80chs.dll" - "${MSVC_MFCLOC_DIR}/mfc80cht.dll" - "${MSVC_MFCLOC_DIR}/mfc80enu.dll" - "${MSVC_MFCLOC_DIR}/mfc80esp.dll" - "${MSVC_MFCLOC_DIR}/mfc80deu.dll" - "${MSVC_MFCLOC_DIR}/mfc80fra.dll" - "${MSVC_MFCLOC_DIR}/mfc80ita.dll" - "${MSVC_MFCLOC_DIR}/mfc80jpn.dll" - "${MSVC_MFCLOC_DIR}/mfc80kor.dll" - ) - endif() - - if(MSVC_VERSION EQUAL 1500) - if(CMAKE_INSTALL_DEBUG_LIBRARIES) - set(MSVC_MFC_DIR - "${MSVC_REDIST_DIR}/Debug_NonRedist/${CMAKE_MSVC_ARCH}/Microsoft.VC90.DebugMFC") - set(__install__libs ${__install__libs} - "${MSVC_MFC_DIR}/Microsoft.VC90.DebugMFC.manifest" - "${MSVC_MFC_DIR}/mfc90d.dll" - "${MSVC_MFC_DIR}/mfc90ud.dll" - "${MSVC_MFC_DIR}/mfcm90d.dll" - "${MSVC_MFC_DIR}/mfcm90ud.dll" - ) - endif() - - set(MSVC_MFC_DIR "${MSVC_REDIST_DIR}/${CMAKE_MSVC_ARCH}/Microsoft.VC90.MFC") - # Install the manifest that allows DLLs to be loaded from the - # directory containing the executable. - if(NOT CMAKE_INSTALL_DEBUG_LIBRARIES_ONLY) - set(__install__libs ${__install__libs} - "${MSVC_MFC_DIR}/Microsoft.VC90.MFC.manifest" - "${MSVC_MFC_DIR}/mfc90.dll" - "${MSVC_MFC_DIR}/mfc90u.dll" - "${MSVC_MFC_DIR}/mfcm90.dll" - "${MSVC_MFC_DIR}/mfcm90u.dll" - ) - endif() - - # include the language dll's for vs9 as well as the actual dll's - set(MSVC_MFCLOC_DIR "${MSVC_REDIST_DIR}/${CMAKE_MSVC_ARCH}/Microsoft.VC90.MFCLOC") - # Install the manifest that allows DLLs to be loaded from the - # directory containing the executable. - set(__install__libs ${__install__libs} - "${MSVC_MFCLOC_DIR}/Microsoft.VC90.MFCLOC.manifest" - "${MSVC_MFCLOC_DIR}/mfc90chs.dll" - "${MSVC_MFCLOC_DIR}/mfc90cht.dll" - "${MSVC_MFCLOC_DIR}/mfc90enu.dll" - "${MSVC_MFCLOC_DIR}/mfc90esp.dll" - "${MSVC_MFCLOC_DIR}/mfc90deu.dll" - "${MSVC_MFCLOC_DIR}/mfc90fra.dll" - "${MSVC_MFCLOC_DIR}/mfc90ita.dll" - "${MSVC_MFCLOC_DIR}/mfc90jpn.dll" - "${MSVC_MFCLOC_DIR}/mfc90kor.dll" - ) - endif() - - set(_MFC_DLL_VERSION "") - set(_MFC_IDE_VERSION "") - if(_MSVC_IDE_VERSION GREATER_EQUAL 10) - set(_MFC_DLL_VERSION ${_MSVC_DLL_VERSION}) - set(_MFC_IDE_VERSION ${_MSVC_IDE_VERSION}) - endif() - - if(_MFC_DLL_VERSION) - set(v "${_MFC_DLL_VERSION}") - set(vs "${_MFC_IDE_VERSION}") - - # Starting with VS 15 the MFC DLLs may be in a different directory. - if (NOT vs VERSION_LESS 15) - file(GLOB _MSVC_REDIST_DIRS "${MSVC_REDIST_DIR}/../*") - find_path(MSVC_REDIST_MFC_DIR NAMES ${CMAKE_MSVC_ARCH}/Microsoft.${MSVC_REDIST_NAME}.MFC - PATHS ${_MSVC_REDIST_DIRS} NO_DEFAULT_PATH) - mark_as_advanced(MSVC_REDIST_MFC_DIR) - unset(_MSVC_REDIST_DIRS) - else() - set(MSVC_REDIST_MFC_DIR "${MSVC_REDIST_DIR}") - endif() - - # Multi-Byte Character Set versions of MFC are available as optional - # addon since Visual Studio 12. So for version 12 or higher, check - # whether they are available and exclude them if they are not. - - if(CMAKE_INSTALL_DEBUG_LIBRARIES) - set(MSVC_MFC_DIR - "${MSVC_REDIST_MFC_DIR}/Debug_NonRedist/${CMAKE_MSVC_ARCH}/Microsoft.${MSVC_REDIST_NAME}.DebugMFC") - set(__install__libs ${__install__libs} - "${MSVC_MFC_DIR}/mfc${v}ud.dll" - "${MSVC_MFC_DIR}/mfcm${v}ud.dll" - ) - if("${v}" LESS 12 OR EXISTS "${MSVC_MFC_DIR}/mfc${v}d.dll") - set(__install__libs ${__install__libs} - "${MSVC_MFC_DIR}/mfc${v}d.dll" - ) - endif() - if("${v}" LESS 12 OR EXISTS "${MSVC_MFC_DIR}/mfcm${v}d.dll") - set(__install__libs ${__install__libs} - "${MSVC_MFC_DIR}/mfcm${v}d.dll" - ) - endif() - endif() - - set(MSVC_MFC_DIR "${MSVC_REDIST_MFC_DIR}/${CMAKE_MSVC_ARCH}/Microsoft.${MSVC_REDIST_NAME}.MFC") - if(NOT CMAKE_INSTALL_DEBUG_LIBRARIES_ONLY) - set(__install__libs ${__install__libs} - "${MSVC_MFC_DIR}/mfc${v}u.dll" - "${MSVC_MFC_DIR}/mfcm${v}u.dll" - ) - if("${v}" LESS 12 OR EXISTS "${MSVC_MFC_DIR}/mfc${v}.dll") - set(__install__libs ${__install__libs} - "${MSVC_MFC_DIR}/mfc${v}.dll" - ) - endif() - if("${v}" LESS 12 OR EXISTS "${MSVC_MFC_DIR}/mfcm${v}.dll") - set(__install__libs ${__install__libs} - "${MSVC_MFC_DIR}/mfcm${v}.dll" - ) - endif() - endif() - - # include the language dll's as well as the actual dll's - set(MSVC_MFCLOC_DIR "${MSVC_REDIST_MFC_DIR}/${CMAKE_MSVC_ARCH}/Microsoft.${MSVC_REDIST_NAME}.MFCLOC") - set(__install__libs ${__install__libs} - "${MSVC_MFCLOC_DIR}/mfc${v}chs.dll" - "${MSVC_MFCLOC_DIR}/mfc${v}cht.dll" - "${MSVC_MFCLOC_DIR}/mfc${v}deu.dll" - "${MSVC_MFCLOC_DIR}/mfc${v}enu.dll" - "${MSVC_MFCLOC_DIR}/mfc${v}esn.dll" - "${MSVC_MFCLOC_DIR}/mfc${v}fra.dll" - "${MSVC_MFCLOC_DIR}/mfc${v}ita.dll" - "${MSVC_MFCLOC_DIR}/mfc${v}jpn.dll" - "${MSVC_MFCLOC_DIR}/mfc${v}kor.dll" - "${MSVC_MFCLOC_DIR}/mfc${v}rus.dll" - ) - endif() - endif() - - # MSVC 8 was the first version with OpenMP - # Furthermore, there is no debug version of this - if(CMAKE_INSTALL_OPENMP_LIBRARIES AND _IRSL_HAVE_MSVC) - set(_MSOMP_DLL_VERSION ${_MSVC_DLL_VERSION}) - set(_MSOMP_IDE_VERSION ${_MSVC_IDE_VERSION}) - - if(_MSOMP_DLL_VERSION) - set(v "${_MSOMP_DLL_VERSION}") - set(vs "${_MSOMP_IDE_VERSION}") - set(MSVC_OPENMP_DIR "${MSVC_REDIST_DIR}/${CMAKE_MSVC_ARCH}/Microsoft.${MSVC_REDIST_NAME}.OPENMP") - - if(NOT CMAKE_INSTALL_DEBUG_LIBRARIES_ONLY) - set(__install__libs ${__install__libs} - "${MSVC_OPENMP_DIR}/vcomp${v}.dll") - endif() - endif() - endif() - - foreach(lib - ${__install__libs} - ) - if(EXISTS ${lib}) - set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS - ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS} ${lib}) - else() - if(NOT CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS) - message(WARNING "system runtime library file does not exist: '${lib}'") - # This warning indicates an incomplete Visual Studio installation - # or a bug somewhere above here in this file. - # If you would like to avoid this warning, fix the real problem, or - # set CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS before including - # this file. - endif() - endif() - endforeach() -endif() - -if(_IRSL_HAVE_Intel) - unset(__install_libs) - if(CMAKE_INSTALL_OPENMP_LIBRARIES) - if(WIN32) - list(APPEND __install_libs "${_Intel_redistdir}/libiomp5md.dll" "${_Intel_redistdir}/libiompstubs5md.dll") - elseif(APPLE) - list(APPEND __install_libs "${_Intel_redistdir}/libiomp5.dylib" "${_Intel_redistdir}/libiompstubs5.dylib") - else() - list(APPEND __install_libs "${_Intel_redistdir}/libiomp5.so" "${_Intel_redistdir}/libiompstubs5.so") - if(_Intel_compiler_ver VERSION_LESS 17) - list(APPEND __install_libs "${_Intel_redistdir}/libomp_db.so") - endif() - if(_Intel_compiler_ver VERSION_LESS 13) - list(APPEND __install_libs "${_Intel_redistdir}/libiompprof5.so") - endif() - endif() - endif() - if(WIN32) - set(__install_dirs "${_Intel_redistdir}/1033") - if(EXISTS "${_Intel_redistdir}/1041") - list(APPEND __install_dirs "${_Intel_redistdir}/1041") - endif() - if(_Intel_compiler_ver VERSION_LESS 18) - list(APPEND __install_dirs "${_Intel_redistdir}/irml" "${_Intel_redistdir}/irml_c") - endif() - foreach(__Intel_lib IN ITEMS cilkrts20.dll libchkp.dll libioffload_host.dll libirngmd.dll - libmmd.dll libmmdd.dll libmpx.dll liboffload.dll svml_dispmd.dll) - - list(APPEND __install_libs "${_Intel_redistdir}/${__Intel_lib}") - endforeach() - if(CMAKE_C_COMPILER_ID STREQUAL Intel OR CMAKE_CXX_COMPILER_ID STREQUAL Intel) - list(APPEND __install_libs "${_Intel_redistdir}/libgfxoffload.dll") - endif() - if(CMAKE_Fortran_COMPILER_ID STREQUAL Intel) - foreach(__Intel_lib IN ITEMS ifdlg100.dll libicaf.dll libifcoremd.dll libifcoremdd.dll libifcorert.dll libifcorertd.dll libifportmd.dll) - - list(APPEND __install_libs "${_Intel_redistdir}/${__Intel_lib}") - endforeach() - endif() - elseif(APPLE) - foreach(__Intel_lib IN ITEMS libchkp.dylib libcilkrts.5.dylib libcilkrts.dylib libimf.dylib libintlc.dylib libirc.dylib libirng.dylib libsvml.dylib) - list(APPEND __install_libs "${_Intel_redistdir}/${__Intel_lib}") - endforeach() - if(CMAKE_C_COMPILER_ID STREQUAL Intel OR CMAKE_CXX_COMPILER_ID STREQUAL Intel) - if(_Intel_compiler_ver VERSION_LESS 17) - list(APPEND __install_libs "${_Intel_redistdir}/libistrconv.dylib") - endif() - endif() - if(CMAKE_Fortran_COMPILER_ID STREQUAL Intel) - foreach(__Intel_lib IN ITEMS libifcore.dylib libifcoremt.dylib libifport.dylib libifportmt.dylib) - - list(APPEND __install_libs "${_Intel_redistdir}/${__Intel_lib}") - endforeach() - endif() - else() - foreach(__Intel_lib IN ITEMS libchkp.so libcilkrts.so libcilkrts.so.5 libimf.so libintlc.so libintlc.so.5 libirc.so libpdbx.so libpdbx.so.5 libsvml.so) - - list(APPEND __install_libs "${_Intel_redistdir}/${__Intel_lib}") - endforeach() - if(_Intel_compiler_ver VERSION_GREATER_EQUAL 13) - foreach(__Intel_lib IN ITEMS libirng.so liboffload.so liboffload.so.5) - - list(APPEND __install_libs "${_Intel_redistdir}/${__Intel_lib}") - endforeach() - endif() - if(CMAKE_C_COMPILER_ID STREQUAL Intel OR CMAKE_CXX_COMPILER_ID STREQUAL Intel) - set(__install_dirs "${_Intel_redistdir}/irml") - list(APPEND __install_libs "${_Intel_redistdir}/cilk_db.so") - if(_Intel_compiler_ver VERSION_GREATER_EQUAL 15) - list(APPEND __install_libs "${_Intel_redistdir}/libistrconv.so" "${_Intel_redistdir}/libgfxoffload.so") - endif() - endif() - if(_Intel_compiler_ver VERSION_GREATER_EQUAL 16) - foreach(__Intel_lib IN ITEMS libioffload_host.so libioffload_host.so.5 libioffload_target.so libioffload_target.so.5 libmpx.so offload_main) - - list(APPEND __install_libs "${_Intel_redistdir}/${__Intel_lib}") - endforeach() - endif() - if(_Intel_compiler_ver VERSION_LESS 15) - foreach(__Intel_lib IN ITEMS libcxaguard.so libcxaguard.so.5) - - list(APPEND __install_libs "${_Intel_redistdir}/${__Intel_lib}") - endforeach() - endif() - if(CMAKE_Fortran_COMPILER_ID STREQUAL Intel) - foreach(__Intel_lib IN ITEMS libicaf.so libifcore.so libifcore.so.5 libifcoremt.so libifcoremt.so.5 libifport.so libifport.so.5) - - list(APPEND __install_libs "${_Intel_redistdir}/${__Intel_lib}") - endforeach() - endif() - endif() - - foreach(lib IN LISTS __install_libs) - if(EXISTS ${lib}) - list(APPEND CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS ${lib}) - else() - if(NOT CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS) - message(WARNING "system runtime library file does not exist: '${lib}'") - endif() - endif() - endforeach() - - foreach(dir IN LISTS __install_dirs) - if(EXISTS ${dir}) - list(APPEND CMAKE_INSTALL_SYSTEM_RUNTIME_DIRECTORIES ${dir}) - else() - if(NOT CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS) - message(WARNING "system runtime library file does not exist: '${dir}'") - endif() - endif() - endforeach() -endif() - -if(WATCOM) - get_filename_component( CompilerPath ${CMAKE_C_COMPILER} PATH ) - if(CMAKE_C_COMPILER_VERSION) - set(_compiler_version ${CMAKE_C_COMPILER_VERSION}) - else() - set(_compiler_version ${CMAKE_CXX_COMPILER_VERSION}) - endif() - string(REGEX MATCHALL "[0-9]+" _watcom_version_list "${_compiler_version}") - list(GET _watcom_version_list 0 _watcom_major) - list(GET _watcom_version_list 1 _watcom_minor) - set( __install__libs - ${CompilerPath}/clbr${_watcom_major}${_watcom_minor}.dll - ${CompilerPath}/mt7r${_watcom_major}${_watcom_minor}.dll - ${CompilerPath}/plbr${_watcom_major}${_watcom_minor}.dll ) - foreach(lib - ${__install__libs} - ) - if(EXISTS ${lib}) - set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS - ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS} ${lib}) - else() - if(NOT CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS) - message(WARNING "system runtime library file does not exist: '${lib}'") - # This warning indicates an incomplete Watcom installation - # or a bug somewhere above here in this file. - # If you would like to avoid this warning, fix the real problem, or - # set CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS before including - # this file. - endif() - endif() - endforeach() -endif() - - -# Include system runtime libraries in the installation if any are -# specified by CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS. -if(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS) - if(NOT CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP) - if(NOT CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION) - if(WIN32) - set(CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION bin) - else() - set(CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION lib) - endif() - endif() - if(CMAKE_INSTALL_SYSTEM_RUNTIME_COMPONENT) - set(_CMAKE_INSTALL_SYSTEM_RUNTIME_COMPONENT - COMPONENT ${CMAKE_INSTALL_SYSTEM_RUNTIME_COMPONENT}) - endif() - install(PROGRAMS ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS} - DESTINATION ${CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION} - ${_CMAKE_INSTALL_SYSTEM_RUNTIME_COMPONENT} - ) - - install(DIRECTORY ${CMAKE_INSTALL_SYSTEM_RUNTIME_DIRECTORIES} - DESTINATION ${CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION} - ${_CMAKE_INSTALL_SYSTEM_RUNTIME_COMPONENT} - ) - endif() -endif() - -cmake_policy(POP) diff --git a/indra/cmake/LLCommon.cmake b/indra/cmake/LLCommon.cmake index 6cc325495..169ba4eb6 100644 --- a/indra/cmake/LLCommon.cmake +++ b/indra/cmake/LLCommon.cmake @@ -10,7 +10,6 @@ if (DARWIN) find_library(CORESERVICES_LIBRARY CoreServices) endif (DARWIN) - set(LLCOMMON_INCLUDE_DIRS ${LIBS_OPEN_DIR}/cwdebug ${LIBS_OPEN_DIR}/llcommon @@ -19,14 +18,7 @@ set(LLCOMMON_INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ) -if (LINUX) - # In order to support using ld.gold on linux, we need to explicitely - # specify all libraries that llcommon uses. - # llcommon uses `clock_gettime' which is provided by librt on linux. - set(LLCOMMON_LIBRARIES llcommon rt) -else (LINUX) - set(LLCOMMON_LIBRARIES llcommon) -endif (LINUX) +set(LLCOMMON_LIBRARIES llcommon) set(LLCOMMON_LINK_SHARED OFF CACHE BOOL "Build the llcommon target as a shared library.") if(LLCOMMON_LINK_SHARED) diff --git a/indra/cmake/LLPlugin.cmake b/indra/cmake/LLPlugin.cmake index 399cb332d..9722f16c3 100644 --- a/indra/cmake/LLPlugin.cmake +++ b/indra/cmake/LLPlugin.cmake @@ -5,10 +5,4 @@ set(LLPLUGIN_INCLUDE_DIRS ${LIBS_OPEN_DIR}/llplugin ) -if (LINUX) - # In order to support using ld.gold on linux, we need to explicitely - # specify all libraries that llplugin uses. - set(LLPLUGIN_LIBRARIES llplugin pthread) -else (LINUX) - set(LLPLUGIN_LIBRARIES llplugin) -endif (LINUX) +set(LLPLUGIN_LIBRARIES llplugin) diff --git a/indra/cmake/NVAPI.cmake b/indra/cmake/NVAPI.cmake index 080d8fcf7..3cdf5ca47 100644 --- a/indra/cmake/NVAPI.cmake +++ b/indra/cmake/NVAPI.cmake @@ -2,18 +2,18 @@ include(Prebuilt) include(Variables) -if (NVAPI) +if (USE_NVAPI) if (WINDOWS) use_prebuilt_binary(nvapi) - if (WORD_SIZE EQUAL 32) + if (ADDRESS_SIZE EQUAL 32) set(NVAPI_LIBRARY nvapi) - elseif (WORD_SIZE EQUAL 64) + elseif (ADDRESS_SIZE EQUAL 64) set(NVAPI_LIBRARY nvapi64) - endif (WORD_SIZE EQUAL 32) + endif (ADDRESS_SIZE EQUAL 32) else (WINDOWS) set(NVAPI_LIBRARY "") endif (WINDOWS) -else (NVAPI) +else (USE_NVAPI) set(NVAPI_LIBRARY "") -endif (NVAPI) +endif (USE_NVAPI) diff --git a/indra/cmake/Variables.cmake b/indra/cmake/Variables.cmake index 51e10a09a..b1afa31e2 100644 --- a/indra/cmake/Variables.cmake +++ b/indra/cmake/Variables.cmake @@ -17,6 +17,14 @@ if(NOT DEFINED COMMON_CMAKE_DIR) set(COMMON_CMAKE_DIR "${CMAKE_SOURCE_DIR}/cmake") endif(NOT DEFINED COMMON_CMAKE_DIR) +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# https://blog.kitware.com/upcoming-in-cmake-2-8-12-osx-rpath-support/ +set(CMAKE_MACOSX_RPATH ON) +set(CMAKE_BUILD_WITH_INSTALL_RPATH ON) +set(CMAKE_INSTALL_RPATH_USE_LINK_PATH OFF) + set_property(GLOBAL PROPERTY USE_FOLDERS ON) get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) @@ -28,23 +36,40 @@ set(LIBS_OPEN_PREFIX) set(SCRIPTS_PREFIX ../scripts) set(VIEWER_PREFIX) set(INTEGRATION_TESTS_PREFIX) + option(LL_TESTS "Build and run unit and integration tests (disable for build timing runs to reduce variation" OFF) option(BUILD_TESTING "Build test suite" OFF) +option(UNATTENDED "Disable use of uneeded tooling for automated builds" OFF) +# Compiler and toolchain options +option(USESYSTEMLIBS "Use libraries from your system rather than Linden-supplied prebuilt libraries." OFF) +option(STANDALONE "Use libraries from your system rather than Linden-supplied prebuilt libraries." OFF) +if (USESYSTEMLIBS) + set(STANDALONE ON) +elseif (STANDALONE) + set(USESYSTEMLIBS ON) +endif (USESYSTEMLIBS) option(INCREMENTAL_LINK "Use incremental linking on win32 builds (enable for faster links on some machines)" OFF) option(USE_PRECOMPILED_HEADERS "Enable use of precompiled header directives where supported." ON) -option(USE_LTO "Enable Whole Program Optimization and related folding and binary reduction routines" OFF) -option(UNATTENDED "Disable use of uneeded tooling for automated builds" OFF) +option(USE_LTO "Enable global and interprocedural optimizations" OFF) # Configure crash reporting option(USE_CRASHPAD "Build support for crashpad reporting engine" OFF) -set(CRASHPAD_URL "" CACHE STRING "Crashpad endpoint url") +if (DEFINED ENV{VIEWER_USE_CRASHPAD}) + set(USE_CRASHPAD $ENV{VIEWER_USE_CRASHPAD}) +endif() + +if (DEFINED ENV{VIEWER_CRASHPAD_URL}) + set(CRASHPAD_URL $ENV{VIEWER_CRASHPAD_URL} CACHE STRING "Viewer Channel Base Name") +else() + set(CRASHPAD_URL "" CACHE STRING "Crashpad endpoint url") +endif() + set(VIEWER_SYMBOL_FILE "" CACHE STRING "Name of tarball into which to place symbol files") # Media Plugins option(ENABLE_MEDIA_PLUGINS "Turn off building media plugins if they are imported by third-party library mechanism" ON) option(LIBVLCPLUGIN "Turn off building support for libvlc plugin" ON) - if (${CMAKE_SYSTEM_NAME} MATCHES "Linux" OR ${CMAKE_SYSTEM_NAME} MATCHES "Darwin") set(LIBVLCPLUGIN OFF) endif (${CMAKE_SYSTEM_NAME} MATCHES "Linux" OR ${CMAKE_SYSTEM_NAME} MATCHES "Darwin") @@ -54,13 +79,11 @@ set(DISABLE_TCMALLOC OFF CACHE BOOL "Disable linkage of TCMalloc. (64bit builds set(DISABLE_FATAL_WARNINGS TRUE CACHE BOOL "Set this to FALSE to enable fatal warnings.") # Audio Engines -option(FMODSTUDIO "Build with support for the FMOD Studio audio engine" ON) - -# Window implementation -option(LLWINDOW_SDL2 "Use SDL2 for window and input handling" OFF) +option(USE_FMODSTUDIO "Build with support for the FMOD Studio audio engine" OFF) # Proprietary Library Features -option(NVAPI "Use nvapi driver interface library" OFF) +option(USE_NVAPI "Use nvapi driver interface library" OFF) + if(LIBS_CLOSED_DIR) file(TO_CMAKE_PATH "${LIBS_CLOSED_DIR}" LIBS_CLOSED_DIR) @@ -87,7 +110,7 @@ if (EXISTS ${CMAKE_SOURCE_DIR}/Server.cmake) set(INSTALL_PROPRIETARY ON CACHE BOOL "Install proprietary binaries") endif (EXISTS ${CMAKE_SOURCE_DIR}/Server.cmake) set(TEMPLATE_VERIFIER_OPTIONS "" CACHE STRING "Options for scripts/template_verifier.py") -set(TEMPLATE_VERIFIER_MASTER_URL "https://forge.alchemyviewer.org/alchemy/tools/Master-Message-Template/raw/master/message_template.msg" CACHE STRING "Location of the master message template") +set(TEMPLATE_VERIFIER_MASTER_URL "https://git.alchemyviewer.org/alchemy/master-message-template/raw/master/message_template.msg" CACHE STRING "Location of the master message template") if (NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING @@ -96,7 +119,6 @@ endif (NOT CMAKE_BUILD_TYPE) # If someone has specified an address size, use that to determine the # architecture. Otherwise, let the architecture specify the address size. -set(ADDRESS_SIZE ${WORD_SIZE}) if (ADDRESS_SIZE EQUAL 32) #message(STATUS "ADDRESS_SIZE is 32") set(ARCH i686) @@ -160,7 +182,7 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") endif (${CMAKE_SYSTEM_NAME} MATCHES "Linux") if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - set(DARWIN 1) + set(DARWIN ON BOOL FORCE) # Architecture set(CMAKE_OSX_SYSROOT macosx10.14) @@ -200,57 +222,60 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") set(LL_ARCH_DIR universal-darwin) endif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") +# Platform specific +if (WINDOWS) + option(LLWINDOW_SDL2 "Use SDL2 for window and input handling. Windows only" OFF) +endif() + # Default deploy grid set(GRID agni CACHE STRING "Target Grid") -set(VIEWER_PRODUCT_NAME "Singularity" CACHE STRING "Viewer Base Name") -string(TOLOWER ${VIEWER_PRODUCT_NAME} VIEWER_PRODUCT_NAME_LOWER) +if (DEFINED ENV{VIEWER_CHANNEL_BASE}) + set(VIEWER_CHANNEL_BASE $ENV{VIEWER_CHANNEL_BASE} CACHE STRING "Viewer Channel Base Name" FORCE) +else() + set(VIEWER_CHANNEL_BASE "Singularity" CACHE STRING "Viewer Channel Base Name") +endif() + +if (DEFINED ENV{VIEWER_CHANNEL_TYPE}) + set(VIEWER_CHANNEL_TYPE $ENV{VIEWER_CHANNEL_TYPE} CACHE STRING "Viewer Channel Type Name" FORCE) +else() + set(VIEWER_CHANNEL_TYPE "Test" CACHE STRING "Viewer Channel Type Name") +endif() + +if (DEFINED ENV{VIEWER_CHANNEL_CODENAME}) + set(VIEWER_CHANNEL_CODENAME $ENV{VIEWER_CHANNEL_CODENAME} CACHE STRING "Viewer Channel Code Name for Project type" FORCE) +else() + set(VIEWER_CHANNEL_CODENAME "Default" CACHE STRING "Viewer Channel Code Name for Project type") +endif() + +if("${VIEWER_CHANNEL_TYPE}" STREQUAL "Project") + set(VIEWER_CHANNEL "${VIEWER_CHANNEL_BASE} ${VIEWER_CHANNEL_TYPE} ${VIEWER_CHANNEL_CODENAME}") +else() + set(VIEWER_CHANNEL "${VIEWER_CHANNEL_BASE} ${VIEWER_CHANNEL_TYPE}") +endif() + +string(TOLOWER "${VIEWER_CHANNEL_BASE}" VIEWER_BRANDING_ID) +string(REPLACE " " "-" VIEWER_BRANDING_ID ${VIEWER_BRANDING_ID}) +set(VIEWER_BINARY_NAME "${VIEWER_BRANDING_ID}-bin" CACHE STRING + "The name of the viewer executable to create.") -set(VIEWER_CHANNEL_BASE "Test" CACHE STRING "Viewer Channel Name") -set(VIEWER_CHANNEL "${VIEWER_PRODUCT_NAME} ${VIEWER_CHANNEL_BASE}") -string(TOLOWER ${VIEWER_CHANNEL} VIEWER_CHANNEL_LOWER) string(REPLACE " " "" VIEWER_CHANNEL_ONEWORD ${VIEWER_CHANNEL}) +set(VIEWER_CHANNEL_NOSPACE ${VIEWER_CHANNEL_ONEWORD} CACHE STRING "Prefix used for resulting artifacts.") option(VIEWER_CHANNEL_GRK "Greek character(s) to represent the viewer channel for support purposes, override only for special branches" "") if (NOT VIEWER_CHANNEL_GRK) - if (VIEWER_CHANNEL_BASE MATCHES "Test") - set(VIEWER_CHANNEL_GRK "\\u03C4") # "τ" - elseif (VIEWER_CHANNEL_BASE MATCHES "Alpha") - set(VIEWER_CHANNEL_GRK "\\u03B1") # "α" - elseif (VIEWER_CHANNEL_BASE MATCHES "Beta") - set(VIEWER_CHANNEL_GRK "\\u03B2") # "β" - endif () + if (VIEWER_CHANNEL_TYPE MATCHES "Test") + set(VIEWER_CHANNEL_GRK "\\u03C4") # "τ" + elseif (VIEWER_CHANNEL_TYPE MATCHES "Alpha") + set(VIEWER_CHANNEL_GRK "\\u03B1") # "α" + elseif (VIEWER_CHANNEL_TYPE MATCHES "Beta") + set(VIEWER_CHANNEL_GRK "\\u03B2") # "β" + endif () endif (NOT VIEWER_CHANNEL_GRK) -if(VIEWER_CHANNEL_LOWER MATCHES "^${VIEWER_PRODUCT_NAME_LOWER} release") - set(VIEWER_PACKAGE_ID "${VIEWER_PRODUCT_NAME}Release") - set(VIEWER_EXE_STRING "${VIEWER_PRODUCT_NAME}Viewer") - set(VIEWER_SHORTCUT_STRING "${VIEWER_PRODUCT_NAME} Viewer") -else() - set(VIEWER_PACKAGE_ID ${VIEWER_CHANNEL_ONEWORD}) - set(VIEWER_EXE_STRING ${VIEWER_CHANNEL_ONEWORD}) - set(VIEWER_SHORTCUT_STRING ${VIEWER_CHANNEL}) -endif() - -set(VIEWER_CHANNEL_NOSPACE ${VIEWER_CHANNEL_ONEWORD} CACHE STRING "Prefix used for resulting artifacts.") - -set(VIEWER_BRANDING_ID "singularity" CACHE STRING "Viewer branding id") - option(ENABLE_SIGNING "Enable signing the viewer" OFF) set(SIGNING_IDENTITY "" CACHE STRING "Specifies the signing identity to use, if necessary.") -set(VERSION_BUILD "0" CACHE STRING "Revision number passed in from the outside") -# Compiler and toolchain options -option(USESYSTEMLIBS "Use libraries from your system rather than Linden-supplied prebuilt libraries." OFF) -option(STANDALONE "Use libraries from your system rather than Linden-supplied prebuilt libraries." OFF) -if (USESYSTEMLIBS) - set(STANDALONE ON) -elseif (STANDALONE) - set(USESYSTEMLIBS ON) -endif (USESYSTEMLIBS) - - - source_group("CMake Rules" FILES CMakeLists.txt) endif(NOT DEFINED ${CMAKE_CURRENT_LIST_FILE}_INCLUDED) diff --git a/indra/deps/CMakeLists.txt b/indra/deps/CMakeLists.txt index 47b676d2c..fb2ed3050 100644 --- a/indra/deps/CMakeLists.txt +++ b/indra/deps/CMakeLists.txt @@ -3,21 +3,22 @@ project(deps) include(FetchContent) set(CMAKE_FOLDER "Third Party") +set(CMAKE_POSITION_INDEPENDENT_CODE ON) FetchContent_Declare( Catch2 GIT_REPOSITORY https://github.com/catchorg/Catch2.git - GIT_TAG v2.10.0 + GIT_TAG v2.11.0 ) FetchContent_Declare( fmt GIT_REPOSITORY https://github.com/fmtlib/fmt.git - GIT_TAG 7512a55aa3ae309587ca89668ef9ec4074a51a1f + GIT_TAG 6.1.2 ) FetchContent_Declare( absl GIT_REPOSITORY https://github.com/abseil/abseil-cpp.git - GIT_TAG ab3552a18964e7063c8324f45b3896a6a20b08a8 + GIT_TAG 29235139149790f5afc430c11cec8f1eb1677607 ) # This is a hack because absl has dumb cmake @@ -43,4 +44,5 @@ if(WINDOWS) FetchContent_MakeAvailable(fmt) endif() -set(CMAKE_FOLDER "") +unset(CMAKE_FOLDER) +unset(CMAKE_POSITION_INDEPENDENT_CODE) diff --git a/indra/llappearance/llwearabletype.h b/indra/llappearance/llwearabletype.h index 6dec79fcb..ec946d5ad 100644 --- a/indra/llappearance/llwearabletype.h +++ b/indra/llappearance/llwearabletype.h @@ -58,6 +58,7 @@ public: WT_UNKNOWN = 17, // Singu note: used for corrupt wearables that do not have their type set in the inventory database. // While all the above values are serialized and stored in the database, this value is local only: // When a new item with value 17 is added by upstream, just increase this value to 18 (and WT_COUNT to 19). + // Keep WT_UNKNOWN and WT_COUNT in sync with llinventory.cpp WT_COUNT = 18, WT_INVALID = 255, diff --git a/indra/llaudio/CMakeLists.txt b/indra/llaudio/CMakeLists.txt index 20456f5dc..92aa14ddc 100644 --- a/indra/llaudio/CMakeLists.txt +++ b/indra/llaudio/CMakeLists.txt @@ -43,7 +43,7 @@ set(llaudio_HEADER_FILES llwindgen.h ) -if (FMODSTUDIO) +if (USE_FMODSTUDIO) include_directories( ${FMODSTUDIO_INCLUDE_DIR} ) @@ -58,7 +58,7 @@ if (FMODSTUDIO) lllistener_fmodstudio.h llstreamingaudio_fmodstudio.h ) -endif (FMODSTUDIO) +endif (USE_FMODSTUDIO) if (OPENAL) list(APPEND llaudio_SOURCE_FILES diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index cae62271d..9baf87d9d 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -269,12 +269,6 @@ list(APPEND llcommon_SOURCE_FILES ${cwdebug_SOURCE_FILES}) list(APPEND llcommon_SOURCE_FILES ${llcommon_HEADER_FILES}) -if(NOT WORD_SIZE EQUAL 32) - if(NOT WINDOWS) - add_definitions(-fPIC) - endif(NOT WINDOWS) -endif(NOT WORD_SIZE EQUAL 32) - if(LLCOMMON_LINK_SHARED) add_library (llcommon SHARED ${llcommon_SOURCE_FILES}) if(WINDOWS) @@ -286,6 +280,8 @@ else(LLCOMMON_LINK_SHARED) add_library (llcommon ${llcommon_SOURCE_FILES}) endif(LLCOMMON_LINK_SHARED) +set_target_properties(llcommon PROPERTIES POSITION_INDEPENDENT_CODE TRUE) + target_link_libraries( llcommon PUBLIC @@ -304,6 +300,7 @@ target_link_libraries( ${Boost_SYSTEM_LIBRARY} ${CORESERVICES_LIBRARY} ${URIPARSER_LIBRARY} + ${RT_LIBRARY} ) if (DARWIN) diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp index 3cb14a2ca..f6c58513b 100644 --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -1338,7 +1338,7 @@ namespace LLError } #if LL_WINDOWS - // VC80 was optimizing the error away. + // MSVC is optimizing the error away. #pragma optimize("", off) #endif void crashAndLoop(const std::string& message) @@ -1347,9 +1347,8 @@ namespace LLError DoutFatal(dc::core, message); #else // Now, we go kaboom! - int* make_me_crash = NULL; - - *make_me_crash = 0; + int* make_me_crash = nullptr; + *make_me_crash = 0xDEADBEEF; while(true) { diff --git a/indra/llcommon/llfile.cpp b/indra/llcommon/llfile.cpp index e68ccd2ad..0b7677fad 100644 --- a/indra/llcommon/llfile.cpp +++ b/indra/llcommon/llfile.cpp @@ -282,6 +282,11 @@ int LLFile::rename_nowarn(const std::string& filename, const std::string& newnam int rc = _wrename(utf16filename.c_str(),utf16newname.c_str()); #else int rc = ::rename(filename.c_str(),newname.c_str()); + if (rc == -1 && errno == EXDEV) + { + rc = std::system(("mv '" + filename + "' '" + newname + '\'').data()); + errno = 0; + } #endif return rc; } diff --git a/indra/llcommon/llsd.cpp b/indra/llcommon/llsd.cpp index 3883b7e8e..73a0ab3e7 100644 --- a/indra/llcommon/llsd.cpp +++ b/indra/llcommon/llsd.cpp @@ -126,9 +126,9 @@ public: virtual Date asDate() const { return LLDate(); } virtual URI asURI() const { return LLURI(); } virtual const Binary& asBinary() const { static const std::vector empty; return empty; } - - virtual const String& asStringRef() const { static const std::string empty; return empty; } + virtual const String& asStringRef() const { static const std::string empty; return empty; } + virtual bool has(const String&) const { return false; } virtual LLSD get(const String&) const { return LLSD(); } virtual LLSD getKeys() const { return LLSD::emptyArray(); } @@ -142,11 +142,11 @@ public: virtual const std::map& map() const { static const std::map empty; return empty; } virtual std::map& map() { static std::map empty; return empty; } - LLSD::map_const_iterator beginMap() const { return endMap(); } + LLSD::map_const_iterator beginMap() const { return map().begin(); } LLSD::map_const_iterator endMap() const { return map().end(); } virtual const std::vector& array() const { static const std::vector empty; return empty; } virtual std::vector& array() { static std::vector empty; return empty; } - LLSD::array_const_iterator beginArray() const { return endArray(); } + LLSD::array_const_iterator beginArray() const { return array().begin(); } LLSD::array_const_iterator endArray() const { return array().end(); } virtual void dumpStats() const; @@ -187,10 +187,11 @@ namespace public: ImplBase(DataRef value) : mValue(value) { } - virtual LLSD::Type type() const { return T; } + LLSD::Type type() const override { return T; } using LLSD::Impl::assign; // Unhiding base class virtuals... - virtual void assign(LLSD::Impl*& var, DataRef value) { + void assign(LLSD::Impl*& var, DataRef value) override + { if (shared()) { Impl::assign(var, value); @@ -203,16 +204,16 @@ namespace }; - class ImplBoolean + class ImplBoolean final : public ImplBase { public: ImplBoolean(LLSD::Boolean v) : Base(v) { } - virtual LLSD::Boolean asBoolean() const { return mValue; } - virtual LLSD::Integer asInteger() const { return mValue ? 1 : 0; } - virtual LLSD::Real asReal() const { return mValue ? 1 : 0; } - virtual LLSD::String asString() const; + LLSD::Boolean asBoolean() const override { return mValue; } + LLSD::Integer asInteger() const override { return mValue ? 1 : 0; } + LLSD::Real asReal() const override { return mValue ? 1 : 0; } + LLSD::String asString() const override; }; LLSD::String ImplBoolean::asString() const @@ -224,32 +225,32 @@ namespace { return mValue ? "true" : ""; } - class ImplInteger + class ImplInteger final : public ImplBase { public: ImplInteger(LLSD::Integer v) : Base(v) { } - virtual LLSD::Boolean asBoolean() const { return mValue != 0; } - virtual LLSD::Integer asInteger() const { return mValue; } - virtual LLSD::Real asReal() const { return mValue; } - virtual LLSD::String asString() const; + LLSD::Boolean asBoolean() const override { return mValue != 0; } + LLSD::Integer asInteger() const override { return mValue; } + LLSD::Real asReal() const override { return mValue; } + LLSD::String asString() const override; }; LLSD::String ImplInteger::asString() const { return llformat("%d", mValue); } - class ImplReal + class ImplReal final : public ImplBase { public: ImplReal(LLSD::Real v) : Base(v) { } - virtual LLSD::Boolean asBoolean() const; - virtual LLSD::Integer asInteger() const; - virtual LLSD::Real asReal() const { return mValue; } - virtual LLSD::String asString() const; + LLSD::Boolean asBoolean() const override; + LLSD::Integer asInteger() const override; + LLSD::Real asReal() const override { return mValue; } + LLSD::String asString() const override; }; LLSD::Boolean ImplReal::asBoolean() const @@ -262,21 +263,21 @@ namespace { return llformat("%lg", mValue); } - class ImplString + class ImplString final : public ImplBase { public: ImplString(const LLSD::String& v) : Base(v) { } - virtual LLSD::Boolean asBoolean() const { return !mValue.empty(); } - virtual LLSD::Integer asInteger() const; - virtual LLSD::Real asReal() const; - virtual LLSD::String asString() const { return mValue; } - virtual LLSD::UUID asUUID() const { return LLUUID(mValue); } - virtual LLSD::Date asDate() const { return LLDate(mValue); } - virtual LLSD::URI asURI() const { return LLURI(mValue); } - virtual int size() const { return mValue.size(); } - virtual const LLSD::String& asStringRef() const { return mValue; } + LLSD::Boolean asBoolean() const override { return !mValue.empty(); } + LLSD::Integer asInteger() const override; + LLSD::Real asReal() const override; + LLSD::String asString() const override { return mValue; } + LLSD::UUID asUUID() const override { return LLUUID(mValue); } + LLSD::Date asDate() const override { return LLDate(mValue); } + LLSD::URI asURI() const override { return LLURI(mValue); } + int size() const override { return mValue.size(); } + const LLSD::String& asStringRef() const override { return mValue; } }; LLSD::Integer ImplString::asInteger() const @@ -306,18 +307,18 @@ namespace } - class ImplUUID + class ImplUUID final : public ImplBase { public: ImplUUID(const LLSD::UUID& v) : Base(v) { } - virtual LLSD::String asString() const{ return mValue.asString(); } - virtual LLSD::UUID asUUID() const { return mValue; } + LLSD::String asString() const override { return mValue.asString(); } + LLSD::UUID asUUID() const override { return mValue; } }; - class ImplDate + class ImplDate final : public ImplBase { public: @@ -325,41 +326,42 @@ namespace : ImplBase(v) { } - virtual LLSD::Integer asInteger() const + LLSD::Integer asInteger() const override { return (LLSD::Integer)(mValue.secondsSinceEpoch()); } - virtual LLSD::Real asReal() const + LLSD::Real asReal() const override { return mValue.secondsSinceEpoch(); } - virtual LLSD::String asString() const{ return mValue.asString(); } - virtual LLSD::Date asDate() const { return mValue; } + + LLSD::String asString() const override { return mValue.asString(); } + LLSD::Date asDate() const override { return mValue; } }; - class ImplURI + class ImplURI final : public ImplBase { public: ImplURI(const LLSD::URI& v) : Base(v) { } - virtual LLSD::String asString() const{ return mValue.asString(); } - virtual LLSD::URI asURI() const { return mValue; } + LLSD::String asString() const override { return mValue.asString(); } + LLSD::URI asURI() const override { return mValue; } }; - class ImplBinary + class ImplBinary final : public ImplBase { public: ImplBinary(const LLSD::Binary& v) : Base(v) { } - virtual const LLSD::Binary& asBinary() const{ return mValue; } + const LLSD::Binary& asBinary() const override { return mValue; } }; - class ImplMap : public LLSD::Impl + class ImplMap final : public LLSD::Impl { private: typedef std::map DataMap; @@ -372,31 +374,31 @@ namespace public: ImplMap() { } - virtual ImplMap& makeMap(LLSD::Impl*&); + ImplMap& makeMap(LLSD::Impl*&) override; - virtual LLSD::Type type() const { return LLSD::TypeMap; } + LLSD::Type type() const override { return LLSD::TypeMap; } - virtual LLSD::Boolean asBoolean() const { return !mData.empty(); } + LLSD::Boolean asBoolean() const override { return !mData.empty(); } - virtual bool has(const LLSD::String&) const; + bool has(const LLSD::String&) const override; using LLSD::Impl::get; // Unhiding get(LLSD::Integer) using LLSD::Impl::erase; // Unhiding erase(LLSD::Integer) using LLSD::Impl::ref; // Unhiding ref(LLSD::Integer) - virtual LLSD get(const LLSD::String&) const; - virtual LLSD getKeys() const; + LLSD get(const LLSD::String&) const override; + LLSD getKeys() const override; void insert(const LLSD::String& k, const LLSD& v); - virtual void erase(const LLSD::String&); + void erase(const LLSD::String&) override; LLSD& ref(const LLSD::String&); - virtual const LLSD& ref(const LLSD::String&) const; + const LLSD& ref(const LLSD::String&) const override; - virtual int size() const { return mData.size(); } + int size() const override { return mData.size(); } DataMap& map() final override { return mData; } const DataMap& map() const final override { return mData; } - virtual void dumpStats() const; - virtual void calcStats(S32 type_counts[], S32 share_counts[]) const; + void dumpStats() const override; + void calcStats(S32 type_counts[], S32 share_counts[]) const override; }; ImplMap& ImplMap::makeMap(LLSD::Impl*& var) @@ -483,7 +485,7 @@ namespace { //std::cout << " " << (*iter).first << ": " << (*iter).second << std::endl; Impl::calcStats((*iter).second, type_counts, share_counts); - iter++; + ++iter; } // Add in the values for this map @@ -491,7 +493,7 @@ namespace } - class ImplArray : public LLSD::Impl + class ImplArray final : public LLSD::Impl { private: typedef std::vector DataVector; @@ -504,28 +506,28 @@ namespace public: ImplArray() { } - virtual ImplArray& makeArray(Impl*&); + ImplArray& makeArray(Impl*&) override; - virtual LLSD::Type type() const { return LLSD::TypeArray; } + LLSD::Type type() const override { return LLSD::TypeArray; } - virtual LLSD::Boolean asBoolean() const { return !mData.empty(); } + LLSD::Boolean asBoolean() const override { return !mData.empty(); } using LLSD::Impl::get; // Unhiding get(LLSD::String) using LLSD::Impl::erase; // Unhiding erase(LLSD::String) using LLSD::Impl::ref; // Unhiding ref(LLSD::String) - virtual int size() const; - virtual LLSD get(LLSD::Integer) const; + int size() const override; + LLSD get(LLSD::Integer) const override; void set(LLSD::Integer, const LLSD&); void insert(LLSD::Integer, const LLSD&); LLSD& append(const LLSD&); - virtual void erase(LLSD::Integer); + void erase(LLSD::Integer) override; LLSD& ref(LLSD::Integer); - virtual const LLSD& ref(LLSD::Integer) const; + const LLSD& ref(LLSD::Integer) const override; DataVector& array() final override { return mData; } const DataVector& array() const final override { return mData; } - virtual void calcStats(S32 type_counts[], S32 share_counts[]) const; + void calcStats(S32 type_counts[], S32 share_counts[]) const override; }; ImplArray& ImplArray::makeArray(Impl*& var) @@ -629,7 +631,7 @@ namespace while (iter != endArray()) { // Add values for all items held in the array Impl::calcStats((*iter), type_counts, share_counts); - iter++; + ++iter; } // Add in the values for this array @@ -701,7 +703,7 @@ void LLSD::Impl::assign(Impl*& var, const Impl* other) void LLSD::Impl::assignUndefined(Impl*& var) { - reset(var, 0); + reset(var, nullptr); } void LLSD::Impl::assign(Impl*& var, LLSD::Boolean v) @@ -777,7 +779,7 @@ void LLSD::Impl::calcStats(S32 type_counts[], S32 share_counts[]) const S32 tp = S32(type()); if (0 <= tp && tp < LLSD::TypeLLSDNumTypes) { - type_counts[tp]++; + type_counts[tp]++; if (shared()) { share_counts[tp]++; @@ -811,10 +813,10 @@ namespace } -LLSD::LLSD() : impl(0) { ALLOC_LLSD_OBJECT; } -LLSD::~LLSD() { FREE_LLSD_OBJECT; Impl::reset(impl, 0); } +LLSD::LLSD() : impl(nullptr) { ALLOC_LLSD_OBJECT; } +LLSD::~LLSD() { FREE_LLSD_OBJECT; Impl::reset(impl, nullptr); } -LLSD::LLSD(const LLSD& other) : impl(0) { ALLOC_LLSD_OBJECT; assign(other); } +LLSD::LLSD(const LLSD& other) : impl(nullptr) { ALLOC_LLSD_OBJECT; assign(other); } void LLSD::assign(const LLSD& other) { Impl::assign(impl, other.impl); } @@ -823,17 +825,17 @@ void LLSD::clear() { Impl::assignUndefined(impl); } LLSD::Type LLSD::type() const { return safe(impl).type(); } // Scalar Constructors -LLSD::LLSD(Boolean v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); } -LLSD::LLSD(Integer v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); } -LLSD::LLSD(Real v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); } -LLSD::LLSD(const UUID& v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); } -LLSD::LLSD(const String& v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); } -LLSD::LLSD(const Date& v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); } -LLSD::LLSD(const URI& v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); } -LLSD::LLSD(const Binary& v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); } +LLSD::LLSD(Boolean v) : impl(nullptr) { ALLOC_LLSD_OBJECT; assign(v); } +LLSD::LLSD(Integer v) : impl(nullptr) { ALLOC_LLSD_OBJECT; assign(v); } +LLSD::LLSD(Real v) : impl(nullptr) { ALLOC_LLSD_OBJECT; assign(v); } +LLSD::LLSD(const UUID& v) : impl(nullptr) { ALLOC_LLSD_OBJECT; assign(v); } +LLSD::LLSD(const String& v) : impl(nullptr) { ALLOC_LLSD_OBJECT; assign(v); } +LLSD::LLSD(const Date& v) : impl(nullptr) { ALLOC_LLSD_OBJECT; assign(v); } +LLSD::LLSD(const URI& v) : impl(nullptr) { ALLOC_LLSD_OBJECT; assign(v); } +LLSD::LLSD(const Binary& v) : impl(nullptr) { ALLOC_LLSD_OBJECT; assign(v); } // Convenience Constructors -LLSD::LLSD(F32 v) : impl(0) { ALLOC_LLSD_OBJECT; assign((Real)v); } +LLSD::LLSD(F32 v) : impl(nullptr) { ALLOC_LLSD_OBJECT; assign((Real)v); } // Scalar Assignment void LLSD::assign(Boolean v) { safe(impl).assign(impl, v); } @@ -858,7 +860,7 @@ const LLSD::Binary& LLSD::asBinary() const { return safe(impl).asBinary(); } const LLSD::String& LLSD::asStringRef() const { return safe(impl).asStringRef(); } // const char * helpers -LLSD::LLSD(const char* v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); } +LLSD::LLSD(const char* v) : impl(nullptr) { ALLOC_LLSD_OBJECT; assign(v); } void LLSD::assign(const char* v) { if(v) assign(std::string(v)); @@ -925,7 +927,7 @@ static const char *llsd_dump(const LLSD &llsd, bool useXMLFormat) // sStorage will point to the result of the last call. This will actually // be one leak, but since this is used only when running under the // debugger, it should not be an issue. - static char *sStorage = NULL; + static char *sStorage = nullptr; delete[] sStorage; std::string out_string; { diff --git a/indra/llcommon/llsd.h b/indra/llcommon/llsd.h index e6c34e32b..1d8950bfc 100644 --- a/indra/llcommon/llsd.h +++ b/indra/llcommon/llsd.h @@ -389,9 +389,9 @@ public: using an arbitrary pointer or scalar type to std::string. */ //@{ - LLSD(const void*); ///< construct from aribrary pointers - void assign(const void*); ///< assign from arbitrary pointers - LLSD& operator=(const void*); ///< assign from arbitrary pointers + LLSD(const void*) = delete; ///< construct from aribrary pointers + void assign(const void*) = delete; ///< assign from arbitrary pointers + LLSD& operator=(const void*) = delete; ///< assign from arbitrary pointers bool has(Integer) const; ///< has() only works for Maps //@} diff --git a/indra/llcommon/llsdjson.cpp b/indra/llcommon/llsdjson.cpp index db89b293e..a31128dd8 100644 --- a/indra/llcommon/llsdjson.cpp +++ b/indra/llcommon/llsdjson.cpp @@ -79,6 +79,17 @@ LLSD LlsdFromJson(const nlohmann::json &val) return result; } +LLSD LlsdFromJsonString(const std::string& str) +{ + auto json = nlohmann::json::parse(str, nullptr, false); + if (json.is_discarded()) + { + LL_WARNS() << "Cannot parse invalid json string:\n" << str << LL_ENDL; + return LLSD(); + } + return LlsdFromJson(json); +} + //========================================================================= nlohmann::json LlsdToJson(const LLSD &val) { diff --git a/indra/llcommon/llsdjson.h b/indra/llcommon/llsdjson.h index bc76acbc8..5c45f697e 100644 --- a/indra/llcommon/llsdjson.h +++ b/indra/llcommon/llsdjson.h @@ -54,6 +54,7 @@ /// For maps and arrays child entries will be converted and added to the structure. /// Order is preserved for an array but not for objects. LLSD LlsdFromJson(const nlohmann::json &val); +LLSD LlsdFromJsonString(const std::string& body); /// Convert an LLSD object into Parsed JSON object maintaining member names and /// array indexs. diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp index f8690f63b..3f85810ee 100644 --- a/indra/llcommon/llsdserialize.cpp +++ b/indra/llcommon/llsdserialize.cpp @@ -118,7 +118,7 @@ bool LLSDSerialize::deserialize(LLSD& sd, std::istream& str, S32 max_bytes) fail_if_not_legacy = true; } - if (!strncasecmp(LEGACY_NON_HEADER, hdr_buf, strlen(LEGACY_NON_HEADER))) /* Flawfinder: ignore */ + if (!strnicmp(LEGACY_NON_HEADER, hdr_buf, strlen(LEGACY_NON_HEADER))) /* Flawfinder: ignore */ { legacy_no_header = true; inbuf = (int)str.gcount(); @@ -141,9 +141,8 @@ bool LLSDSerialize::deserialize(LLSD& sd, std::istream& str, S32 max_bytes) } header = hdr_buf; - std::string::size_type start = std::string::npos; + std::string::size_type start = header.find_first_not_of("& buffer = data.asBinary(); ostr << "b(" << buffer.size() << ")\""; - if(buffer.size()) + if(!buffer.empty()) { if (options & LLSDFormatter::OPTIONS_PRETTY_BINARY) { std::ios_base::fmtflags old_flags = ostr.flags(); ostr.setf( std::ios::hex, std::ios::basefield ); ostr << "0x"; - for (size_t i = 0; i < buffer.size(); i++) + for (unsigned char i : buffer) { - ostr << (int) buffer[i]; + ostr << static_cast(i); } ostr.flags(old_flags); } else { - ostr.write((const char*)&buffer[0], buffer.size()); + ostr.write(reinterpret_cast(&buffer[0]), buffer.size()); } } ostr << "\""; @@ -1442,9 +1441,9 @@ S32 LLSDBinaryFormatter::format(const LLSD& data, std::ostream& ostr, U32 option { ostr.put('{'); U32 size_nbo = htonl(data.size()); - ostr.write((const char*)(&size_nbo), sizeof(U32)); - LLSD::map_const_iterator iter = data.beginMap(); - LLSD::map_const_iterator end = data.endMap(); + ostr.write(reinterpret_cast(&size_nbo), sizeof(U32)); + auto iter = data.beginMap(); + auto end = data.endMap(); for(; iter != end; ++iter) { ostr.put('k'); @@ -1459,7 +1458,7 @@ S32 LLSDBinaryFormatter::format(const LLSD& data, std::ostream& ostr, U32 option { ostr.put('['); U32 size_nbo = htonl(data.size()); - ostr.write((const char*)(&size_nbo), sizeof(U32)); + ostr.write(reinterpret_cast(&size_nbo), sizeof(U32)); for (const auto& entry : data.array()) { format_count += format(entry, ostr); @@ -1525,7 +1524,7 @@ S32 LLSDBinaryFormatter::format(const LLSD& data, std::ostream& ostr, U32 option const std::vector& buffer = data.asBinary(); U32 size_nbo = htonl(buffer.size()); ostr.write((const char*)(&size_nbo), sizeof(U32)); - if(buffer.size()) ostr.write((const char*)&buffer[0], buffer.size()); + if(!buffer.empty()) ostr.write((const char*)&buffer[0], buffer.size()); break; } @@ -1702,12 +1701,12 @@ int deserialize_string_raw( // *FIX: This is memory inefficient. S32 len = strtol(buf + 1, NULL, 0); if((max_bytes>0)&&(len>max_bytes)) return LLSDParser::PARSE_FAILURE; - std::vector buf; + std::vector buf2; if(len) { - buf.resize(len); - count += (int)fullread(istr, (char *)&buf[0], len); - value.assign(buf.begin(), buf.end()); + buf2.resize(len); + count += (int)fullread(istr, (char *)&buf2[0], len); + value.assign(buf2.begin(), buf2.end()); } c = istr.get(); ++count; @@ -2091,7 +2090,18 @@ std::string zip_llsd(LLSD& data) } have = CHUNK-strm.avail_out; - output = (U8*) realloc(output, cur_size+have); + U8* new_output = (U8*) realloc(output, cur_size+have); + if (new_output == NULL) + { + LL_WARNS() << "Failed to compress LLSD block: can't reallocate memory, current size: " << cur_size << " bytes; requested " << cur_size + have << " bytes." << LL_ENDL; + deflateEnd(&strm); + if (output) + { + free(output); + } + return std::string(); + } + output = new_output; memcpy(output+cur_size, out, have); cur_size += have; } @@ -2110,15 +2120,6 @@ std::string zip_llsd(LLSD& data) deflateEnd(&strm); free(output); -#if 0 //verify results work with unzip_llsd - std::istringstream test(result); - LLSD test_sd; - if (!unzip_llsd(test_sd, test, result.size())) - { - LL_ERRS() << "Invalid compression result!" << LL_ENDL; - } -#endif - return result; } @@ -2169,7 +2170,19 @@ bool unzip_llsd(LLSD& data, std::istream& is, S32 size) U32 have = CHUNK-strm.avail_out; - result = (U8*) realloc(result, cur_size + have); + U8* new_result = (U8*)realloc(result, cur_size + have); + if (new_result == NULL) + { + LL_WARNS() << "Failed to unzip LLSD block: can't reallocate memory, current size: " << cur_size << " bytes; requested " << cur_size + have << " bytes." << LL_ENDL; + inflateEnd(&strm); + if (result) + { + free(result); + } + delete in; + return false; + } + result = new_result; memcpy(result+cur_size, out, have); cur_size += have; @@ -2215,6 +2228,11 @@ bool unzip_llsd(LLSD& data, std::istream& is, S32 size) //and trailers are different for the formats. U8* unzip_llsdNavMesh( bool& valid, unsigned int& outsize, std::istream& is, S32 size ) { + if (size == 0) + { + LL_WARNS() << "No data to unzip." << LL_ENDL; + return NULL; + } U8* result = NULL; U32 cur_size = 0; z_stream strm; @@ -2254,7 +2272,23 @@ U8* unzip_llsdNavMesh( bool& valid, unsigned int& outsize, std::istream& is, S32 } U32 have = CHUNK-strm.avail_out; - result = (U8*) realloc(result, cur_size + have); + U8* new_result = (U8*) realloc(result, cur_size + have); + if (new_result == NULL) + { + LL_WARNS() << "Failed to unzip LLSD NavMesh block: can't reallocate memory, current size: " << cur_size + << " bytes; requested " << cur_size + have + << " bytes; total syze: ." << size << " bytes." + << LL_ENDL; + inflateEnd(&strm); + if (result) + { + free(result); + } + delete [] in; + valid = false; + return NULL; + } + result = new_result; memcpy(result+cur_size, out, have); cur_size += have; diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp index 86992aee6..e14ae9027 100644 --- a/indra/llinventory/llinventory.cpp +++ b/indra/llinventory/llinventory.cpp @@ -1165,8 +1165,10 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new) // mType, these are the two asset types that are IT_WEARABLE: static U32 AT_BODYPART = 13; // LLAssetType::AT_BODYPART // Viewer local values: - static U32 WT_UNKNOWN = 16; // LLWearableType::WT_UNKNOWN - static U32 WT_COUNT = 17; // LLWearableType::WT_COUNT + static U32 WT_UNKNOWN = 17; // LLWearableType::WT_UNKNOWN + static U32 WT_COUNT = 18; // LLWearableType::WT_COUNT + // Keep WT_UNKNOWN and WT_COUNT + // in sync with llwearabletype.h // The last 8 bits of mFlags contain the wearable type. static U32 II_FLAGS_SUBTYPE_MASK = 0xff; // LLInventoryItemFlags::II_FLAGS_SUBTYPE_MASK diff --git a/indra/llinventory/llparcel.cpp b/indra/llinventory/llparcel.cpp index a4aaae365..158c2edc5 100644 --- a/indra/llinventory/llparcel.cpp +++ b/indra/llinventory/llparcel.cpp @@ -40,6 +40,8 @@ #include "llsdutil_math.h" #include "message.h" #include "u64.h" +#include "llregionflags.h" +#include static const F32 SOME_BIG_NUMBER = 1000.0f; static const F32 SOME_BIG_NEG_NUMBER = -1000.0f; @@ -742,8 +744,8 @@ void LLParcel::unpackMessage(LLMessageSystem* msg) void LLParcel::packAccessEntries(LLMessageSystem* msg, const std::map& list) { - access_map_const_iterator cit = list.begin(); - access_map_const_iterator end = list.end(); + LLAccessEntry::map::const_iterator cit = list.begin(); + LLAccessEntry::map::const_iterator end = list.end(); if (cit == end) { @@ -794,9 +796,28 @@ void LLParcel::unpackAccessEntries(LLMessageSystem* msg, } +void LLParcel::unpackExperienceEntries(LLMessageSystem* msg, U32 type) +{ + LLUUID id; + + S32 i; + S32 count = msg->getNumberOfBlocksFast(_PREHASH_List); + for (i = 0; i < count; i++) + { + msg->getUUIDFast(_PREHASH_List, _PREHASH_ID, id, i); + + if (id.notNull()) + { + mExperienceKeys[id] = type; + } + } +} + + + void LLParcel::expirePasses(S32 now) { - access_map_iterator itor = mAccessList.begin(); + LLAccessEntry::map::iterator itor = mAccessList.begin(); while (itor != mAccessList.end()) { const LLAccessEntry& entry = (*itor).second; @@ -886,7 +907,7 @@ BOOL LLParcel::addToAccessList(const LLUUID& agent_id, S32 time) // Can't add owner to these lists return FALSE; } - access_map_iterator itor = mAccessList.begin(); + LLAccessEntry::map::iterator itor = mAccessList.begin(); while (itor != mAccessList.end()) { const LLAccessEntry& entry = (*itor).second; @@ -931,7 +952,7 @@ BOOL LLParcel::addToBanList(const LLUUID& agent_id, S32 time) return FALSE; } - access_map_iterator itor = mBanList.begin(); + LLAccessEntry::map::iterator itor = mBanList.begin(); while (itor != mBanList.end()) { const LLAccessEntry& entry = (*itor).second; @@ -970,7 +991,7 @@ BOOL remove_from_access_array(std::map* list, const LLUUID& agent_id) { BOOL removed = FALSE; - access_map_iterator itor = list->begin(); + LLAccessEntry::map::iterator itor = list->begin(); while (itor != list->end()) { const LLAccessEntry& entry = (*itor).second; @@ -1091,7 +1112,7 @@ void LLParcel::startSale(const LLUUID& buyer_id, BOOL is_buyer_group) mSaleTimerExpires.start(); mSaleTimerExpires.setTimerExpirySec(U64Microseconds(DEFAULT_USEC_SALE_TIMEOUT)); mStatus = OS_LEASE_PENDING; - mClaimDate = time(NULL); + mClaimDate = time(nullptr); setAuctionID(0); // clear the autoreturn whenever land changes hands setCleanOtherTime(0); @@ -1313,3 +1334,58 @@ LLParcel::ECategory category_ui_string_to_category(const std::string& s) // is a distinct option from "None" and "Other" return LLParcel::C_ANY; } + +LLAccessEntry::map LLParcel::getExperienceKeysByType(U32 type) const +{ + LLAccessEntry::map access; + LLAccessEntry entry; + xp_type_map_t::const_iterator it = mExperienceKeys.begin(); + for(/**/; it != mExperienceKeys.end(); ++it) + { + if(it->second == type) + { + entry.mID = it->first; + access[entry.mID] = entry; + } + } + return access; +} + +void LLParcel::clearExperienceKeysByType(U32 type) +{ + xp_type_map_t::iterator it = mExperienceKeys.begin(); + while(it != mExperienceKeys.end()) + { + if(it->second == type) + { + mExperienceKeys.erase(it++); + } + else + { + ++it; + } + } +} + +void LLParcel::setExperienceKeyType(const LLUUID& experience_key, U32 type) +{ + if (type == EXPERIENCE_KEY_TYPE_NONE) + { + mExperienceKeys.erase(experience_key); + } + else + { + if (countExperienceKeyType(type) < PARCEL_MAX_EXPERIENCE_LIST) + { + mExperienceKeys[experience_key] = type; + } + } +} + +U32 LLParcel::countExperienceKeyType(U32 type) +{ + return std::count_if( + boost::begin(mExperienceKeys | boost::adaptors::map_values), + boost::end(mExperienceKeys | boost::adaptors::map_values), + std::bind2nd(std::equal_to(), type)); +} diff --git a/indra/llinventory/llparcel.h b/indra/llinventory/llparcel.h index e91f9a320..c1322c387 100644 --- a/indra/llinventory/llparcel.h +++ b/indra/llinventory/llparcel.h @@ -60,6 +60,9 @@ const S32 PARCEL_MAX_ACCESS_LIST = 300; //for access/ban lists. const F32 PARCEL_MAX_ENTRIES_PER_PACKET = 48.f; +// Maximum number of experiences +const S32 PARCEL_MAX_EXPERIENCE_LIST = 24; + // Weekly charge for listing a parcel in the directory const S32 PARCEL_DIRECTORY_FEE = 30; @@ -141,9 +144,11 @@ class LLSD; class LLAccessEntry { public: + + typedef std::map map; + LLAccessEntry() - : mID(), - mTime(0), + : mTime(0), mFlags(0) {} @@ -152,8 +157,6 @@ public: U32 mFlags; // Not used - currently should always be zero }; -typedef std::map::iterator access_map_iterator; -typedef std::map::const_iterator access_map_const_iterator; class LLParcel { @@ -331,6 +334,9 @@ public: void unpackAccessEntries(LLMessageSystem* msg, std::map* list); + void unpackExperienceEntries(LLMessageSystem* msg, U32 type); + + void setAABBMin(const LLVector3& min) { mAABBMin = min; } void setAABBMax(const LLVector3& max) { mAABBMax = max; } @@ -707,6 +713,17 @@ public: std::map mTempBanList; std::map mTempAccessList; + typedef std::map xp_type_map_t; + + void setExperienceKeyType(const LLUUID& experience_key, U32 type); + U32 countExperienceKeyType(U32 type); + U32 getExperienceKeyType(const LLUUID& experience_key)const; + LLAccessEntry::map getExperienceKeysByType(U32 type)const; + void clearExperienceKeysByType(U32 type); + +private: + xp_type_map_t mExperienceKeys; + }; diff --git a/indra/llinventory/llparcelflags.h b/indra/llinventory/llparcelflags.h index 9d4884e32..fbfc2af1d 100644 --- a/indra/llinventory/llparcelflags.h +++ b/indra/llinventory/llparcelflags.h @@ -1,31 +1,25 @@ /** * @file llparcelflags.h * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * 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 + * Copyright (C) 2010, Linden Research, Inc. * - * 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 + * 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. * - * 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. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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$ */ @@ -97,8 +91,10 @@ const U32 PF_DEFAULT = PF_ALLOW_FLY | PF_USE_ESTATE_VOICE_CHAN; // Access list flags -const U32 AL_ACCESS = (1 << 0); -const U32 AL_BAN = (1 << 1); +const U32 AL_ACCESS = (1 << 0); +const U32 AL_BAN = (1 << 1); +const U32 AL_ALLOW_EXPERIENCE = (1 << 3); +const U32 AL_BLOCK_EXPERIENCE = (1 << 4); //const U32 AL_RENTER = (1 << 2); // Block access return values. BA_ALLOWED is the only success case diff --git a/indra/llmath/lloctree.h b/indra/llmath/lloctree.h index 2f843490d..67a7c997e 100644 --- a/indra/llmath/lloctree.h +++ b/indra/llmath/lloctree.h @@ -704,7 +704,7 @@ public: #endif } - notifyRemoval(data); + this->notifyRemoval(data); checkAlive(); } diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt index c131b436c..b5f5bafc1 100644 --- a/indra/llmessage/CMakeLists.txt +++ b/indra/llmessage/CMakeLists.txt @@ -45,6 +45,7 @@ set(llmessage_SOURCE_FILES llclassifiedflags.cpp lldatapacker.cpp lldispatcher.cpp + llexperiencecache.cpp llfiltersd2xmlrpc.cpp llhost.cpp llhttpclient.cpp @@ -133,11 +134,13 @@ set(llmessage_HEADER_FILES llcipher.h llcircuit.h llclassifiedflags.h + llcororesponder.h llcurl.h lldatapacker.h lldbstrings.h lldispatcher.h lleventflags.h + llexperiencecache.h llfiltersd2xmlrpc.h llfollowcamparams.h llhost.h @@ -227,7 +230,8 @@ target_link_libraries( ${OPENSSL_LIBRARIES} ${CRYPTO_LIBRARIES} ${XMLRPCEPI_LIBRARIES} - ) + ${PTHREAD_LIBRARY} +) # tests if (LL_TESTS) diff --git a/indra/llmessage/llavatarname.cpp b/indra/llmessage/llavatarname.cpp index fdcfed161..a02d7c012 100644 --- a/indra/llmessage/llavatarname.cpp +++ b/indra/llmessage/llavatarname.cpp @@ -139,7 +139,7 @@ void LLAvatarName::fromString(const std::string& full_name) mLegacyLastName = full_name.substr(index+1); if (mLegacyLastName != "Resident") { - mUsername = mLegacyFirstName + "." + mLegacyLastName; + mUsername = mLegacyFirstName + '.' + mLegacyLastName; mDisplayName = full_name; LLStringUtil::toLower(mUsername); } @@ -184,7 +184,7 @@ std::string LLAvatarName::getCompleteName(bool linefeed) const name = mDisplayName; if (sUseUsernames) { - name += (linefeed ? "\n(" : " (") + mUsername + ")"; + name += (linefeed ? "\n(" : " (") + mUsername + ')'; } } } @@ -238,7 +238,7 @@ std::string LLAvatarName::getUserName() const } else { - name = mLegacyFirstName + " " + mLegacyLastName; + name = mLegacyFirstName + ' ' + mLegacyLastName; } return name; } diff --git a/indra/llmessage/llavatarname.h b/indra/llmessage/llavatarname.h index 5902d34d8..4f0df57cc 100644 --- a/indra/llmessage/llavatarname.h +++ b/indra/llmessage/llavatarname.h @@ -94,7 +94,7 @@ public: { case 1 : return getCompleteName(); case 2 : return getDisplayName(); - case 3 : return getLegacyName() + (mIsDisplayNameDefault ? "" : " (" + mDisplayName + ")"); break; + case 3 : return getLegacyName() + (mIsDisplayNameDefault ? "" : " (" + mDisplayName + ')'); break; default : return getLegacyName(); } } diff --git a/indra/llmessage/llcororesponder.h b/indra/llmessage/llcororesponder.h new file mode 100644 index 000000000..bacec85a8 --- /dev/null +++ b/indra/llmessage/llcororesponder.h @@ -0,0 +1,63 @@ +/** + * @file llcororesponder.h + * @brief A responder purposed to call coro functions, to ease transition to LLCoro + * + * $LicenseInfo:firstyear=2006&license=viewerlgpl$ + * Second Life Viewer Source Code + * + * Copyright (C) 2020, Liru Færs + * + * 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 +#include "llhttpclient.h" + +struct LLCoroResponderBase : public LLHTTPClient::ResponderWithCompleted +{ + const AIHTTPReceivedHeaders& getHeaders() const { return mReceivedHeaders; } + const LLSD& getContent() const { return mContent; } + + char const* getName() const override final { return "LLCoroResponder"; } +protected: + LLCoroResponderBase() {} +}; + +struct LLCoroResponder final : public LLCoroResponderBase +{ + typedef std::function cb_t; + LLCoroResponder(const cb_t& cb) : mCB(cb) {} + void httpCompleted() override { mCB(*this); } +private: + const cb_t mCB; +}; + +struct LLCoroResponderRaw final : public LLCoroResponderBase +{ + typedef std::function cb_t; + LLCoroResponderRaw(const cb_t& cb) : mCB(cb) {} + void completedRaw(const LLChannelDescriptors& channels, const buffer_ptr_t& buffer) override + { + std::string content; + decode_raw_body(channels, buffer, content); + mCB(*this, content); + } +private: + const cb_t mCB; +}; + diff --git a/indra/llmessage/llexperiencecache.cpp b/indra/llmessage/llexperiencecache.cpp new file mode 100644 index 000000000..482b87091 --- /dev/null +++ b/indra/llmessage/llexperiencecache.cpp @@ -0,0 +1,921 @@ +/** + * @file llexperiencecache.cpp + * @brief llexperiencecache and related class definitions + * + * $LicenseInfo:firstyear=2012&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, 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 "llexperiencecache.h" + +#include "llavatarname.h" +#include "llcororesponder.h" +#include "llsdserialize.h" +#include "lleventfilter.h" +#include "lldir.h" +#include +#include +#include +#include +#include + +//========================================================================= +namespace LLExperienceCacheImpl +{ + void mapKeys(const LLSD& legacyKeys); + F64 getErrorRetryDeltaTime(S32 status, const AIHTTPReceivedHeaders& headers); + bool maxAgeFromCacheControl(const std::string& cache_control, S32 *max_age); + + static const std::string PRIVATE_KEY = "private_id"; + static const std::string EXPERIENCE_ID = "public_id"; + + static const std::string MAX_AGE("max-age"); + static const boost::char_separator EQUALS_SEPARATOR("="); + static const boost::char_separator COMMA_SEPARATOR(","); + + // *TODO$: this seems to be tied to mapKeys which is used by bootstrap.... but I don't think that bootstrap is used. + typedef std::map KeyMap; + KeyMap privateToPublicKeyMap; +} + +//========================================================================= +const std::string LLExperienceCache::PRIVATE_KEY = "private_id"; +const std::string LLExperienceCache::MISSING = "DoesNotExist"; + +const std::string LLExperienceCache::AGENT_ID = "agent_id"; +const std::string LLExperienceCache::GROUP_ID = "group_id"; +const std::string LLExperienceCache::EXPERIENCE_ID = "public_id"; +const std::string LLExperienceCache::NAME = "name"; +const std::string LLExperienceCache::PROPERTIES = "properties"; +const std::string LLExperienceCache::EXPIRES = "expiration"; +const std::string LLExperienceCache::DESCRIPTION = "description"; +const std::string LLExperienceCache::QUOTA = "quota"; +const std::string LLExperienceCache::MATURITY = "maturity"; +const std::string LLExperienceCache::METADATA = "extended_metadata"; +const std::string LLExperienceCache::SLURL = "slurl"; + +// should be in sync with experience-api/experiences/models.py +const int LLExperienceCache::PROPERTY_INVALID = 1 << 0; +const int LLExperienceCache::PROPERTY_PRIVILEGED = 1 << 3; +const int LLExperienceCache::PROPERTY_GRID = 1 << 4; +const int LLExperienceCache::PROPERTY_PRIVATE = 1 << 5; +const int LLExperienceCache::PROPERTY_DISABLED = 1 << 6; +const int LLExperienceCache::PROPERTY_SUSPENDED = 1 << 7; + +// default values +const F64 LLExperienceCache::DEFAULT_EXPIRATION = 600.0; +const S32 LLExperienceCache::DEFAULT_QUOTA = 128; // this is megabytes +const int LLExperienceCache::SEARCH_PAGE_SIZE = 30; + +//========================================================================= +LLExperienceCache::LLExperienceCache(): + mShutdown(false) +{ +} + +LLExperienceCache::~LLExperienceCache() +{ + +} + +void LLExperienceCache::initSingleton() +{ + mCacheFileName = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "experience_cache.xml"); + + LL_INFOS("ExperienceCache") << "Loading " << mCacheFileName << LL_ENDL; + llifstream cache_stream(mCacheFileName.c_str()); + + if (cache_stream.is_open()) + { + cache_stream >> (*this); + } +} + +void LLExperienceCache::cleanup() +{ + LL_INFOS("ExperienceCache") << "Saving " << mCacheFileName << LL_ENDL; + + llofstream cache_stream(mCacheFileName.c_str()); + if (cache_stream.is_open()) + { + cache_stream << (*this); + } + mShutdown = true; +} + +//------------------------------------------------------------------------- +void LLExperienceCache::importFile(std::istream& istr) +{ + LLSD data; + S32 parse_count = LLSDSerialize::fromXMLDocument(data, istr); + if (parse_count < 1) return; + + LLSD experiences = data["experiences"]; + + LLUUID public_key; + for (const auto& it : experiences.map()) + { + public_key.set(it.first); + mCache[public_key] = it.second; + } + + LL_DEBUGS("ExperienceCache") << "importFile() loaded " << mCache.size() << LL_ENDL; +} + +void LLExperienceCache::exportFile(std::ostream& ostr) const +{ + LLSD experiences; + + cache_t::const_iterator it = mCache.begin(); + for (; it != mCache.end(); ++it) + { + if (!it->second.has(EXPERIENCE_ID) || it->second[EXPERIENCE_ID].asUUID().isNull() || + it->second.has("DoesNotExist") || (it->second.has(PROPERTIES) && it->second[PROPERTIES].asInteger() & PROPERTY_INVALID)) + continue; + + experiences[it->first.asString()] = it->second; + } + + LLSD data; + data["experiences"] = experiences; + + LLSDSerialize::toPrettyXML(data, ostr); +} + +// *TODO$: Rider: This method does not seem to be used... it may be useful in testing. +void LLExperienceCache::bootstrap(const LLSD& legacyKeys, int initialExpiration) +{ + LLExperienceCacheImpl::mapKeys(legacyKeys); + for (auto experience : legacyKeys.array()) + { + if (experience.has(EXPERIENCE_ID)) + { + if (!experience.has(EXPIRES)) + { + experience[EXPIRES] = initialExpiration; + } + processExperience(experience[EXPERIENCE_ID].asUUID(), experience); + } + else + { + LL_WARNS("ExperienceCache") + << "Skipping bootstrap entry which is missing " << EXPERIENCE_ID + << LL_ENDL; + } + } +} + +LLUUID LLExperienceCache::getExperienceId(const LLUUID& private_key, bool null_if_not_found) +{ + if (private_key.isNull()) + return LLUUID::null; + + LLExperienceCacheImpl::KeyMap::const_iterator it = LLExperienceCacheImpl::privateToPublicKeyMap.find(private_key); + if (it == LLExperienceCacheImpl::privateToPublicKeyMap.end()) + { + if (null_if_not_found) + { + return LLUUID::null; + } + return private_key; + } + LL_WARNS("LLExperience") << "converted private key " << private_key << " to experience_id " << it->second << LL_ENDL; + return it->second; +} + +//========================================================================= +void LLExperienceCache::processExperience(const LLUUID& public_key, const LLSD& experience) +{ + LL_INFOS("ExperienceCache") << "Processing experience \"" << experience[NAME] << "\" with key " << public_key.asString() << LL_ENDL; + + mCache[public_key]=experience; + LLSD & row = mCache[public_key]; + + if(row.has(EXPIRES)) + { + row[EXPIRES] = row[EXPIRES].asReal() + LLFrameTimer::getTotalSeconds(); + } + + if(row.has(EXPERIENCE_ID)) + { + mPendingQueue.erase(row[EXPERIENCE_ID].asUUID()); + } + + //signal + signal_map_t::iterator sig_it = mSignalMap.find(public_key); + if (sig_it != mSignalMap.end()) + { + signal_ptr signal = sig_it->second; + (*signal)(experience); + + mSignalMap.erase(public_key); + } +} + +const LLExperienceCache::cache_t& LLExperienceCache::getCached() +{ + return mCache; +} + +void LLExperienceCache::requestExperiencesCoro(const LLCoroResponder& responder, RequestQueue_t requests) +{ + //LL_INFOS("requestExperiencesCoro") << "url: " << url << LL_ENDL; + + LLSD result = responder.getContent(); + auto status = responder.getStatus(); + + if (!responder.isGoodStatus(status)) + { + F64 now = LLFrameTimer::getTotalSeconds(); + + auto headers = responder.getHeaders(); + // build dummy entries for the failed requests + for (auto request : requests) + { + LLSD exp = get(request); + //leave the properties alone if we already have a cache entry for this xp + if (exp.isUndefined()) + { + exp[PROPERTIES] = PROPERTY_INVALID; + } + exp[EXPIRES] = now + LLExperienceCacheImpl::getErrorRetryDeltaTime(status, headers); + exp[EXPERIENCE_ID] = request; + exp["key_type"] = EXPERIENCE_ID; + exp["uuid"] = request; + exp["error"] = status; + exp[QUOTA] = DEFAULT_QUOTA; + + processExperience(request, exp); + } + return; + } + + LLSD experiences = result["experience_keys"]; + + for (const auto& row : experiences.array()) + { + LLUUID public_key = row[EXPERIENCE_ID].asUUID(); + + LL_DEBUGS("ExperienceCache") << "Received result for " << public_key + << " display '" << row[LLExperienceCache::NAME].asString() << "'" << LL_ENDL; + + processExperience(public_key, row); + } + + LLSD error_ids = result["error_ids"]; + + for (const auto& err : error_ids.array()) + { + LLUUID id = err.asUUID(); + LLSD exp; + exp[EXPIRES] = DEFAULT_EXPIRATION; + exp[EXPERIENCE_ID] = id; + exp[PROPERTIES] = PROPERTY_INVALID; + exp[MISSING] = true; + exp[QUOTA] = DEFAULT_QUOTA; + + processExperience(id, exp); + LL_WARNS("ExperienceCache") << "LLExperienceResponder::result() error result for " << id << LL_ENDL; + } + +} + +void LLExperienceCache::requestExperiences() +{ + if (mCapability == nullptr) + { + LL_WARNS("ExperienceCache") << "Capability query method not set." << LL_ENDL; + return; + } + + std::string urlBase = mCapability("GetExperienceInfo"); + if (urlBase.empty()) + { + LL_DEBUGS("ExperienceCache") << "No Experience capability." << LL_ENDL; + return; + } + + if (*urlBase.rbegin() != '/') + { + urlBase += "/"; + } + urlBase += "id/"; + + + F64 now = LLFrameTimer::getTotalSeconds(); + + const U32 EXP_URL_SEND_THRESHOLD = 3000; + constexpr U32 EXP_PAGE_SIZE = EXP_URL_SEND_THRESHOLD / UUID_STR_LENGTH; + + std::ostringstream ostr; + ostr << urlBase << "?page_size=" << EXP_PAGE_SIZE; + RequestQueue_t requests; + + while (!mRequestQueue.empty()) + { + RequestQueue_t::iterator it = mRequestQueue.begin(); + LLUUID key = (*it); + mRequestQueue.erase(it); + requests.insert(key); + + ostr << "&" << EXPERIENCE_ID << "=" << key.asString(); + mPendingQueue[key] = now; + + if (mRequestQueue.empty() || (ostr.tellp() > EXP_URL_SEND_THRESHOLD)) + { // request is placed in the coprocedure pool for the ExpCache cache. Throttling is done by the pool itself. + LLHTTPClient::get(ostr.str(), new LLCoroResponder( + boost::bind(&LLExperienceCache::requestExperiencesCoro, this, _1, requests) )); + + ostr.str(std::string()); + ostr << urlBase << "?page_size=" << EXP_PAGE_SIZE; + requests.clear(); + } + } + +} + + +bool LLExperienceCache::isRequestPending(const LLUUID& public_key) +{ + bool isPending = false; + const F64 PENDING_TIMEOUT_SECS = 5.0 * 60.0; + + PendingQueue_t::const_iterator it = mPendingQueue.find(public_key); + + if(it != mPendingQueue.end()) + { + F64 expire_time = LLFrameTimer::getTotalSeconds() - PENDING_TIMEOUT_SECS; + isPending = (it->second > expire_time); + } + + return isPending; +} + +void LLExperienceCache::setCapabilityQuery(LLExperienceCache::CapabilityQuery_t queryfn) +{ + mCapability = queryfn; +} + + +void LLExperienceCache::idleCoro() +{ + const F32 SECS_BETWEEN_REQUESTS = 0.5f; + const F32 ERASE_EXPIRED_TIMEOUT = 60.f; // seconds + + { + static LLFrameTimer sRequestTimer; + if (!sRequestTimer.checkExpirationAndReset(SECS_BETWEEN_REQUESTS)) return; + + if (mEraseExpiredTimer.checkExpirationAndReset(ERASE_EXPIRED_TIMEOUT)) + { + eraseExpired(); + } + + if (!mRequestQueue.empty()) + { + requestExperiences(); + } + } + + // The coroutine system will likely be shut down by the time we get to this point + // (or at least no further cycling will occur on it since the user has decided to quit.) +} + +void LLExperienceCache::erase(const LLUUID& key) +{ + cache_t::iterator it = mCache.find(key); + + if(it != mCache.end()) + { + mCache.erase(it); + } +} + +void LLExperienceCache::eraseExpired() +{ + F64 now = LLFrameTimer::getTotalSeconds(); + cache_t::iterator it = mCache.begin(); + while (it != mCache.end()) + { + cache_t::iterator cur = it; + LLSD& exp = cur->second; + ++it; + + //LL_INFOS("ExperienceCache") << "Testing experience \"" << exp[NAME] << "\" with exp time " << exp[EXPIRES].asReal() << "(now = " << now << ")" << LL_ENDL; + + if(exp.has(EXPIRES) && exp[EXPIRES].asReal() < now) + { + if(!exp.has(EXPERIENCE_ID)) + { + LL_WARNS("ExperienceCache") << "Removing experience with no id " << LL_ENDL ; + mCache.erase(cur); + } + else + { + LLUUID id = exp[EXPERIENCE_ID].asUUID(); + LLUUID private_key = exp.has(LLExperienceCache::PRIVATE_KEY) ? exp[LLExperienceCache::PRIVATE_KEY].asUUID():LLUUID::null; + if(private_key.notNull() || !exp.has("DoesNotExist")) + { + fetch(id, true); + } + else + { + LL_WARNS("ExperienceCache") << "Removing invalid experience " << id << LL_ENDL ; + mCache.erase(cur); + } + } + } + } +} + +bool LLExperienceCache::fetch(const LLUUID& key, bool refresh/* = true*/) +{ + if(!key.isNull() && !isRequestPending(key) && (refresh || mCache.find(key)==mCache.end())) + { + LL_DEBUGS("ExperienceCache") << " queue request for " << EXPERIENCE_ID << " " << key << LL_ENDL; + + mRequestQueue.insert(key); + return true; + } + return false; +} + +void LLExperienceCache::insert(const LLSD& experience_data) +{ + if(experience_data.has(EXPERIENCE_ID)) + { + processExperience(experience_data[EXPERIENCE_ID].asUUID(), experience_data); + } + else + { + LL_WARNS("ExperienceCache") << ": Ignoring cache insert of experience which is missing " << EXPERIENCE_ID << LL_ENDL; + } +} + +const LLSD& LLExperienceCache::get(const LLUUID& key) +{ + static const LLSD empty; + + if(key.isNull()) + return empty; + cache_t::const_iterator it = mCache.find(key); + + if (it != mCache.end()) + { + return it->second; + } + fetch(key); + + return empty; +} + +void LLExperienceCache::get(const LLUUID& key, LLExperienceCache::ExperienceGetFn_t slot) +{ + if(key.isNull()) + return; + + cache_t::const_iterator it = mCache.find(key); + if (it != mCache.end()) + { + // ...name already exists in cache, fire callback now + callback_signal_t signal; + signal.connect(slot); + + signal(it->second); + return; + } + + fetch(key); + + signal_ptr signal = boost::make_shared(); + + std::pair result = mSignalMap.insert(signal_map_t::value_type(key, signal)); + if (!result.second) + signal = (*result.first).second; + signal->connect(slot); +} + +//========================================================================= +void LLExperienceCache::fetchAssociatedExperience(const LLUUID& objectId, const LLUUID& itemId, std::string url, ExperienceGetFn_t fn) +{ + if (mCapability == nullptr) + { + LL_WARNS("ExperienceCache") << "Capability query method not set." << LL_ENDL; + return; + } + + + if (url.empty()) + { + url = mCapability("GetMetadata"); + + if (url.empty()) + { + LL_WARNS("ExperienceCache") << "No Metadata capability." << LL_ENDL; + return; + } + } + + LLSD fields; + fields.append("experience"); + LLSD data; + data["object-id"] = objectId; + data["item-id"] = itemId; + data["fields"] = fields; + + LLHTTPClient::post(url, data, new LLCoroResponder( + boost::bind(&LLExperienceCache::fetchAssociatedExperienceCoro, this, _1, fn))); +} + +void LLExperienceCache::fetchAssociatedExperienceCoro(const LLCoroResponder& responder, ExperienceGetFn_t fn) +{ + LLSD result = responder.getContent(); + auto status = responder.getStatus(); + + if (!responder.isGoodStatus(status) || !result.has("experience")) + { + LLSD failure; + if (!status) + { + failure["error"] = status; + failure["message"] = responder.getReason(); + } + else + { + failure["error"] = -1; + failure["message"] = "no experience"; + } + if (fn != nullptr) + fn(failure); + return; + } + + LLUUID expId = result["experience"].asUUID(); + get(expId, fn); +} + +//------------------------------------------------------------------------- +void LLExperienceCache::findExperienceByName(const std::string text, int page, ExperienceGetFn_t fn) +{ + if (mCapability == nullptr) + { + LL_WARNS("ExperienceCache") << "Capability query method not set." << LL_ENDL; + return; + } + + std::ostringstream url; + + url << mCapability("FindExperienceByName") << "?page=" << page << "&page_size=" << SEARCH_PAGE_SIZE << "&query=" << LLURI::escape(text); + + LLHTTPClient::get(url.str(), new LLCoroResponder( + boost::bind(&LLExperienceCache::findExperienceByNameCoro, this, _1, fn))); +} + +void LLExperienceCache::findExperienceByNameCoro(const LLCoroResponder& responder, ExperienceGetFn_t fn) +{ + LLSD result = responder.getContent(); + + if (!responder.isGoodStatus(responder.getStatus())) + { + fn(LLSD()); + return; + } + + const LLSD& experiences = result["experience_keys"]; + for (const auto& it : experiences.array()) + { + insert(it); + } + + fn(result); +} + +//------------------------------------------------------------------------- +void LLExperienceCache::getGroupExperiences(const LLUUID &groupId, ExperienceGetFn_t fn) +{ + if (mCapability == nullptr) + { + LL_WARNS("ExperienceCache") << "Capability query method not set." << LL_ENDL; + return; + } + + // search for experiences owned by the current group + std::string url = mCapability("GroupExperiences"); + if (url.empty()) + { + LL_WARNS("ExperienceCache") << "No Group Experiences capability" << LL_ENDL; + return; + } + + url += "?" + groupId.asString(); + + LLHTTPClient::get(url, new LLCoroResponder( + boost::bind(&LLExperienceCache::getGroupExperiencesCoro, this, _1, fn))); +} + +void LLExperienceCache::getGroupExperiencesCoro(const LLCoroResponder& responder, ExperienceGetFn_t fn) +{ + LLSD result = responder.getContent(); + + if (!responder.isGoodStatus(responder.getStatus())) + { + fn(LLSD()); + return; + } + + const LLSD& experienceIds = result["experience_ids"]; + fn(experienceIds); +} + +//------------------------------------------------------------------------- +void LLExperienceCache::getRegionExperiences(CapabilityQuery_t regioncaps, ExperienceGetFn_t fn) +{ + regionExperiences(regioncaps, LLSD(), false, fn); +} + +void LLExperienceCache::setRegionExperiences(CapabilityQuery_t regioncaps, const LLSD &experiences, ExperienceGetFn_t fn) +{ + regionExperiences(regioncaps, experiences, true, fn); +} + +void LLExperienceCache::regionExperiences(CapabilityQuery_t regioncaps, const LLSD &experiences, bool update, ExperienceGetFn_t fn) +{ + // search for experiences owned by the current group + std::string url = regioncaps("RegionExperiences"); + if (url.empty()) + { + LL_WARNS("ExperienceCache") << "No Region Experiences capability" << LL_ENDL; + return; + } + + auto httpRequest = new LLCoroResponder( + boost::bind(&LLExperienceCache::regionExperiencesCoro, this, _1, fn)); + + LLSD result; + if (update) + LLHTTPClient::post(url, experiences, httpRequest); + else + LLHTTPClient::get(url, httpRequest); +} + +void LLExperienceCache::regionExperiencesCoro(const LLCoroResponder& responder, ExperienceGetFn_t fn) +{ + LLSD result = responder.getContent(); + + if (!responder.isGoodStatus(responder.getStatus())) + { +// fn(LLSD()); + return; + } + + fn(result); + +} + +//------------------------------------------------------------------------- +void LLExperienceCache::getExperiencePermission(const LLUUID &experienceId, ExperienceGetFn_t fn) +{ + if (mCapability == nullptr) + { + LL_WARNS("ExperienceCache") << "Capability query method not set." << LL_ENDL; + return; + } + + std::string url = mCapability("ExperiencePreferences") + "?" + experienceId.asString(); + + LLHTTPClient::get(url, new LLCoroResponder( + boost::bind(&LLExperienceCache::experiencePermissionCoro, this, _1, fn))); +} + +void LLExperienceCache::setExperiencePermission(const LLUUID &experienceId, const std::string &permission, ExperienceGetFn_t fn) +{ + if (mCapability == nullptr) + { + LL_WARNS("ExperienceCache") << "Capability query method not set." << LL_ENDL; + return; + } + + std::string url = mCapability("ExperiencePreferences"); + if (url.empty()) + return; + LLSD permData; + LLSD data; + permData["permission"] = permission; + data[experienceId.asString()] = permData; + + LLHTTPClient::put(url, data, new LLCoroResponder( + boost::bind(&LLExperienceCache::experiencePermissionCoro, this, _1, fn))); +} + +void LLExperienceCache::forgetExperiencePermission(const LLUUID &experienceId, ExperienceGetFn_t fn) +{ + if (mCapability == nullptr) + { + LL_WARNS("ExperienceCache") << "Capability query method not set." << LL_ENDL; + return; + } + + std::string url = mCapability("ExperiencePreferences") + "?" + experienceId.asString(); + LLHTTPClient::del(url, new LLCoroResponder( + boost::bind(&LLExperienceCache::experiencePermissionCoro, this, _1, fn))); +} + +void LLExperienceCache::experiencePermissionCoro(const LLCoroResponder& responder, ExperienceGetFn_t fn) +{ + // search for experiences owned by the current group + + LLSD result = responder.getContent(); + + if (responder.isGoodStatus(responder.getStatus())) + { + fn(result); + } +} + +//------------------------------------------------------------------------- +void LLExperienceCache::getExperienceAdmin(const LLUUID &experienceId, ExperienceGetFn_t fn) +{ + if (mCapability == nullptr) + { + LL_WARNS("ExperienceCache") << "Capability query method not set." << LL_ENDL; + return; + } + + std::string url = mCapability("IsExperienceAdmin"); + if (url.empty()) + { + LL_WARNS("ExperienceCache") << "No Region Experiences capability" << LL_ENDL; + return; + } + url += "?experience_id=" + experienceId.asString(); + + LLHTTPClient::get(url, new LLCoroResponder( + boost::bind(fn, boost::bind(&LLCoroResponder::getContent, _1)))); +} + +//------------------------------------------------------------------------- +void LLExperienceCache::updateExperience(LLSD updateData, ExperienceGetFn_t fn) +{ + if (mCapability == nullptr) + { + LL_WARNS("ExperienceCache") << "Capability query method not set." << LL_ENDL; + return; + } + + std::string url = mCapability("UpdateExperience"); + if (url.empty()) + { + LL_WARNS("ExperienceCache") << "No Region Experiences capability" << LL_ENDL; + return; + } + + updateData.erase(LLExperienceCache::QUOTA); + updateData.erase(LLExperienceCache::EXPIRES); + updateData.erase(LLExperienceCache::AGENT_ID); + + LLHTTPClient::post(url, updateData, new LLCoroResponder( + boost::bind(fn, boost::bind(&LLCoroResponder::getContent, _1)))); +} + +//========================================================================= +void LLExperienceCacheImpl::mapKeys(const LLSD& legacyKeys) +{ + for (const auto& exp : legacyKeys.array()) + { + if (exp.has(LLExperienceCacheImpl::EXPERIENCE_ID) && exp.has(LLExperienceCacheImpl::PRIVATE_KEY)) + { + LLExperienceCacheImpl::privateToPublicKeyMap[exp[LLExperienceCacheImpl::PRIVATE_KEY].asUUID()] = + exp[LLExperienceCacheImpl::EXPERIENCE_ID].asUUID(); + } + } +} + +// Return time to retry a request that generated an error, based on +// error type and headers. Return value is seconds-since-epoch. +F64 LLExperienceCacheImpl::getErrorRetryDeltaTime(S32 status, const AIHTTPReceivedHeaders& headers) +{ + // Retry-After takes priority + std::string retry_afters; + if (headers.getFirstValue("retry-after", retry_afters)) + { + LLSD retry_after(retry_afters); + // We only support the delta-seconds type + S32 delta_seconds = retry_after.asInteger(); + if (delta_seconds > 0) + { + // ...valid delta-seconds + return F64(delta_seconds); + } + } + + // If no Retry-After, look for Cache-Control max-age + // Allow the header to override the default + std::string cache_control; + if (headers.getFirstValue("cache-control", cache_control)) + { + S32 max_age = 0; + if (LLExperienceCacheImpl::maxAgeFromCacheControl(cache_control, &max_age)) + { + LL_WARNS("ExperienceCache") + << "got EXPIRES from headers, max_age " << max_age + << LL_ENDL; + return (F64)max_age; + } + } + + // No information in header, make a guess + if (status == 503) + { + // ...service unavailable, retry soon + const F64 SERVICE_UNAVAILABLE_DELAY = 600.0; // 10 min + return SERVICE_UNAVAILABLE_DELAY; + } + else if (status == 499) + { + // ...we were probably too busy, retry quickly + const F64 BUSY_DELAY = 10.0; // 10 seconds + return BUSY_DELAY; + + } + else + { + // ...other unexpected error + const F64 DEFAULT_DELAY = 3600.0; // 1 hour + return DEFAULT_DELAY; + } +} + +bool LLExperienceCacheImpl::maxAgeFromCacheControl(const std::string& cache_control, S32 *max_age) +{ + // Split the string on "," to get a list of directives + typedef boost::tokenizer > tokenizer; + tokenizer directives(cache_control, COMMA_SEPARATOR); + + tokenizer::iterator token_it = directives.begin(); + for ( ; token_it != directives.end(); ++token_it) + { + // Tokens may have leading or trailing whitespace + std::string token = *token_it; + LLStringUtil::trim(token); + + if (token.compare(0, MAX_AGE.size(), MAX_AGE) == 0) + { + // ...this token starts with max-age, so let's chop it up by "=" + tokenizer subtokens(token, EQUALS_SEPARATOR); + tokenizer::iterator subtoken_it = subtokens.begin(); + + // Must have a token + if (subtoken_it == subtokens.end()) return false; + std::string subtoken = *subtoken_it; + + // Must exactly equal "max-age" + LLStringUtil::trim(subtoken); + if (subtoken != MAX_AGE) return false; + + // Must have another token + ++subtoken_it; + if (subtoken_it == subtokens.end()) return false; + subtoken = *subtoken_it; + + // Must be a valid integer + // *NOTE: atoi() returns 0 for invalid values, so we have to + // check the string first. + // *TODO: Do servers ever send "0000" for zero? We don't handle it + LLStringUtil::trim(subtoken); + if (subtoken == "0") + { + *max_age = 0; + return true; + } + S32 val = atoi( subtoken.c_str() ); + if (val > 0 && val < S32_MAX) + { + *max_age = val; + return true; + } + return false; + } + } + return false; +} + + + + diff --git a/indra/llmessage/llexperiencecache.h b/indra/llmessage/llexperiencecache.h new file mode 100644 index 000000000..cddf5f67e --- /dev/null +++ b/indra/llmessage/llexperiencecache.h @@ -0,0 +1,181 @@ +/** + * @file llexperiencecache.h + * @brief Caches information relating to experience keys + * + * $LicenseInfo:firstyear=2012&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, 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_LLEXPERIENCECACHE_H +#define LL_LLEXPERIENCECACHE_H + +#include "linden_common.h" +#include "llsingleton.h" +#include "llframetimer.h" +#include "llsd.h" +#include + +struct LLCoroResponder; +class LLSD; +class LLUUID; + + +class LLExperienceCache final : public LLSingleton < LLExperienceCache > +{ + friend class LLSingleton; + LLExperienceCache(); + +public: + typedef std::function CapabilityQuery_t; + typedef std::function ExperienceGetFn_t; + + void idleCoro(); + void setCapabilityQuery(CapabilityQuery_t queryfn); + void cleanup(); + + //------------------------------------------- + // Cache methods + void erase(const LLUUID& key); + bool fetch(const LLUUID& key, bool refresh = false); + void insert(const LLSD& experience_data); + const LLSD& get(const LLUUID& key); + void get(const LLUUID& key, ExperienceGetFn_t slot); // If name information is in cache, callback will be called immediately. + + bool isRequestPending(const LLUUID& public_key); + + //------------------------------------------- + void fetchAssociatedExperience(const LLUUID& objectId, const LLUUID& itemId, ExperienceGetFn_t fn) { fetchAssociatedExperience(objectId, itemId, LLStringUtil::null, fn); } + void fetchAssociatedExperience(const LLUUID& objectId, const LLUUID& itemId, std::string url, ExperienceGetFn_t fn); + void findExperienceByName(const std::string text, int page, ExperienceGetFn_t fn); + void getGroupExperiences(const LLUUID &groupId, ExperienceGetFn_t fn); + + // the Get/Set Region Experiences take a CapabilityQuery to get the capability since + // the region being queried may not be the region that the agent is standing on. + void getRegionExperiences(CapabilityQuery_t regioncaps, ExperienceGetFn_t fn); + void setRegionExperiences(CapabilityQuery_t regioncaps, const LLSD &experiences, ExperienceGetFn_t fn); + + void getExperiencePermission(const LLUUID &experienceId, ExperienceGetFn_t fn); + void setExperiencePermission(const LLUUID &experienceId, const std::string &permission, ExperienceGetFn_t fn); + void forgetExperiencePermission(const LLUUID &experienceId, ExperienceGetFn_t fn); + + void getExperienceAdmin(const LLUUID &experienceId, ExperienceGetFn_t fn); + + void updateExperience(LLSD updateData, ExperienceGetFn_t fn); + //------------------------------------------- + static const std::string NAME; // "name" + static const std::string EXPERIENCE_ID; // "public_id" + static const std::string AGENT_ID; // "agent_id" + static const std::string GROUP_ID; // "group_id" + static const std::string PROPERTIES; // "properties" + static const std::string EXPIRES; // "expiration" + static const std::string DESCRIPTION; // "description" + static const std::string QUOTA; // "quota" + static const std::string MATURITY; // "maturity" + static const std::string METADATA; // "extended_metadata" + static const std::string SLURL; // "slurl" + + static const std::string MISSING; // "DoesNotExist" + + // should be in sync with experience-api/experiences/models.py + static const int PROPERTY_INVALID; // 1 << 0 + static const int PROPERTY_PRIVILEGED; // 1 << 3 + static const int PROPERTY_GRID; // 1 << 4 + static const int PROPERTY_PRIVATE; // 1 << 5 + static const int PROPERTY_DISABLED; // 1 << 6 + static const int PROPERTY_SUSPENDED; // 1 << 7 + +private: + virtual ~LLExperienceCache(); + + void initSingleton() override; + + // Callback types for get() + typedef boost::signals2::signal < void(const LLSD &) > callback_signal_t; + typedef boost::shared_ptr signal_ptr; + // May have multiple callbacks for a single ID, which are + // represented as multiple slots bound to the signal. + // Avoid copying signals via pointers. + typedef std::map signal_map_t; + typedef std::map cache_t; + + typedef uuid_set_t RequestQueue_t; + typedef std::map PendingQueue_t; + + //-------------------------------------------- + static const std::string PRIVATE_KEY; // "private_id" + + // default values + static const F64 DEFAULT_EXPIRATION; // 600.0 + static const S32 DEFAULT_QUOTA; // 128 this is megabytes + static const int SEARCH_PAGE_SIZE; + +//-------------------------------------------- + void processExperience(const LLUUID& public_key, const LLSD& experience); + +//-------------------------------------------- + cache_t mCache; + signal_map_t mSignalMap; + RequestQueue_t mRequestQueue; + PendingQueue_t mPendingQueue; + + LLFrameTimer mEraseExpiredTimer; // Periodically clean out expired entries from the cache + CapabilityQuery_t mCapability; + std::string mCacheFileName; + bool mShutdown; + + void eraseExpired(); + void requestExperiencesCoro(const LLCoroResponder& responder, RequestQueue_t); + void requestExperiences(); + + void fetchAssociatedExperienceCoro(const LLCoroResponder& responder, ExperienceGetFn_t); + void findExperienceByNameCoro(const LLCoroResponder& responder, ExperienceGetFn_t); + void getGroupExperiencesCoro(const LLCoroResponder& responder, ExperienceGetFn_t); + void regionExperiences(CapabilityQuery_t regioncaps, const LLSD& experiences, bool update, ExperienceGetFn_t fn); + void regionExperiencesCoro(const LLCoroResponder& responder, ExperienceGetFn_t fn); + void experiencePermissionCoro(const LLCoroResponder& responder, ExperienceGetFn_t fn); + + void bootstrap(const LLSD& legacyKeys, int initialExpiration); + void exportFile(std::ostream& ostr) const; + void importFile(std::istream& istr); + + // + const cache_t& getCached(); + + // maps an experience private key to the experience id + LLUUID getExperienceId(const LLUUID& private_key, bool null_if_not_found=false); + + //===================================================================== + inline friend std::ostream &operator << (std::ostream &os, const LLExperienceCache &cache) + { + cache.exportFile(os); + return os; + } + + inline friend std::istream &operator >> (std::istream &is, LLExperienceCache &cache) + { + cache.importFile(is); + return is; + } +}; + +#endif // LL_LLEXPERIENCECACHE_H diff --git a/indra/llmessage/llregionflags.h b/indra/llmessage/llregionflags.h index 70194342a..95faff21b 100644 --- a/indra/llmessage/llregionflags.h +++ b/indra/llmessage/llregionflags.h @@ -168,19 +168,20 @@ const U32 ESTATE_ACCESS_ALL = ESTATE_ACCESS_ALLOWED_AGENTS | ESTATE_ACCESS_BANNED_AGENTS | ESTATE_ACCESS_MANAGERS; -// for EstateOwnerRequest, estateaccessdelta message -const U32 ESTATE_ACCESS_APPLY_TO_ALL_ESTATES = 1 << 0; -const U32 ESTATE_ACCESS_APPLY_TO_MANAGED_ESTATES = 1 << 1; +// for EstateOwnerRequest, estateaccessdelta, estateexperiencedelta messages +const U32 ESTATE_ACCESS_APPLY_TO_ALL_ESTATES = 1U << 0; +const U32 ESTATE_ACCESS_APPLY_TO_MANAGED_ESTATES = 1U << 1; -const U32 ESTATE_ACCESS_ALLOWED_AGENT_ADD = 1 << 2; -const U32 ESTATE_ACCESS_ALLOWED_AGENT_REMOVE = 1 << 3; -const U32 ESTATE_ACCESS_ALLOWED_GROUP_ADD = 1 << 4; -const U32 ESTATE_ACCESS_ALLOWED_GROUP_REMOVE = 1 << 5; -const U32 ESTATE_ACCESS_BANNED_AGENT_ADD = 1 << 6; -const U32 ESTATE_ACCESS_BANNED_AGENT_REMOVE = 1 << 7; -const U32 ESTATE_ACCESS_MANAGER_ADD = 1 << 8; -const U32 ESTATE_ACCESS_MANAGER_REMOVE = 1 << 9; -const U32 ESTATE_ACCESS_NO_REPLY = 1 << 10; +const U32 ESTATE_ACCESS_ALLOWED_AGENT_ADD = 1U << 2; +const U32 ESTATE_ACCESS_ALLOWED_AGENT_REMOVE = 1U << 3; +const U32 ESTATE_ACCESS_ALLOWED_GROUP_ADD = 1U << 4; +const U32 ESTATE_ACCESS_ALLOWED_GROUP_REMOVE = 1U << 5; +const U32 ESTATE_ACCESS_BANNED_AGENT_ADD = 1U << 6; +const U32 ESTATE_ACCESS_BANNED_AGENT_REMOVE = 1U << 7; +const U32 ESTATE_ACCESS_MANAGER_ADD = 1U << 8; +const U32 ESTATE_ACCESS_MANAGER_REMOVE = 1U << 9; +const U32 ESTATE_ACCESS_NO_REPLY = 1U << 10; +const U32 ESTATE_ACCESS_FAILED_BAN_ESTATE_MANAGER = 1U << 11; const S32 ESTATE_MAX_MANAGERS = 15; const S32 ESTATE_MAX_ACCESS_IDS = 500; // max for access, banned @@ -191,6 +192,26 @@ const U32 SWD_OTHERS_LAND_ONLY = (1 << 0); const U32 SWD_ALWAYS_RETURN_OBJECTS = (1 << 1); const U32 SWD_SCRIPTED_ONLY = (1 << 2); +// Controls experience key validity in the estate +const U32 EXPERIENCE_KEY_TYPE_NONE = 0; +const U32 EXPERIENCE_KEY_TYPE_BLOCKED = 1; +const U32 EXPERIENCE_KEY_TYPE_ALLOWED = 2; +const U32 EXPERIENCE_KEY_TYPE_TRUSTED = 3; + +const U32 EXPERIENCE_KEY_TYPE_FIRST = EXPERIENCE_KEY_TYPE_BLOCKED; +const U32 EXPERIENCE_KEY_TYPE_LAST = EXPERIENCE_KEY_TYPE_TRUSTED; + +// +const U32 ESTATE_EXPERIENCE_TRUSTED_ADD = 1U << 2; +const U32 ESTATE_EXPERIENCE_TRUSTED_REMOVE = 1U << 3; +const U32 ESTATE_EXPERIENCE_ALLOWED_ADD = 1U << 4; +const U32 ESTATE_EXPERIENCE_ALLOWED_REMOVE = 1U << 5; +const U32 ESTATE_EXPERIENCE_BLOCKED_ADD = 1U << 6; +const U32 ESTATE_EXPERIENCE_BLOCKED_REMOVE = 1U << 7; + +const S32 ESTATE_MAX_EXPERIENCE_IDS = 8; + + #endif diff --git a/indra/llmessage/message_prehash.cpp b/indra/llmessage/message_prehash.cpp index 6598a402c..a9201ef46 100644 --- a/indra/llmessage/message_prehash.cpp +++ b/indra/llmessage/message_prehash.cpp @@ -1393,6 +1393,8 @@ char const* const _PREHASH_AppearanceVersion = LLMessageStringTable::getInstance char const* const _PREHASH_CofVersion = LLMessageStringTable::getInstance()->getString("CofVersion"); char const* const _PREHASH_AppearanceHover = LLMessageStringTable::getInstance()->getString("AppearanceHover"); char const* const _PREHASH_HoverHeight = LLMessageStringTable::getInstance()->getString("HoverHeight"); +char const* const _PREHASH_Experience = LLMessageStringTable::getInstance()->getString("Experience"); +char const* const _PREHASH_ExperienceID = LLMessageStringTable::getInstance()->getString("ExperienceID"); // Aurora Sim char const* const _PREHASH_RegionSizeX = LLMessageStringTable::getInstance()->getString("RegionSizeX"); diff --git a/indra/llmessage/message_prehash.h b/indra/llmessage/message_prehash.h index e57e2379e..390ea8ff7 100644 --- a/indra/llmessage/message_prehash.h +++ b/indra/llmessage/message_prehash.h @@ -1393,6 +1393,8 @@ extern char const* const _PREHASH_AppearanceVersion; extern char const* const _PREHASH_CofVersion; extern char const* const _PREHASH_AppearanceHover; extern char const* const _PREHASH_HoverHeight; +extern char const* const _PREHASH_Experience; +extern char const* const _PREHASH_ExperienceID; // Aurora Sim extern char const* const _PREHASH_RegionSizeX; diff --git a/indra/llplugin/CMakeLists.txt b/indra/llplugin/CMakeLists.txt index 3a903080e..7ec2f5c5f 100644 --- a/indra/llplugin/CMakeLists.txt +++ b/indra/llplugin/CMakeLists.txt @@ -7,6 +7,7 @@ include(LLCommon) include(LLMath) include(LLMessage) include(LLRender) +include(Boost) include_directories( ${LLCOMMON_INCLUDE_DIRS} @@ -46,14 +47,6 @@ set(llplugin_HEADER_FILES set_source_files_properties(${llplugin_HEADER_FILES} PROPERTIES HEADER_FILE_ONLY TRUE) -if(NOT WORD_SIZE EQUAL 32) - if(WINDOWS) - # add_definitions(/FIXED:NO) - else(WINDOWS) # not windows therefore gcc LINUX and DARWIN - add_definitions(-fPIC) - endif(WINDOWS) -endif (NOT WORD_SIZE EQUAL 32) - list(APPEND llplugin_SOURCE_FILES ${llplugin_HEADER_FILES}) add_library (llplugin ${llplugin_SOURCE_FILES}) @@ -67,6 +60,8 @@ else() ) endif() +set_target_properties(llplugin PROPERTIES POSITION_INDEPENDENT_CODE TRUE) + add_subdirectory(slplugin) # # Add tests diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp index a6b041c46..daa7f4c8a 100644 --- a/indra/llplugin/llpluginclassmedia.cpp +++ b/indra/llplugin/llpluginclassmedia.cpp @@ -623,12 +623,14 @@ bool LLPluginClassMedia::keyEvent(EKeyEventType type, int key_code, MASK modifie return result; } -void LLPluginClassMedia::scrollEvent(int x, int y, MASK modifiers) +void LLPluginClassMedia::scrollEvent(int x, int y, int clicks_x, int clicks_y, MASK modifiers) { LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "scroll_event"); message.setValueS32("x", x); message.setValueS32("y", y); + message.setValueS32("clicks_x", clicks_x); + message.setValueS32("clicks_y", clicks_y); message.setValue("modifiers", translateModifiers(modifiers)); sendMessage(message); @@ -711,9 +713,9 @@ void LLPluginClassMedia::sendPickFileResponse(const std::vector fil } LLSD file_list = LLSD::emptyArray(); - for (std::vector::const_iterator in_iter = files.begin(); in_iter != files.end(); ++in_iter) + for (const auto& file : files) { - file_list.append(LLSD::String(*in_iter)); + file_list.append(LLSD::String(file)); } message.setValueLLSD("file_list", file_list); diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h index ebb9a36b5..7e8c2e4eb 100644 --- a/indra/llplugin/llpluginclassmedia.h +++ b/indra/llplugin/llpluginclassmedia.h @@ -75,7 +75,7 @@ public: void setAutoScale(bool auto_scale); void setZoomFactor(F64 zoom_factor) { mZoomFactor = zoom_factor; } - void setBackgroundColor(LLColor4 color) { mBackgroundColor = color; }; + void setBackgroundColor(const LLColor4& color) { mBackgroundColor = color; }; void setOwner(LLPluginClassMediaOwner *owner) { mOwner = owner; }; @@ -107,7 +107,7 @@ public: bool keyEvent(EKeyEventType type, int key_code, MASK modifiers, LLSD native_key_data); - void scrollEvent(int x, int y, MASK modifiers); + void scrollEvent(int x, int y, int clicks_x, int clicks_y, MASK modifiers); // enable/disable media plugin debugging messages and info spam void enableMediaPluginDebugging( bool enable ); diff --git a/indra/llplugin/slplugin/CMakeLists.txt b/indra/llplugin/slplugin/CMakeLists.txt index 93a125ea1..f8ab56916 100644 --- a/indra/llplugin/slplugin/CMakeLists.txt +++ b/indra/llplugin/slplugin/CMakeLists.txt @@ -1,7 +1,6 @@ project(SLPlugin) include(00-Common) -include(Linking) include(LLCommon) include(LLPlugin) include(Linking) @@ -69,12 +68,7 @@ target_link_libraries(SLPlugin ${LLCOMMON_LIBRARIES} ${APRUTIL_LIBRARIES} ${PLUGIN_API_WINDOWS_LIBRARIES} -) - -add_dependencies(SLPlugin - ${LLPLUGIN_LIBRARIES} - ${LLMESSAGE_LIBRARIES} - ${LLCOMMON_LIBRARIES} + ${PTHREAD_LIBRARY} ) if (DARWIN) diff --git a/indra/llprimitive/llprimitive.h b/indra/llprimitive/llprimitive.h index e0dbd13d4..d69c73199 100644 --- a/indra/llprimitive/llprimitive.h +++ b/indra/llprimitive/llprimitive.h @@ -320,7 +320,7 @@ public: // - Vir struct LLTEContents { - static const U32 MAX_TES = 32; + static const U32 MAX_TES = 45; U8 image_data[MAX_TES*16]; U8 colors[MAX_TES*4]; diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index 11b8c800e..3caf919eb 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -37,6 +37,7 @@ set(llui_SOURCE_FILES lldraghandle.cpp lleditmenuhandler.cpp llfiltereditor.cpp + llflatlistview.cpp llfloater.cpp llflyoutbutton.cpp llfocusmgr.cpp @@ -116,6 +117,7 @@ set(llui_HEADER_FILES lldraghandle.h lleditmenuhandler.h llfiltereditor.h + llflatlistview.h llfloater.h llflyoutbutton.h llfocusmgr.h diff --git a/indra/llui/lfidbearer.cpp b/indra/llui/lfidbearer.cpp index cc7a3f988..6ac6714d5 100644 --- a/indra/llui/lfidbearer.cpp +++ b/indra/llui/lfidbearer.cpp @@ -20,13 +20,39 @@ #include "linden_common.h" #include "lfidbearer.h" #include "llmenugl.h" +#include "lluictrlfactory.h" -std::vector LFIDBearer::sMenus = {}; -LFIDBearer* LFIDBearer::sActive = nullptr; +const std::array LFIDBearer::sMenuStrings +{ + "menu_avs_list.xml" // 0 +, "menu_groups_list.xml" // 1 +, "menu_objects_list.xml" // 2 +, "menu_experiences.xml" // 3 +}; +std::array LFIDBearer::sMenus {}; + +const LFIDBearer* LFIDBearer::sActive = nullptr; +LFIDBearer::Type LFIDBearer::sActiveType = LFIDBearer::AVATAR; +uuid_vec_t LFIDBearer::sActiveIDs {}; + +void LFIDBearer::buildMenus() +{ + auto& factory = LLUICtrlFactory::instance(); + for (auto i = 0; i < COUNT; ++i) + sMenus[i] = factory.buildMenu(sMenuStrings[i], LLMenuGL::sMenuContainer); +} + +LLMenuGL* LFIDBearer::showMenu(LLView* self, const std::string& menu_name, S32 x, S32 y, std::function on_menu_built) +{ + auto menu = LLUICtrlFactory::instance().buildMenu(menu_name, LLMenuGL::sMenuContainer); + if (on_menu_built) on_menu_built(menu); + showMenu(self, menu, x, y); + return menu; +} void LFIDBearer::showMenu(LLView* self, LLMenuGL* menu, S32 x, S32 y) { - sActive = this; // Menu listeners rely on this + setActive(); // Menu listeners rely on this menu->buildDrawLabels(); menu->updateParent(LLMenuGL::sMenuContainer); LLMenuGL::showPopup(self, menu, x, y); diff --git a/indra/llui/lfidbearer.h b/indra/llui/lfidbearer.h index 8b4c7684d..3f434a5a7 100644 --- a/indra/llui/lfidbearer.h +++ b/indra/llui/lfidbearer.h @@ -1,6 +1,7 @@ /* Copyright (C) 2019 Liru Færs * * LFIDBearer is a class that holds an ID or IDs that menus can use + * This class also bears the type of ID/IDs that it is holding * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -26,20 +27,47 @@ class LLView; struct LFIDBearer { + enum Type : S8 + { + MULTIPLE = -2, + NONE = -1, + AVATAR = 0, + GROUP, + OBJECT, + EXPERIENCE, + COUNT + }; + virtual ~LFIDBearer() { if (sActive == this) sActive = nullptr; } virtual LLUUID getStringUUIDSelectedItem() const = 0; - virtual uuid_vec_t getSelectedIDs() const = 0; - virtual S32 getNumSelected() const = 0; + virtual uuid_vec_t getSelectedIDs() const { return { getStringUUIDSelectedItem() }; } + virtual Type getSelectedType() const { return AVATAR; } - template static T* getActive() { return static_cast(sActive); } - static LLUUID getActiveSelectedID() { return sActive->getStringUUIDSelectedItem(); } - static uuid_vec_t getActiveSelectedIDs() { return sActive->getSelectedIDs(); } - static S32 getActiveNumSelected() { return sActive->getNumSelected(); } + template static const T* getActive() { return static_cast(sActive); } + static const LLUUID& getActiveSelectedID() { return sActiveIDs.empty() ? LLUUID::null : sActiveIDs[0]; } + static const uuid_vec_t& getActiveSelectedIDs() { return sActiveIDs; } + static size_t getActiveNumSelected() { return sActiveIDs.size(); } + static const Type& getActiveType() { return sActiveType; } + void setActive() const + { + sActive = this; + sActiveType = getSelectedType(); + sActiveIDs = getSelectedIDs(); + //sActiveIDs or even some kinda hybrid map, if Type is MULTIPLE fill the vals? and remove a buncha virtual functions? + } + + static void buildMenus(); + LLMenuGL* showMenu(LLView* self, const std::string& menu_name, S32 x, S32 y, std::function on_menu_built = nullptr); void showMenu(LLView* self, LLMenuGL* menu, S32 x, S32 y); - static void addCommonMenu(LLMenuGL* menu) { sMenus.push_back(menu); } protected: - static std::vector sMenus; // Menus that recur, such as general avatars or groups menus - static LFIDBearer* sActive; + // Menus that recur, such as general avatars or groups menus + static const std::array sMenuStrings; + static std::array sMenus; + +private: + static const LFIDBearer* sActive; + static Type sActiveType; + static uuid_vec_t sActiveIDs; }; diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp index dd39a5ab0..284aa7750 100644 --- a/indra/llui/llcombobox.cpp +++ b/indra/llui/llcombobox.cpp @@ -446,8 +446,7 @@ void LLComboBox::setLabel(const LLStringExplicit& name) if (!mAllowTextEntry) { - mButton->setLabelUnselected(name); - mButton->setLabelSelected(name); + mButton->setLabel(name); } } @@ -465,9 +464,7 @@ void LLComboBox::updateLabel() // the combo button label. if (!mAllowTextEntry) { - std::string label = getSelectedItemLabel(); - mButton->setLabelUnselected(label); - mButton->setLabelSelected(label); + mButton->setLabel(getSelectedItemLabel()); } } @@ -513,13 +510,16 @@ void LLComboBox::onFocusLost() void LLComboBox::setButtonVisible(BOOL visible) { + static LLUICachedControl drop_shadow_button ("DropShadowButton", 0); + mButton->setVisible(visible); if (mTextEntry) { LLRect text_entry_rect(0, getRect().getHeight(), getRect().getWidth(), 0); if (visible) { - text_entry_rect.mRight -= llmax(8,mArrowImage->getWidth()) + 2 * LLUI::sConfigGroup->getS32("DropShadowButton"); + S32 arrow_width = mArrowImage ? mArrowImage->getWidth() : 0; + text_entry_rect.mRight -= llmax(8,arrow_width) + 2 * drop_shadow_button; } //mTextEntry->setRect(text_entry_rect); mTextEntry->reshape(text_entry_rect.getWidth(), text_entry_rect.getHeight(), TRUE); @@ -558,18 +558,21 @@ S32 LLComboBox::getCurrentIndex() const void LLComboBox::updateLayout() { + static LLUICachedControl drop_shadow_button ("DropShadowButton", 0); LLRect rect = getLocalRect(); if (mAllowTextEntry) { - S32 shadow_size = LLUI::sConfigGroup->getS32("DropShadowButton"); - mButton->setRect(LLRect( getRect().getWidth() - llmax(8,mArrowImage->getWidth()) - 2 * shadow_size, + S32 arrow_width = mArrowImage ? mArrowImage->getWidth() : 0; + S32 shadow_size = drop_shadow_button; + mButton->setRect(LLRect( getRect().getWidth() - llmax(8,arrow_width) - 2 * shadow_size, rect.mTop, rect.mRight, rect.mBottom)); mButton->setTabStop(FALSE); + mButton->setHAlign(LLFontGL::HCENTER); if (!mTextEntry) { LLRect text_entry_rect(0, getRect().getHeight(), getRect().getWidth(), 0); - text_entry_rect.mRight -= llmax(8,mArrowImage->getWidth()) + 2 * shadow_size; + text_entry_rect.mRight -= llmax(8,arrow_width) + 2 * drop_shadow_button; // clear label on button std::string cur_label = mButton->getLabelSelected(); mTextEntry = new LLLineEditor(std::string("combo_text_entry"), @@ -718,6 +721,7 @@ void LLComboBox::showList() mList->setVisible(TRUE); setUseBoundingRect(TRUE); +// updateBoundingRect(); } void LLComboBox::hideList() @@ -744,6 +748,7 @@ void LLComboBox::hideList() { gFocusMgr.setTopCtrl(NULL); } +// updateBoundingRect(); } } @@ -1029,9 +1034,7 @@ void LLComboBox::onTextEntry(LLLineEditor* line_editor) void LLComboBox::updateSelection() { - if(mSuppressAutoComplete) { - return; - } + if(mSuppressAutoComplete) return; LLWString left_wstring = mTextEntry->getWText().substr(0, mTextEntry->getCursor()); // user-entered portion of string, based on assumption that any selected @@ -1242,3 +1245,25 @@ BOOL LLComboBox::selectItemRange( S32 first, S32 last ) return mList->selectItemRange(first, last); } + +/* Singu Note: This isn't very necessary for now, let's not bother. +static LLRegisterWidget register_icons_combo_box("icons_combo_box"); + +LLIconsComboBox::Params::Params() +: icon_column("icon_column", ICON_COLUMN), + label_column("label_column", LABEL_COLUMN) +{} + +LLIconsComboBox::LLIconsComboBox(const LLIconsComboBox::Params& p) +: LLComboBox(p), + mIconColumnIndex(p.icon_column), + mLabelColumnIndex(p.label_column) +{} + +const std::string LLIconsComboBox::getSelectedItemLabel(S32 column) const +{ + mButton->setImageOverlay(LLComboBox::getSelectedItemLabel(mIconColumnIndex), mButton->getImageOverlayHAlign()); + + return LLComboBox::getSelectedItemLabel(mLabelColumnIndex); +} +*/ diff --git a/indra/llui/lleditmenuhandler.h b/indra/llui/lleditmenuhandler.h index d72283cd9..966ab352e 100644 --- a/indra/llui/lleditmenuhandler.h +++ b/indra/llui/lleditmenuhandler.h @@ -49,7 +49,7 @@ public: virtual void cut() {}; virtual BOOL canCut() const { return FALSE; } - virtual void copy() {}; + virtual void copy() const {}; virtual BOOL canCopy() const { return FALSE; } virtual void paste() {}; diff --git a/indra/llui/llflatlistview.cpp b/indra/llui/llflatlistview.cpp new file mode 100644 index 000000000..205bea49d --- /dev/null +++ b/indra/llui/llflatlistview.cpp @@ -0,0 +1,1464 @@ +/** + * @file llflatlistview.cpp + * @brief LLFlatListView base class and extension to support messages for several cases of an empty list. + * + * $LicenseInfo:firstyear=2009&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llpanel.h" +#include "lltextbox.h" +#include "lluictrlfactory.h" + +#include "llflatlistview.h" + +static const LLRegisterWidget flat_list_view("flat_list_view"); + +const LLSD SELECTED_EVENT = LLSD().with("selected", true); +const LLSD UNSELECTED_EVENT = LLSD().with("selected", false); + +//forward declaration +bool llsds_are_equal(const LLSD& llsd_1, const LLSD& llsd_2); + +LLFlatListView::Params::Params() +: allow_select("allow_select"), + multi_select("multi_select"), + keep_one_selected("keep_one_selected"), + keep_selection_visible_on_reshape("keep_selection_visible_on_reshape",false), + item_pad("item_pad"), + no_items_text("no_items_text") +{}; + +void LLFlatListView::reshape(S32 width, S32 height, BOOL called_from_parent /* = TRUE */) +{ + S32 delta = height - getRect().getHeight(); + LLScrollContainer::reshape(width, height, called_from_parent); + setItemsNoScrollWidth(width); + rearrangeItems(); + + if (delta!= 0 && mKeepSelectionVisibleOnReshape) + { + ensureSelectedVisible(); + } +} + +const LLRect& LLFlatListView::getItemsRect() const +{ + return mItemsPanel->getRect(); +} + +bool LLFlatListView::addItem(LLPanel * item, const LLSD& value /*= LLUUID::null*/, EAddPosition pos /*= ADD_BOTTOM*/,bool rearrange /*= true*/) +{ + if (!item) return false; + if (value.isUndefined()) return false; + + //force uniqueness of items, easiest check but unreliable + if (item->getParent() == mItemsPanel) return false; + + item_pair_t* new_pair = new item_pair_t(item, value); + switch (pos) + { + case ADD_TOP: + mItemPairs.push_front(new_pair); + //in LLView::draw() children are iterated in backorder + mItemsPanel->addChildInBack(item); + break; + case ADD_BOTTOM: + mItemPairs.push_back(new_pair); + mItemsPanel->addChild(item); + break; + default: + break; + } + + //_4 is for MASK + item->setMouseDownCallback(boost::bind(&LLFlatListView::onItemMouseClick, this, new_pair, _4)); + item->setRightMouseDownCallback(boost::bind(&LLFlatListView::onItemRightMouseClick, this, new_pair, _4)); + + // Children don't accept the focus + item->setTabStop(false); + + if (rearrange) + { + rearrangeItems(); + notifyParentItemsRectChanged(); + } + return true; +} + +bool LLFlatListView::addItemPairs(pairs_list_t panel_list, bool rearrange /*= true*/) +{ + if (!mItemComparator) + { + LL_WARNS_ONCE() << "No comparator specified for inserting FlatListView items." << LL_ENDL; + return false; + } + if (panel_list.size() == 0) + { + return false; + } + + // presort list so that it will be easier to sort elements into mItemPairs + panel_list.sort(ComparatorAdaptor(*mItemComparator)); + + pairs_const_iterator_t new_pair_it = panel_list.begin(); + item_pair_t* new_pair = *new_pair_it; + pairs_iterator_t pair_it = mItemPairs.begin(); + item_pair_t* item_pair = *pair_it; + + // sort panel_list into mItemPars + while (new_pair_it != panel_list.end() && pair_it != mItemPairs.end()) + { + if (!new_pair->first || new_pair->first->getParent() == mItemsPanel) + { + // iterator already used or we are reusing existing panel + new_pair_it++; + new_pair = *new_pair_it; + } + else if (mItemComparator->compare(new_pair->first, item_pair->first)) + { + LLPanel* panel = new_pair->first; + + mItemPairs.insert(pair_it, new_pair); + mItemsPanel->addChild(panel); + + //_4 is for MASK + panel->setMouseDownCallback(boost::bind(&LLFlatListView::onItemMouseClick, this, new_pair, _4)); + panel->setRightMouseDownCallback(boost::bind(&LLFlatListView::onItemRightMouseClick, this, new_pair, _4)); + // Children don't accept the focus + panel->setTabStop(false); + } + else + { + pair_it++; + item_pair = *pair_it; + } + } + + // Add what is left of panel_list into the end of mItemPairs. + for (; new_pair_it != panel_list.end(); ++new_pair_it) + { + item_pair_t* item_pair = *new_pair_it; + LLPanel *panel = item_pair->first; + if (panel && panel->getParent() != mItemsPanel) + { + mItemPairs.push_back(item_pair); + mItemsPanel->addChild(panel); + + //_4 is for MASK + panel->setMouseDownCallback(boost::bind(&LLFlatListView::onItemMouseClick, this, item_pair, _4)); + panel->setRightMouseDownCallback(boost::bind(&LLFlatListView::onItemRightMouseClick, this, item_pair, _4)); + // Children don't accept the focus + panel->setTabStop(false); + } + } + + if (rearrange) + { + rearrangeItems(); + notifyParentItemsRectChanged(); + } + return true; +} + + +bool LLFlatListView::insertItemAfter(LLPanel* after_item, LLPanel* item_to_add, const LLSD& value /*= LLUUID::null*/) +{ + if (!after_item) return false; + if (!item_to_add) return false; + if (value.isUndefined()) return false; + + if (mItemPairs.empty()) return false; + + //force uniqueness of items, easiest check but unreliable + if (item_to_add->getParent() == mItemsPanel) return false; + + item_pair_t* after_pair = getItemPair(after_item); + if (!after_pair) return false; + + item_pair_t* new_pair = new item_pair_t(item_to_add, value); + if (after_pair == mItemPairs.back()) + { + mItemPairs.push_back(new_pair); + mItemsPanel->addChild(item_to_add); + } + else + { + pairs_iterator_t it = mItemPairs.begin(); + for (; it != mItemPairs.end(); ++it) + { + if (*it == after_pair) + { + // insert new elements before the element at position of passed iterator. + mItemPairs.insert(++it, new_pair); + mItemsPanel->addChild(item_to_add); + break; + } + } + } + + //_4 is for MASK + item_to_add->setMouseDownCallback(boost::bind(&LLFlatListView::onItemMouseClick, this, new_pair, _4)); + item_to_add->setRightMouseDownCallback(boost::bind(&LLFlatListView::onItemRightMouseClick, this, new_pair, _4)); + + rearrangeItems(); + notifyParentItemsRectChanged(); + return true; +} + + +bool LLFlatListView::removeItem(LLPanel* item, bool rearrange) +{ + if (!item) return false; + if (item->getParent() != mItemsPanel) return false; + + item_pair_t* item_pair = getItemPair(item); + if (!item_pair) return false; + + return removeItemPair(item_pair, rearrange); +} + +bool LLFlatListView::removeItemByValue(const LLSD& value, bool rearrange) +{ + if (value.isUndefined()) return false; + + item_pair_t* item_pair = getItemPair(value); + if (!item_pair) return false; + + return removeItemPair(item_pair, rearrange); +} + +bool LLFlatListView::removeItemByUUID(const LLUUID& uuid, bool rearrange) +{ + return removeItemByValue(LLSD(uuid), rearrange); +} + +LLPanel* LLFlatListView::getItemByValue(const LLSD& value) const +{ + if (value.isUndefined()) return nullptr; + + item_pair_t* pair = getItemPair(value); + if (pair) return pair->first; + return nullptr; +} + +bool LLFlatListView::valueExists(const LLSD& value) const +{ + if (value.isUndefined()) return false; + item_pair_t* pair = getItemPair(value); + return pair != nullptr; +} + +bool LLFlatListView::selectItem(LLPanel* item, bool select /*= true*/) +{ + if (!item) return false; + if (item->getParent() != mItemsPanel) return false; + + item_pair_t* item_pair = getItemPair(item); + if (!item_pair) return false; + + return selectItemPair(item_pair, select); +} + +bool LLFlatListView::selectItemByValue(const LLSD& value, bool select /*= true*/) +{ + if (value.isUndefined()) return false; + + item_pair_t* item_pair = getItemPair(value); + if (!item_pair) return false; + + return selectItemPair(item_pair, select); +} + +bool LLFlatListView::selectItemByUUID(const LLUUID& uuid, bool select /* = true*/) +{ + return selectItemByValue(LLSD(uuid), select); +} + + +LLSD LLFlatListView::getSelectedValue() const +{ + if (mSelectedItemPairs.empty()) return LLSD(); + + item_pair_t* first_selected_pair = mSelectedItemPairs.front(); + return first_selected_pair->second; +} + +void LLFlatListView::getSelectedValues(std::vector& selected_values) const +{ + if (mSelectedItemPairs.empty()) return; + + for (pairs_const_iterator_t it = mSelectedItemPairs.begin(); it != mSelectedItemPairs.end(); ++it) + { + selected_values.push_back((*it)->second); + } +} + +LLUUID LLFlatListView::getSelectedUUID() const +{ + const LLSD& value = getSelectedValue(); + if (value.isDefined() && value.isUUID()) + { + return value.asUUID(); + } + else + { + return LLUUID::null; + } +} + +void LLFlatListView::getSelectedUUIDs(uuid_vec_t& selected_uuids) const +{ + if (mSelectedItemPairs.empty()) return; + + for (pairs_const_iterator_t it = mSelectedItemPairs.begin(); it != mSelectedItemPairs.end(); ++it) + { + selected_uuids.push_back((*it)->second.asUUID()); + } +} + +LLPanel* LLFlatListView::getSelectedItem() const +{ + if (mSelectedItemPairs.empty()) return nullptr; + + return mSelectedItemPairs.front()->first; +} + +void LLFlatListView::getSelectedItems(std::vector& selected_items) const +{ + if (mSelectedItemPairs.empty()) return; + + for (pairs_const_iterator_t it = mSelectedItemPairs.begin(); it != mSelectedItemPairs.end(); ++it) + { + selected_items.push_back((*it)->first); + } +} + +void LLFlatListView::resetSelection(bool no_commit_on_deselection /*= false*/) +{ + if (mSelectedItemPairs.empty()) return; + + for (pairs_iterator_t it= mSelectedItemPairs.begin(); it != mSelectedItemPairs.end(); ++it) + { + item_pair_t* pair_to_deselect = *it; + LLPanel* item = pair_to_deselect->first; + item->setValue(UNSELECTED_EVENT); + } + + mSelectedItemPairs.clear(); + + if (mCommitOnSelectionChange && !no_commit_on_deselection) + { + onCommit(); + } + + // Stretch selected item rect to ensure it won't be clipped + mSelectedItemsBorder->setRect(getLastSelectedItemRect().stretch(-1)); +} + +void LLFlatListView::setNoItemsCommentText(const std::string& comment_text) +{ + mNoItemsCommentTextbox->setValue(comment_text); +} + +U32 LLFlatListView::size(const bool only_visible_items) const +{ + if (only_visible_items) + { + U32 size = 0; + for (pairs_const_iterator_t + iter = mItemPairs.begin(), + iter_end = mItemPairs.end(); + iter != iter_end; ++iter) + { + if ((*iter)->first->getVisible()) + ++size; + } + return size; + } + else + { + return mItemPairs.size(); + } +} + +void LLFlatListView::clear() +{ + // This will clear mSelectedItemPairs, calling all appropriate callbacks. + resetSelection(); + + // do not use LLView::deleteAllChildren to avoid removing nonvisible items. drag-n-drop for ex. + for (pairs_iterator_t it = mItemPairs.begin(); it != mItemPairs.end(); ++it) + { + mItemsPanel->removeChild((*it)->first); + (*it)->first->die(); + delete *it; + } + mItemPairs.clear(); + + // also set items panel height to zero. Reshape it to allow reshaping of non-item children + LLRect rc = mItemsPanel->getRect(); + rc.mBottom = rc.mTop; + mItemsPanel->reshape(rc.getWidth(), rc.getHeight()); + mItemsPanel->setRect(rc); + + setNoItemsCommentVisible(true); + notifyParentItemsRectChanged(); +} + +void LLFlatListView::sort() +{ + if (!mItemComparator) + { + LL_WARNS() << "No comparator specified for sorting FlatListView items." << LL_ENDL; + return; + } + + mItemPairs.sort(ComparatorAdaptor(*mItemComparator)); + rearrangeItems(); +} + +bool LLFlatListView::updateValue(const LLSD& old_value, const LLSD& new_value) +{ + if (old_value.isUndefined() || new_value.isUndefined()) return false; + if (llsds_are_equal(old_value, new_value)) return false; + + item_pair_t* item_pair = getItemPair(old_value); + if (!item_pair) return false; + + item_pair->second = new_value; + return true; +} + +////////////////////////////////////////////////////////////////////////// +// PROTECTED STUFF +////////////////////////////////////////////////////////////////////////// + +LLFlatListView::LLFlatListView(const std::string& name, const LLRect& rect, bool opaque, const LLColor4& color, const S32& item_pad, bool allow_select, bool multi_select, bool keep_one_selected, bool keep_selection_visible_on_reshape, const std::string& no_items_text) +: LLScrollContainer(name, rect, nullptr, opaque, color) + , mItemComparator(nullptr) + , mItemsPanel(nullptr) + , mItemPad(item_pad) + , mAllowSelection(allow_select) + , mMultipleSelection(multi_select) + , mCommitOnSelectionChange(false) + , mKeepOneItemSelected(keep_one_selected) + , mIsConsecutiveSelection(false) + , mKeepSelectionVisibleOnReshape(keep_selection_visible_on_reshape) + , mPrevNotifyParentRect(LLRect()) + , mNoItemsCommentTextbox(nullptr) +{ + mBorderThickness = getBorderWidth(); + + LLRect scroll_rect = getRect(); + LLRect items_rect; + + setItemsNoScrollWidth(scroll_rect.getWidth()); + items_rect.setLeftTopAndSize(mBorderThickness, scroll_rect.getHeight() - mBorderThickness, mItemsNoScrollWidth, 0); + + mItemsPanel = new LLPanel("items panel", items_rect); + addChild(mItemsPanel); + + //we don't need to stretch in vertical direction on reshaping by a parent + //no bottom following! + mItemsPanel->setFollows(FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_TOP); + + mSelectedItemsBorder = new LLViewBorder( + "scroll border", + getLastSelectedItemRect(), + LLViewBorder::BEVEL_IN); + mSelectedItemsBorder->setVisible(false); + mItemsPanel->addChild(mSelectedItemsBorder); + + { + // create textbox for "No Items" comment text + { + LLRect comment_rect = getRect(); + comment_rect.setOriginAndSize(0, 0, comment_rect.getWidth(), comment_rect.getHeight()); + comment_rect.stretch(-getBorderWidth()); + mNoItemsCommentTextbox = new LLTextBox(no_items_text, comment_rect, no_items_text); + } + mNoItemsCommentTextbox->setBorderVisible(false); + + { + mNoItemsCommentTextbox->setFollows(FOLLOWS_ALL); + } + } +}; + +LLFlatListView::~LLFlatListView() +{ + delete_and_clear(mItemPairs); +} + +// virtual +void LLFlatListView::draw() +{ + // Highlight border if a child of this container has keyboard focus + if ( mSelectedItemsBorder->getVisible() ) + { + mSelectedItemsBorder->setKeyboardFocusHighlight( hasFocus() ); + } + LLScrollContainer::draw(); +} + +// virtual +BOOL LLFlatListView::postBuild() +{ + setTabStop(true); + return LLScrollContainer::postBuild(); +} + +void LLFlatListView::rearrangeItems() +{ + static LLUICachedControl scrollbar_size ("UIScrollbarSize", 0); + + setNoItemsCommentVisible(0==size()); + + if (mItemPairs.empty()) return; + + //calculating required height - assuming items can be of different height + //list should accommodate all its items + S32 height = 0; + + S32 invisible_children_count = 0; + pairs_iterator_t it = mItemPairs.begin(); + for (; it != mItemPairs.end(); ++it) + { + LLPanel* item = (*it)->first; + + // skip invisible child + if (!item->getVisible()) + { + ++invisible_children_count; + continue; + } + + height += item->getRect().getHeight(); + } + + // add paddings between items, excluding invisible ones + height += mItemPad * (mItemPairs.size() - invisible_children_count - 1); + + LLRect rc = mItemsPanel->getRect(); + S32 width = mItemsNoScrollWidth; + + // update width to avoid horizontal scrollbar + if (height > getRect().getHeight() - 2 * mBorderThickness) + width -= scrollbar_size; + + //changes the bottom, end of the list goes down in the scroll container + rc.setLeftTopAndSize(rc.mLeft, rc.mTop, width, height); + mItemsPanel->setRect(rc); + + //reshaping items + S32 item_new_top = height; + pairs_iterator_t it2, first_it = mItemPairs.begin(); + for (it2 = first_it; it2 != mItemPairs.end(); ++it2) + { + LLPanel* item = (*it2)->first; + + // skip invisible child + if (!item->getVisible()) + continue; + + LLRect rc = item->getRect(); + rc.setLeftTopAndSize(rc.mLeft, item_new_top, width, rc.getHeight()); + item->reshape(rc.getWidth(), rc.getHeight()); + item->setRect(rc); + + // move top for next item in list + item_new_top -= (rc.getHeight() + mItemPad); + } + + // Stretch selected item rect to ensure it won't be clipped + mSelectedItemsBorder->setRect(getLastSelectedItemRect().stretch(-1)); +} + +void LLFlatListView::onItemMouseClick(item_pair_t* item_pair, MASK mask) +{ + if (!item_pair) return; + + if (!item_pair->first) + { + LL_WARNS() << "Attempt to selet an item pair containing null panel item" << LL_ENDL; + return; + } + + setFocus(TRUE); + + bool select_item = !isSelected(item_pair); + + //*TODO find a better place for that enforcing stuff + if (mKeepOneItemSelected && numSelected() == 1 && !select_item) return; + + if ( (mask & MASK_SHIFT) && !(mask & MASK_CONTROL) + && mMultipleSelection && !mSelectedItemPairs.empty() ) + { + item_pair_t* last_selected_pair = mSelectedItemPairs.back(); + + // If item_pair is already selected - do nothing + if (last_selected_pair == item_pair) + return; + + bool grab_items = false; + bool reverse = false; + pairs_list_t pairs_to_select; + + // Pick out items from list between last selected and current clicked item_pair. + for (pairs_iterator_t + iter = mItemPairs.begin(), + iter_end = mItemPairs.end(); + iter != iter_end; ++iter) + { + item_pair_t* cur = *iter; + if (cur == last_selected_pair || cur == item_pair) + { + // We've got reverse selection if last grabed item isn't a new selection. + reverse = grab_items && (cur != item_pair); + grab_items = !grab_items; + // Skip last selected and current clicked item pairs. + continue; + } + if (!cur->first->getVisible()) + { + // Skip invisible item pairs. + continue; + } + if (grab_items) + { + pairs_to_select.push_back(cur); + } + } + + if (reverse) + { + pairs_to_select.reverse(); + } + + pairs_to_select.push_back(item_pair); + + for (pairs_iterator_t + iter = pairs_to_select.begin(), + iter_end = pairs_to_select.end(); + iter != iter_end; ++iter) + { + item_pair_t* pair_to_select = *iter; + if (isSelected(pair_to_select)) + { + // Item was already selected but there is a need to keep order from last selected pair to new selection. + // Do it here to prevent extra mCommitOnSelectionChange in selectItemPair(). + mSelectedItemPairs.remove(pair_to_select); + mSelectedItemPairs.push_back(pair_to_select); + } + else + { + selectItemPair(pair_to_select, true); + } + } + + if (!select_item) + { + // Update last selected item border. + mSelectedItemsBorder->setRect(getLastSelectedItemRect().stretch(-1)); + } + return; + } + + //no need to do additional commit on selection reset + if (!(mask & MASK_CONTROL) || !mMultipleSelection) resetSelection(true); + + //only CTRL usage allows to deselect an item, usual clicking on an item cannot deselect it + if (mask & MASK_CONTROL) + selectItemPair(item_pair, select_item); + else + selectItemPair(item_pair, true); +} + +void LLFlatListView::onItemRightMouseClick(item_pair_t* item_pair, MASK mask) +{ + if (!item_pair) + return; + + // Forbid deselecting of items on right mouse button click if mMultipleSelection flag is set on, + // because some of derived classes may have context menu and selected items must be kept. + if ( !(mask & MASK_CONTROL) && mMultipleSelection && isSelected(item_pair) ) + return; + + // else got same behavior as at onItemMouseClick + onItemMouseClick(item_pair, mask); +} + +BOOL LLFlatListView::handleKeyHere(KEY key, MASK mask) +{ + BOOL reset_selection = (mask != MASK_SHIFT); + BOOL handled = FALSE; + switch (key) + { + case KEY_RETURN: + { + if (mSelectedItemPairs.size() && mask == MASK_NONE) + { + mOnReturnSignal(this, getValue()); + handled = TRUE; + } + break; + } + case KEY_UP: + { + if ( !selectNextItemPair(true, reset_selection) && reset_selection) + { + // If case we are in accordion tab notify parent to go to the previous accordion + if (notifyParent(LLSD().with("action","select_prev")) > 0 )//message was processed + resetSelection(); + } + break; + } + case KEY_DOWN: + { + if ( !selectNextItemPair(false, reset_selection) && reset_selection) + { + // If case we are in accordion tab notify parent to go to the next accordion + if ( notifyParent(LLSD().with("action","select_next")) > 0 ) //message was processed + resetSelection(); + } + break; + } + case KEY_ESCAPE: + { + if (mask == MASK_NONE) + { + setFocus(FALSE); // pass focus to the game area (EXT-8357) + } + break; + } + default: + break; + } + + if ( ( key == KEY_UP || key == KEY_DOWN ) && mSelectedItemPairs.size() ) + { + ensureSelectedVisible(); + /* + LLRect visible_rc = getVisibleContentRect(); + LLRect selected_rc = getLastSelectedItemRect(); + + if ( !visible_rc.contains (selected_rc) ) + { + // But scroll in Items panel coordinates + scrollToShowRect(selected_rc); + } + + // In case we are in accordion tab notify parent to show selected rectangle + LLRect screen_rc; + localRectToScreen(selected_rc, &screen_rc); + notifyParent(LLSD().with("scrollToShowRect",screen_rc.getValue()));*/ + + handled = TRUE; + } + + return handled ? handled : LLScrollContainer::handleKeyHere(key, mask); +} + +LLFlatListView::item_pair_t* LLFlatListView::getItemPair(LLPanel* item) const +{ + llassert(item); + + for (pairs_const_iterator_t it= mItemPairs.begin(); it != mItemPairs.end(); ++it) + { + item_pair_t* item_pair = *it; + if (item_pair->first == item) return item_pair; + } + return nullptr; +} + +//compares two LLSD's +bool llsds_are_equal(const LLSD& llsd_1, const LLSD& llsd_2) +{ + llassert(llsd_1.isDefined()); + llassert(llsd_2.isDefined()); + + if (llsd_1.type() != llsd_2.type()) return false; + + if (!llsd_1.isMap()) + { + if (llsd_1.isUUID()) return llsd_1.asUUID() == llsd_2.asUUID(); + + //assumptions that string representaion is enough for other types + return llsd_1.asString() == llsd_2.asString(); + } + + if (llsd_1.size() != llsd_2.size()) return false; + + LLSD::map_const_iterator llsd_1_it = llsd_1.beginMap(); + LLSD::map_const_iterator llsd_2_it = llsd_2.beginMap(); + for (S32 i = 0; i < llsd_1.size(); ++i) + { + if ((*llsd_1_it).first != (*llsd_2_it).first) return false; + if (!llsds_are_equal((*llsd_1_it).second, (*llsd_2_it).second)) return false; + ++llsd_1_it; + ++llsd_2_it; + } + return true; +} + +LLFlatListView::item_pair_t* LLFlatListView::getItemPair(const LLSD& value) const +{ + llassert(value.isDefined()); + + for (pairs_const_iterator_t it= mItemPairs.begin(); it != mItemPairs.end(); ++it) + { + item_pair_t* item_pair = *it; + if (llsds_are_equal(item_pair->second, value)) return item_pair; + } + return nullptr; +} + +bool LLFlatListView::selectItemPair(item_pair_t* item_pair, bool select) +{ + llassert(item_pair); + + if (!mAllowSelection && select) return false; + + if (isSelected(item_pair) == select) return true; //already in specified selection state + if (select) + { + mSelectedItemPairs.push_back(item_pair); + } + else + { + mSelectedItemPairs.remove(item_pair); + } + + //a way of notifying panel of selection state changes + LLPanel* item = item_pair->first; + item->setValue(select ? SELECTED_EVENT : UNSELECTED_EVENT); + + if (mCommitOnSelectionChange) + { + onCommit(); + } + + // Stretch selected item rect to ensure it won't be clipped + mSelectedItemsBorder->setRect(getLastSelectedItemRect().stretch(-1)); + // By default mark it as not consecutive selection + mIsConsecutiveSelection = false; + + return true; +} + +void LLFlatListView::scrollToShowFirstSelectedItem() +{ + if (!mSelectedItemPairs.size()) return; + + LLRect selected_rc = mSelectedItemPairs.front()->first->getRect(); + + if (selected_rc.isValid()) + { + scrollToShowRect(selected_rc); + } +} + +LLRect LLFlatListView::getLastSelectedItemRect() +{ + if (!mSelectedItemPairs.size()) + { + return LLRect::null; + } + + return mSelectedItemPairs.back()->first->getRect(); +} + +void LLFlatListView::selectFirstItem () +{ + // No items - no actions! + if (0 == size()) return; + + // Select first visible item + for (pairs_iterator_t + iter = mItemPairs.begin(), + iter_end = mItemPairs.end(); + iter != iter_end; ++iter) + { + // skip invisible items + if ( (*iter)->first->getVisible() ) + { + selectItemPair(*iter, true); + ensureSelectedVisible(); + break; + } + } +} + +void LLFlatListView::selectLastItem () +{ + // No items - no actions! + if (0 == size()) return; + + // Select last visible item + for (pairs_list_t::reverse_iterator + r_iter = mItemPairs.rbegin(), + r_iter_end = mItemPairs.rend(); + r_iter != r_iter_end; ++r_iter) + { + // skip invisible items + if ( (*r_iter)->first->getVisible() ) + { + selectItemPair(*r_iter, true); + ensureSelectedVisible(); + break; + } + } +} + +void LLFlatListView::ensureSelectedVisible() +{ + LLRect selected_rc = getLastSelectedItemRect(); + + if (selected_rc.isValid()) + { + scrollToShowRect(selected_rc); + } +} + + +// virtual +bool LLFlatListView::selectNextItemPair(bool is_up_direction, bool reset_selection) +{ + // No items - no actions! + if (0 == size()) + return false; + + if (!mIsConsecutiveSelection) + { + // Leave only one item selected if list has not consecutive selection + if (mSelectedItemPairs.size() && !reset_selection) + { + item_pair_t* cur_sel_pair = mSelectedItemPairs.back(); + resetSelection(); + selectItemPair (cur_sel_pair, true); + } + } + + if (mSelectedItemPairs.size()) + { + item_pair_t* to_sel_pair = nullptr; + item_pair_t* cur_sel_pair = nullptr; + + // Take the last selected pair + cur_sel_pair = mSelectedItemPairs.back(); + // Bases on given direction choose next item to select + if (is_up_direction) + { + // Find current selected item position in mItemPairs list + pairs_list_t::reverse_iterator sel_it = std::find(mItemPairs.rbegin(), mItemPairs.rend(), cur_sel_pair); + + for (;++sel_it != mItemPairs.rend();) + { + // skip invisible items + if ( (*sel_it)->first->getVisible() ) + { + to_sel_pair = *sel_it; + break; + } + } + } + else + { + // Find current selected item position in mItemPairs list + pairs_list_t::iterator sel_it = std::find(mItemPairs.begin(), mItemPairs.end(), cur_sel_pair); + + for (;++sel_it != mItemPairs.end();) + { + // skip invisible items + if ( (*sel_it)->first->getVisible() ) + { + to_sel_pair = *sel_it; + break; + } + } + } + + if (to_sel_pair) + { + bool select = true; + if (reset_selection) + { + // Reset current selection if we were asked about it + resetSelection(); + } + else + { + // If item already selected and no reset request than we should deselect last selected item. + select = (mSelectedItemPairs.end() == std::find(mSelectedItemPairs.begin(), mSelectedItemPairs.end(), to_sel_pair)); + } + // Select/Deselect next item + selectItemPair(select ? to_sel_pair : cur_sel_pair, select); + // Mark it as consecutive selection + mIsConsecutiveSelection = true; + return true; + } + } + else + { + // If there weren't selected items then choose the first one bases on given direction + // Force selection to first item + if (is_up_direction) + selectLastItem(); + else + selectFirstItem(); + // Mark it as consecutive selection + mIsConsecutiveSelection = true; + return true; + } + + return false; +} + +BOOL LLFlatListView::canSelectAll() const +{ + return 0 != size() && mAllowSelection && mMultipleSelection; +} + +void LLFlatListView::selectAll() +{ + if (!mAllowSelection || !mMultipleSelection) + return; + + mSelectedItemPairs.clear(); + + for (pairs_const_iterator_t it= mItemPairs.begin(); it != mItemPairs.end(); ++it) + { + item_pair_t* item_pair = *it; + mSelectedItemPairs.push_back(item_pair); + //a way of notifying panel of selection state changes + LLPanel* item = item_pair->first; + item->setValue(SELECTED_EVENT); + } + + if (mCommitOnSelectionChange) + { + onCommit(); + } + + // Stretch selected item rect to ensure it won't be clipped + mSelectedItemsBorder->setRect(getLastSelectedItemRect().stretch(-1)); +} + +bool LLFlatListView::isSelected(item_pair_t* item_pair) const +{ + llassert(item_pair); + + pairs_const_iterator_t it_end = mSelectedItemPairs.end(); + return std::find(mSelectedItemPairs.begin(), it_end, item_pair) != it_end; +} + +bool LLFlatListView::removeItemPair(item_pair_t* item_pair, bool rearrange) +{ + llassert(item_pair); + + bool deleted = false; + bool selection_changed = false; + for (pairs_iterator_t it = mItemPairs.begin(); it != mItemPairs.end(); ++it) + { + item_pair_t* _item_pair = *it; + if (_item_pair == item_pair) + { + mItemPairs.erase(it); + deleted = true; + break; + } + } + + if (!deleted) return false; + + for (pairs_iterator_t it = mSelectedItemPairs.begin(); it != mSelectedItemPairs.end(); ++it) + { + item_pair_t* selected_item_pair = *it; + if (selected_item_pair == item_pair) + { + it = mSelectedItemPairs.erase(it); + selection_changed = true; + break; + } + } + + mItemsPanel->removeChild(item_pair->first); + item_pair->first->die(); + delete item_pair; + + if (rearrange) + { + rearrangeItems(); + notifyParentItemsRectChanged(); + } + + if (selection_changed && mCommitOnSelectionChange) + { + onCommit(); + } + + return true; +} + +void LLFlatListView::notifyParentItemsRectChanged() +{ + S32 comment_height = 0; + + // take into account comment text height if exists + if (mNoItemsCommentTextbox && mNoItemsCommentTextbox->getVisible()) + { + // top text padding inside the textbox is included into the height + comment_height = mNoItemsCommentTextbox->getTextPixelHeight(); + + // take into account a distance from parent's top border to textbox's top + comment_height += getRect().getHeight() - mNoItemsCommentTextbox->getRect().mTop; + } + + LLRect req_rect = getItemsRect(); + + // get maximum of items total height and comment text height + req_rect.setOriginAndSize(req_rect.mLeft, req_rect.mBottom, req_rect.getWidth(), llmax(req_rect.getHeight(), comment_height)); + + // take into account border size. + req_rect.stretch(getBorderWidth()); + + if (req_rect == mPrevNotifyParentRect) + return; + + mPrevNotifyParentRect = req_rect; + + LLSD params; + params["action"] = "size_changes"; + params["width"] = req_rect.getWidth(); + params["height"] = req_rect.getHeight(); + + if (getParent()) // dummy widgets don't have a parent + getParent()->notifyParent(params); +} + +void LLFlatListView::setNoItemsCommentVisible(bool visible) const +{ + if (mNoItemsCommentTextbox) + { + mSelectedItemsBorder->setVisible(!visible); + mNoItemsCommentTextbox->setVisible(visible); + } +} + +void LLFlatListView::getItems(std::vector& items) const +{ + if (mItemPairs.empty()) return; + + items.clear(); + for (pairs_const_iterator_t it = mItemPairs.begin(); it != mItemPairs.end(); ++it) + { + items.push_back((*it)->first); + } +} + +void LLFlatListView::getValues(std::vector& values) const +{ + if (mItemPairs.empty()) return; + + values.clear(); + for (pairs_const_iterator_t it = mItemPairs.begin(); it != mItemPairs.end(); ++it) + { + values.push_back((*it)->second); + } +} + +// virtual +void LLFlatListView::onFocusReceived() +{ + if (size()) + { + mSelectedItemsBorder->setVisible(TRUE); + } + gEditMenuHandler = this; +} +// virtual +void LLFlatListView::onFocusLost() +{ + mSelectedItemsBorder->setVisible(FALSE); + // Route menu back to the default + if (gEditMenuHandler == this) + { + gEditMenuHandler = nullptr; + } +} + +//virtual +S32 LLFlatListView::notify(const LLSD& info) +{ + if (info.has("action")) + { + std::string str_action = info["action"]; + if (str_action == "select_first") + { + setFocus(true); + selectFirstItem(); + return 1; + } + else if (str_action == "select_last") + { + setFocus(true); + selectLastItem(); + return 1; + } + } + else if (info.has("rearrange")) + { + rearrangeItems(); + notifyParentItemsRectChanged(); + return 1; + } + return 0; +} + +void LLFlatListView::detachItems(std::vector& detached_items) +{ + LLSD action; + action.with("detach", LLSD()); + // Clear detached_items list + detached_items.clear(); + // Go through items and detach valid items, remove them from items panel + // and add to detached_items. + for (pairs_iterator_t + iter = mItemPairs.begin(), + iter_end = mItemPairs.end(); + iter != iter_end; ++iter) + { + LLPanel* pItem = (*iter)->first; + if (1 == pItem->notify(action)) + { + selectItemPair((*iter), false); + mItemsPanel->removeChild(pItem); + detached_items.push_back(pItem); + } + } + if (!detached_items.empty()) + { + // Some items were detached, clean ourself from unusable memory + if (detached_items.size() == mItemPairs.size()) + { + // This way will be faster if all items were disconnected + for (pairs_iterator_t + iter = mItemPairs.begin(), + iter_end = mItemPairs.end(); + iter != iter_end; ++iter) + { + (*iter)->first = nullptr; + delete *iter; + } + mItemPairs.clear(); + // Also set items panel height to zero. + // Reshape it to allow reshaping of non-item children. + LLRect rc = mItemsPanel->getRect(); + rc.mBottom = rc.mTop; + mItemsPanel->reshape(rc.getWidth(), rc.getHeight()); + mItemsPanel->setRect(rc); + setNoItemsCommentVisible(true); + } + else + { + for (std::vector::const_iterator + detached_iter = detached_items.begin(), + detached_iter_end = detached_items.end(); + detached_iter != detached_iter_end; ++detached_iter) + { + LLPanel* pDetachedItem = *detached_iter; + for (pairs_iterator_t + iter = mItemPairs.begin(), + iter_end = mItemPairs.end(); + iter != iter_end; ++iter) + { + item_pair_t* item_pair = *iter; + if (item_pair->first == pDetachedItem) + { + mItemPairs.erase(iter); + item_pair->first = nullptr; + delete item_pair; + break; + } + } + } + rearrangeItems(); + } + notifyParentItemsRectChanged(); + } +} + + +/************************************************************************/ +/* LLFlatListViewEx implementation */ +/************************************************************************/ +/* Singu Note: Let's not use this for now... +LLFlatListViewEx::Params::Params() +: no_items_msg("no_items_msg") +, no_filtered_items_msg("no_filtered_items_msg") +{ + +} + +LLFlatListViewEx::LLFlatListViewEx(const Params& p) +: LLFlatListView(p) +, mNoFilteredItemsMsg(p.no_filtered_items_msg) +, mNoItemsMsg(p.no_items_msg) +, mForceShowingUnmatchedItems(false) +, mHasMatchedItems(false) +{ + +} + +void LLFlatListViewEx::updateNoItemsMessage(const std::string& filter_string) +{ + bool items_filtered = !filter_string.empty(); + if (items_filtered) + { + // items were filtered + LLStringUtil::format_map_t args; + args["[SEARCH_TERM]"] = LLURI::escape(filter_string); + std::string text = mNoFilteredItemsMsg; + LLStringUtil::format(text, args); + setNoItemsCommentText(text); + } + else + { + // list does not contain any items at all + setNoItemsCommentText(mNoItemsMsg); + } + +} + +bool LLFlatListViewEx::getForceShowingUnmatchedItems() +{ + return mForceShowingUnmatchedItems; +} + +void LLFlatListViewEx::setForceShowingUnmatchedItems(bool show) +{ + mForceShowingUnmatchedItems = show; +} + +void LLFlatListViewEx::setFilterSubString(const std::string& filter_str) +{ + if (0 != LLStringUtil::compareInsensitive(filter_str, mFilterSubString)) + { + mFilterSubString = filter_str; + updateNoItemsMessage(mFilterSubString); + filterItems(); + } +} + +void LLFlatListViewEx::updateItemVisibility(LLPanel* item, const LLSD &action) +{ + if (!item) return; + + // 0 signifies that filter is matched, + // i.e. we don't hide items that don't support 'match_filter' action, separators etc. + if (0 == item->notify(action)) + { + mHasMatchedItems = true; + item->setVisible(true); + } + else + { + // TODO: implement (re)storing of current selection. + if (!mForceShowingUnmatchedItems) + { + selectItem(item, false); + } + item->setVisible(mForceShowingUnmatchedItems); + } +} + +void LLFlatListViewEx::filterItems() +{ + typedef std::vector item_panel_list_t; + + std::string cur_filter = mFilterSubString; + LLStringUtil::toUpper(cur_filter); + + LLSD action; + action.with("match_filter", cur_filter); + + item_panel_list_t items; + getItems(items); + + mHasMatchedItems = false; + for (item_panel_list_t::iterator + iter = items.begin(), + iter_end = items.end(); + iter != iter_end; ++iter) + { + LLPanel* pItem = (*iter); + updateItemVisibility(pItem, action); + } + + sort(); + notifyParentItemsRectChanged(); +} + +bool LLFlatListViewEx::hasMatchedItems() +{ + return mHasMatchedItems; +} +*/ + +// Old-style fromXML stuffs +// static +LLView* LLFlatListView::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) +{ + // Stuff from scroll container + std::string name("flat_list_view"); + node->getAttributeString("name", name); + + LLRect rect; + createRect(node, rect, parent, LLRect()); + + BOOL opaque = FALSE; + node->getAttributeBOOL("opaque", opaque); + + LLColor4 color(0,0,0,0); + LLUICtrlFactory::getAttributeColor(node, "color", color); + + // Stuff from flat list + bool allow_select = false; + node->getAttribute_bool("allow_select", allow_select); + bool multi_select = false; + node->getAttribute_bool("multi_select", multi_select); + bool keep_one_selected = false; + node->getAttribute_bool("keep_one_selected", keep_one_selected); + bool keep_selection_visible_on_reshape = false; + node->getAttribute_bool("keep_selection_visible_on_reshape", keep_selection_visible_on_reshape); + U32 item_pad; + node->getAttributeU32("item_pad", item_pad); + std::string no_items_text; + node->getAttributeString("no_items_text", no_items_text); + + return new LLFlatListView(name, rect, opaque, color, item_pad, allow_select, multi_select, keep_one_selected, keep_selection_visible_on_reshape, no_items_text); +} +// + +//EOF diff --git a/indra/llui/llflatlistview.h b/indra/llui/llflatlistview.h new file mode 100644 index 000000000..ade20412a --- /dev/null +++ b/indra/llui/llflatlistview.h @@ -0,0 +1,540 @@ +/** + * @file llflatlistview.h + * @brief LLFlatListView base class and extension to support messages for several cases of an empty list. + * + * $LicenseInfo:firstyear=2009&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLFLATLISTVIEW_H +#define LL_LLFLATLISTVIEW_H + +#include "llpanel.h" +#include "llscrollcontainer.h" +#include "lltextbox.h" + + +/** + * LLFlatListView represents a flat list ui control that operates on items in a form of LLPanel's. + * LLSD can be associated with each added item, it can keep data from an item in digested form. + * Associated LLSD's can be of any type (singular, a map etc.). + * Items (LLPanel's subclasses) can be of different height. + * The list is LLPanel created in itself and grows in height while new items are added. + * + * The control can manage selection of its items when the flag "allow_select" is set. Also ability to select + * multiple items (by using CTRL) is enabled through setting the flag "multi_select" - if selection is not allowed that flag + * is ignored. The option "keep_one_selected" forces at least one item to be selected at any time (only for mouse events on items) + * since any item of the list was selected. + * + * Examples of using this control are presented in Picks panel (My Profile and Profile View), where this control is used to + * manage the list of pick items. + * + * ASSUMPTIONS AND STUFF + * - NULL pointers and undefined LLSD's are not accepted by any method of this class unless specified otherwise + * - Order of returned selected items are not guaranteed + * - The control assumes that all items being added are unique. + */ +class LLFlatListView : public LLScrollContainer, public LLEditMenuHandler +{ + LOG_CLASS(LLFlatListView); +public: + + /** + * Abstract comparator for comparing flat list items in a form of LLPanel + */ + class ItemComparator + { + public: + ItemComparator() {}; + virtual ~ItemComparator() {}; + + /** Returns true if item1 < item2, false otherwise */ + virtual bool compare(const LLPanel* item1, const LLPanel* item2) const = 0; + }; + + /** + * Represents reverse comparator which acts as a decorator for a comparator that need to be reversed + */ + class ItemReverseComparator : public ItemComparator + { + public: + ItemReverseComparator(const ItemComparator& comparator) : mComparator(comparator) {}; + virtual ~ItemReverseComparator() {}; + + bool compare(const LLPanel* item1, const LLPanel* item2) const override + { + return mComparator.compare(item2, item1); + } + + private: + const ItemComparator& mComparator; + }; + + + struct Params : public LLInitParam::Block + { + /** turning on/off selection support */ + Optional allow_select; + + /** turning on/off multiple selection (works while clicking and holding CTRL)*/ + Optional multi_select; + + /** don't allow to deselect all selected items (for mouse events on items only) */ + Optional keep_one_selected; + + /** try to keep selection visible after reshape */ + Optional keep_selection_visible_on_reshape; + + /** padding between items */ + Optional item_pad; + + /** textbox with info message when list is empty*/ + Optional no_items_text; + + Params(); + }; + + // disable traversal when finding widget to hand focus off to + /*virtual*/ BOOL canFocusChildren() const override { return FALSE; } + + /** + * Connects callback to signal called when Return key is pressed. + */ + boost::signals2::connection setReturnCallback( const commit_signal_t::slot_type& cb ) { return mOnReturnSignal.connect(cb); } + + /** Overridden LLPanel's reshape, height is ignored, the list sets its height to accommodate all items */ + void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE) override; + + /** Returns full rect of child panel */ + const LLRect& getItemsRect() const; + + LLRect getRequiredRect() override { return getItemsRect(); } + + /** Returns distance between items */ + const S32 getItemsPad() const { return mItemPad; } + + /** + * Adds and item and LLSD value associated with it to the list at specified position + * @return true if the item was added, false otherwise + */ + virtual bool addItem(LLPanel * item, const LLSD& value = LLUUID::null, EAddPosition pos = ADD_BOTTOM, bool rearrange = true); + + /** + * Insert item_to_add along with associated value to the list right after the after_item. + * @return true if the item was successfully added, false otherwise + */ + virtual bool insertItemAfter(LLPanel* after_item, LLPanel* item_to_add, const LLSD& value = LLUUID::null); + + /** + * Remove specified item + * @return true if the item was removed, false otherwise + */ + virtual bool removeItem(LLPanel* item, bool rearrange = true); + + /** + * Remove an item specified by value + * @return true if the item was removed, false otherwise + */ + virtual bool removeItemByValue(const LLSD& value, bool rearrange = true); + + /** + * Remove an item specified by uuid + * @return true if the item was removed, false otherwise + */ + virtual bool removeItemByUUID(const LLUUID& uuid, bool rearrange = true); + + /** + * Get an item by value + * @return the item as LLPanel if associated with value, NULL otherwise + */ + virtual LLPanel* getItemByValue(const LLSD& value) const; + + /** + * Check for item by value in list + * @return bool whether item exists by value or not + */ + virtual bool valueExists(const LLSD& value) const; + + template + T* getTypedItemByValue(const LLSD& value) const + { + return dynamic_cast(getItemByValue(value)); + } + + /** + * Select or deselect specified item based on select + * @return true if succeed, false otherwise + */ + virtual bool selectItem(LLPanel* item, bool select = true); + + /** + * Select or deselect an item by associated value based on select + * @return true if succeed, false otherwise + */ + virtual bool selectItemByValue(const LLSD& value, bool select = true); + + /** + * Select or deselect an item by associated uuid based on select + * @return true if succeed, false otherwise + */ + virtual bool selectItemByUUID(const LLUUID& uuid, bool select = true); + + /** + * Get all panels stored in the list. + */ + virtual void getItems(std::vector& items) const; + + /** + * Get all items values. + */ + virtual void getValues(std::vector& values) const; + + /** + * Get LLSD associated with the first selected item + */ + virtual LLSD getSelectedValue() const; + + /** + * Get LLSD's associated with selected items. + * @param selected_values std::vector being populated with LLSD associated with selected items + */ + virtual void getSelectedValues(std::vector& selected_values) const; + + + /** + * Get LLUUID associated with selected item + * @return LLUUID if such was associated with selected item + */ + virtual LLUUID getSelectedUUID() const; + + /** + * Get LLUUIDs associated with selected items + * @param selected_uuids An std::vector being populated with LLUUIDs associated with selected items + */ + virtual void getSelectedUUIDs(uuid_vec_t& selected_uuids) const; + + /** Get the top selected item */ + virtual LLPanel* getSelectedItem() const; + + /** + * Get selected items + * @param selected_items An std::vector being populated with pointers to selected items + */ + virtual void getSelectedItems(std::vector& selected_items) const; + + + /** + * Resets selection of items. + * + * It calls onCommit callback if setCommitOnSelectionChange(bool b) was called with "true" + * argument for current Flat List. + * @param no_commit_on_deselection - if true onCommit callback will not be called + */ + virtual void resetSelection(bool no_commit_on_deselection = false); + + /** + * Sets comment text which will be shown in the list is it is empty. + * + * Textbox to hold passed text is created while this method is called at the first time. + * + * @param comment_text - string to be shown as a comment. + */ + void setNoItemsCommentText( const std::string& comment_text); + + /** Turn on/off multiple selection support */ + void setAllowMultipleSelection(bool allow) { mMultipleSelection = allow; } + + /** Turn on/off selection support */ + void setAllowSelection(bool can_select) { mAllowSelection = can_select; } + + /** Sets flag whether onCommit should be fired if selection was changed */ + // FIXME: this should really be a separate signal, since "Commit" implies explicit user action, and selection changes can happen more indirectly. + void setCommitOnSelectionChange(bool b) { mCommitOnSelectionChange = b; } + + /** Get number of selected items in the list */ + U32 numSelected() const {return mSelectedItemPairs.size(); } + + /** Get number of (visible) items in the list */ + U32 size(const bool only_visible_items = true) const; + + /** Removes all items from the list */ + void clear() override; + + /** + * Removes all items that can be detached from the list but doesn't destroy + * them, caller responsible to manage items after they are detached. + * Detachable item should accept "detach" action via notify() method, + * where it disconnect all callbacks, does other valuable routines and + * return 1. + */ + void detachItems(std::vector& detached_items); + + /** + * Set comparator to use for future sorts. + * + * This class does NOT manage lifetime of the comparator + * but assumes that the comparator is always alive. + */ + void setComparator(const ItemComparator* comp) { mItemComparator = comp; } + void sort(); + + bool updateValue(const LLSD& old_value, const LLSD& new_value); + + void scrollToShowFirstSelectedItem(); + + void selectFirstItem (); + void selectLastItem (); + + S32 notify(const LLSD& info) override; + + static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); // Old-style + + virtual ~LLFlatListView(); +protected: + + /** Pairs LLpanel representing a single item LLPanel and LLSD associated with it */ + typedef std::pair item_pair_t; + + typedef std::list pairs_list_t; + typedef pairs_list_t::iterator pairs_iterator_t; + typedef pairs_list_t::const_iterator pairs_const_iterator_t; + + /** An adapter for a ItemComparator */ + struct ComparatorAdaptor + { + ComparatorAdaptor(const ItemComparator& comparator) : mComparator(comparator) {}; + + bool operator()(const item_pair_t* item_pair1, const item_pair_t* item_pair2) const + { + return mComparator.compare(item_pair1->first, item_pair2->first); + } + + const ItemComparator& mComparator; + }; + + + friend class LLUICtrlFactory; + LLFlatListView(const std::string& name, const LLRect& rect, bool opaque, const LLColor4& color, const S32& item_pad, bool allow_select, bool multi_select, bool keep_one_selected, bool keep_selection_visible_on_reshape, const std::string& no_items_text); + + /** Manage selection on mouse events */ + void onItemMouseClick(item_pair_t* item_pair, MASK mask); + + void onItemRightMouseClick(item_pair_t* item_pair, MASK mask); + + /** + * Updates position of items. + * It does not take into account invisible items. + */ + virtual void rearrangeItems(); + + virtual item_pair_t* getItemPair(LLPanel* item) const; + + virtual item_pair_t* getItemPair(const LLSD& value) const; + + virtual bool selectItemPair(item_pair_t* item_pair, bool select); + + virtual bool selectNextItemPair(bool is_up_direction, bool reset_selection); + + BOOL canSelectAll() const override; + void selectAll() override; + + virtual bool isSelected(item_pair_t* item_pair) const; + + virtual bool removeItemPair(item_pair_t* item_pair, bool rearrange); + + bool addItemPairs(pairs_list_t panel_list, bool rearrange = true); + + /** + * Notify parent about changed size of internal controls with "size_changes" action + * + * Size includes Items Rect width and either Items Rect height or comment text height. + * Comment text height is included if comment text is set and visible. + * List border size is also included into notified size. + */ + void notifyParentItemsRectChanged(); + + BOOL handleKeyHere(KEY key, MASK mask) override; + + BOOL postBuild() override; + + void onFocusReceived() override; + + void onFocusLost() override; + + void draw() override; + + LLRect getLastSelectedItemRect(); + + void ensureSelectedVisible(); + +private: + + void setItemsNoScrollWidth(S32 new_width) {mItemsNoScrollWidth = new_width - 2 * mBorderThickness;} + + void setNoItemsCommentVisible(bool visible) const; + +protected: + + /** Comparator to use when sorting the list. */ + const ItemComparator* mItemComparator; + + +private: + + LLPanel* mItemsPanel; + + S32 mItemsNoScrollWidth; + + S32 mBorderThickness; + + /** Items padding */ + S32 mItemPad; + + /** Selection support flag */ + bool mAllowSelection; + + /** Multiselection support flag, ignored if selection is not supported */ + bool mMultipleSelection; + + /** + * Flag specified whether onCommit be called if selection is changed in the list. + * + * Can be ignored in the resetSelection() method. + * @see resetSelection() + */ + bool mCommitOnSelectionChange; + + bool mKeepOneItemSelected; + + bool mIsConsecutiveSelection; + + bool mKeepSelectionVisibleOnReshape; + + /** All pairs of the list */ + pairs_list_t mItemPairs; + + /** Selected pairs for faster access */ + pairs_list_t mSelectedItemPairs; + + /** + * Rectangle contained previous size of items parent notified last time. + * Is used to reduce amount of parentNotify() calls if size was not changed. + */ + LLRect mPrevNotifyParentRect; + + LLTextBox* mNoItemsCommentTextbox; + + LLViewBorder* mSelectedItemsBorder; + + commit_signal_t mOnReturnSignal; +}; + +/** + * Extends LLFlatListView functionality to show different messages when there are no items in the + * list depend on whether they are filtered or not. + * + * Class provides one message per case of empty list. + * It also provides protected updateNoItemsMessage() method to be called each time when derived list + * is changed to update base mNoItemsCommentTextbox value. + * + * It is implemented to avoid duplication of this functionality in concrete implementations of the + * lists. It is intended to be used as a base class for lists which should support two different + * messages for empty state. Can be improved to support more than two messages via state-to-message map. + */ +class LLFlatListViewEx : public LLFlatListView +{ +public: + LOG_CLASS(LLFlatListViewEx); + + struct Params : public LLInitParam::Block + { + /** + * Contains a message for empty list when it does not contain any items at all. + */ + Optional no_items_msg; + + /** + * Contains a message for empty list when its items are removed by filtering. + */ + Optional no_filtered_items_msg; + Params(); + }; + + // *WORKAROUND: two methods to overload appropriate Params due to localization issue: + // no_items_msg & no_filtered_items_msg attributes are not defined as translatable in VLT. See EXT-5931 + void setNoItemsMsg(const std::string& msg) { mNoItemsMsg = msg; } + void setNoFilteredItemsMsg(const std::string& msg) { mNoFilteredItemsMsg = msg; } + + bool getForceShowingUnmatchedItems(); + + void setForceShowingUnmatchedItems(bool show); + + /** + * Sets up new filter string and filters the list. + */ + void setFilterSubString(const std::string& filter_str); + std::string getFilterSubString() const { return mFilterSubString; } + + /** + * Filters the list, rearranges and notifies parent about shape changes. + * Derived classes may want to overload rearrangeItems() to exclude repeated separators after filtration. + */ + void filterItems(); + + /** + * Returns true if last call of filterItems() found at least one matching item + */ + bool hasMatchedItems(); + +protected: + LLFlatListViewEx(const Params& p); + + /** + * Applies a message for empty list depend on passed argument. + * + * @param filter_string - if is not empty, message for filtered items will be set, otherwise for + * completely empty list. Value of filter string will be passed as search_term in SLURL. + */ + void updateNoItemsMessage(const std::string& filter_string); + + /** + * Applies visibility acording to action and LLFlatListView settings. + * + * @param item - item we are changing + * @param item - action - parameters to determin visibility from + */ + void updateItemVisibility(LLPanel* item, const LLSD &action); + +private: + std::string mNoFilteredItemsMsg; + std::string mNoItemsMsg; + std::string mFilterSubString; + /** + * Show list items that don't match current filter + */ + bool mForceShowingUnmatchedItems; + /** + * True if last call of filterItems() found at least one matching item + */ + bool mHasMatchedItems; +}; + +#endif diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index 1f851e2dd..dd2954c11 100644 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -181,7 +181,6 @@ LLLineEditor::LLLineEditor(const std::string& name, const LLRect& rect, // make the popup menu available LLMenuGL* menu = LLUICtrlFactory::getInstance()->buildMenu("menu_texteditor.xml", LLMenuGL::sMenuContainer); - menu->addSeparator(); //menu->setBackgroundColor(gColors.getColor("MenuPopupBgColor")); menu->setCanTearOff(FALSE); menu->setVisible(FALSE); @@ -1120,7 +1119,7 @@ BOOL LLLineEditor::canCopy() const // copy selection to clipboard -void LLLineEditor::copy() +void LLLineEditor::copy() const { if( canCopy() ) { @@ -3006,54 +3005,47 @@ void LLLineEditor::showContextMenu(S32 x, S32 y) { gEditMenuHandler = this; - - LLMenuGL* menu = (LLMenuGL*)mContextMenuHandle.get(); - if (menu) + if(menu->isOpen()) { - if(menu->isOpen()) - { - menu->setVisible(FALSE); - } - - // spell_check="true" in xui - if (!mReadOnly && mSpellCheckable) - { - // search for word matches - S32 wordStart = 0; - S32 wordLen = 0; - S32 pos = calculateCursorFromMouse(x); - if (getWordBoundriesAt(pos, &wordStart, &wordLen)) - { - const auto selectedWord = wstring_to_utf8str(getWText().substr(wordStart, wordLen)); - - if (!glggHunSpell->isSpelledRight(selectedWord)) - { - //misspelled word here, and you have just right clicked on it! - - for (const auto& word : glggHunSpell->getSuggestionList(selectedWord)) - { - menu->addChild(new LLMenuItemCallGL(word, spell_correct, nullptr, this)); - } - menu->addChild(new LLMenuItemCallGL("Add Word", spell_add, nullptr, this)); - } - } - - const std::string showstr("Show Misspellings"), hidestr("Hide Misspellings"); - bool show = !glggHunSpell->getSpellCheckHighlight(); - auto word = show ? showstr : hidestr; - if (!menu->hasChild(word)) - { - menu->addChild(new LLMenuItemCallGL(word, spell_show, nullptr, show ? &show : nullptr)); - if (auto child = menu->getChild(show ? hidestr : showstr, false, false)) - menu->removeChild(child); - } - } - - mLastContextMenuX = x; - menu->buildDrawLabels(); - menu->updateParent(LLMenuGL::sMenuContainer); - LLMenuGL::showPopup(this, menu, x, y); + menu->setVisible(FALSE); } + + // spell_check="true" in xui + if (!mReadOnly && mSpellCheckable) + { + constexpr auto spell_sep = "Spell Check Sep"; + // Remove everything after the separator if we added it, because menus don't autodie yet. + menu->erase(menu->find(menu->findChild(spell_sep)), menu->end()); + menu->addSeparator(spell_sep); + + // search for word matches + S32 wordStart = 0; + S32 wordLen = 0; + S32 pos = calculateCursorFromMouse(x); + if (getWordBoundriesAt(pos, &wordStart, &wordLen)) + { + const auto selectedWord = wstring_to_utf8str(getWText().substr(wordStart, wordLen)); + + if (!glggHunSpell->isSpelledRight(selectedWord)) + { + //misspelled word here, and you have just right clicked on it! + + for (const auto& word : glggHunSpell->getSuggestionList(selectedWord)) + { + menu->addChild(new LLMenuItemCallGL(word, spell_correct, nullptr, this)); + } + menu->addChild(new LLMenuItemCallGL("Add Word", spell_add, nullptr, this)); + } + } + + bool show = !glggHunSpell->getSpellCheckHighlight(); + menu->addChild(new LLMenuItemCallGL(show ? "Show Misspellings" : "Hide Misspellings", spell_show, nullptr, show ? menu : nullptr)); + } + + mLastContextMenuX = x; + menu->buildDrawLabels(); + menu->updateParent(LLMenuGL::sMenuContainer); + LLMenuGL::showPopup(this, menu, x, y); } } diff --git a/indra/llui/lllineeditor.h b/indra/llui/lllineeditor.h index 440407cd8..ec002a452 100644 --- a/indra/llui/lllineeditor.h +++ b/indra/llui/lllineeditor.h @@ -107,7 +107,7 @@ public: virtual void cut(); virtual BOOL canCut() const; - virtual void copy(); + void copy() const override final; virtual BOOL canCopy() const; virtual void paste(); diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp index 7b9bbe372..d7175b9aa 100644 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -692,16 +692,17 @@ BOOL LLMenuItemSeparatorGL::handleHover(S32 x, S32 y, MASK mask) // This class represents a vertical separator. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLMenuItemVerticalSeparatorGL +class LLMenuItemVerticalSeparatorGL final : public LLMenuItemSeparatorGL { public: - LLMenuItemVerticalSeparatorGL( void ); + LLMenuItemVerticalSeparatorGL(const std::string& name = LLStringUtil::null); BOOL handleMouseDown(S32 x, S32 y, MASK mask) override { return FALSE; } }; -LLMenuItemVerticalSeparatorGL::LLMenuItemVerticalSeparatorGL( void ) +LLMenuItemVerticalSeparatorGL::LLMenuItemVerticalSeparatorGL(const std::string& name) +: LLMenuItemSeparatorGL(name) { setLabel( VERTICAL_SEPARATOR_LABEL ); } @@ -826,15 +827,15 @@ U32 LLMenuItemTearOffGL::getNominalHeight( void ) const // This class represents a blank, non-functioning item. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLMenuItemBlankGL : public LLMenuItemGL +class LLMenuItemBlankGL final : public LLMenuItemGL { public: - LLMenuItemBlankGL( void ) : LLMenuItemGL( LLStringUtil::null, LLStringUtil::null ) + LLMenuItemBlankGL(const std::string& name = LLStringUtil::null) : LLMenuItemGL(name, LLStringUtil::null) { setEnabled(FALSE); } - virtual void onCommit( void ) {} - virtual void draw( void ) {} + void onCommit() override {} + void draw() override {} }; @@ -3166,12 +3167,7 @@ void LLMenuGL::erase( S32 begin, S32 end, bool arrange/* = true*/) item_list_t::iterator end_position = mItems.begin(); std::advance(end_position, end); - for (item_list_t::iterator position_iter = start_position; position_iter != end_position; position_iter++) - { - LLUICtrl::removeChild(*position_iter); - } - - mItems.erase(start_position, end_position); + erase(start_position, end_position); if (arrange) { @@ -3193,7 +3189,7 @@ void LLMenuGL::insert(S32 position, LLView* ctrl, bool arrange /*= true*/) std::advance(position_iter, position); insert(position_iter, item, arrange); } -void LLMenuGL::insert(item_list_t::iterator position_iter, LLMenuItemGL* item, bool arrange /*= true*/) +void LLMenuGL::insert(item_list_t::const_iterator position_iter, LLMenuItemGL* item, bool arrange /*= true*/) { mItems.insert(position_iter, item); LLUICtrl::addChild(item); @@ -3243,9 +3239,9 @@ BOOL LLMenuGL::append( LLMenuItemGL* item ) } // add a separator to this menu -BOOL LLMenuGL::addSeparator() +BOOL LLMenuGL::addSeparator(const std::string& name) { - LLMenuItemGL* separator = new LLMenuItemSeparatorGL(); + LLMenuItemGL* separator = new LLMenuItemSeparatorGL(name); return addChild(separator); } @@ -3332,11 +3328,6 @@ void LLMenuGL::setTornOff(BOOL torn_off) mTornOff = torn_off; } -U32 LLMenuGL::getItemCount() -{ - return mItems.size(); -} - LLMenuItemGL* LLMenuGL::getItem(S32 number) { if (number >= 0 && number < (S32)mItems.size()) @@ -4197,10 +4188,10 @@ S32 LLMenuBarGL::getRightmostMenuEdge() } // add a vertical separator to this menu -BOOL LLMenuBarGL::addSeparator() +BOOL LLMenuBarGL::addSeparator(const std::string& name) { - LLMenuItemGL* separator = new LLMenuItemVerticalSeparatorGL(); - return append( separator ); + LLMenuItemGL* separator = new LLMenuItemVerticalSeparatorGL(name); + return append(separator); } // add a menu - this will create a drop down menu. @@ -5361,9 +5352,9 @@ BOOL LLPieMenu::append(LLMenuItemGL *item) } // virtual -BOOL LLPieMenu::addSeparator() +BOOL LLPieMenu::addSeparator(const std::string& name) { - return append( new LLMenuItemBlankGL() ); + return append(new LLMenuItemBlankGL(name)); } // virtual diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h index 45e21e18e..d63b294d8 100644 --- a/indra/llui/llmenugl.h +++ b/indra/llui/llmenugl.h @@ -490,7 +490,7 @@ public: void setCanTearOff(BOOL tear_off); // add a separator to this menu - virtual BOOL addSeparator(); + virtual BOOL addSeparator(const std::string& name = LLStringUtil::null); // for branching menu items, bring sub menus up to root level of menu hierarchy virtual void updateParent( LLView* parentp ); @@ -527,16 +527,31 @@ public: // erase group of items from menu void erase(S32 begin, S32 end, bool arrange = true); + typedef std::list item_list_t; + inline item_list_t::iterator erase(item_list_t::const_iterator first, item_list_t::const_iterator last) + { + for (auto it = first; it != last; ++it) + LLUICtrl::removeChild(*it); + return mItems.erase(first, last); + } // add new item at position void insert(S32 begin, LLView* ctrl, bool arrange = true); - void insert(std::list::iterator position_iter, LLMenuItemGL* item, bool arrange = true); + void insert(item_list_t::const_iterator position_iter, LLMenuItemGL* item, bool arrange = true); // find an item's position - std::list::iterator find(LLMenuItemGL* item) { return std::find(mItems.begin(), mItems.end(), item); } + item_list_t::const_iterator find(LLMenuItemGL* item) const { return std::find(mItems.begin(), mItems.end(), item); } + + // end of items, for use with other members that return an iterator + item_list_t::const_iterator end() const { return mItems.cend(); } + + // get list of items + const item_list_t& getItems() const { return mItems; } + + // number of menu items + item_list_t::size_type getItemCount() const { return mItems.size(); } void setItemLastSelected(LLMenuItemGL* item); // must be in menu - U32 getItemCount(); // number of menu items LLMenuItemGL* getItem(S32 number); // 0 = first item LLMenuItemGL* getHighlightedItem(); @@ -591,9 +606,8 @@ public: virtual BOOL appendMenu( LLMenuGL* menu ); protected: - // TODO: create accessor methods for these? - typedef std::list< LLMenuItemGL* > item_list_t; item_list_t mItems; + // TODO: create accessor methods for these? LLMenuItemGL*mFirstVisibleItem; LLMenuItemGL *mArrowUpItem, *mArrowDownItem; @@ -764,7 +778,7 @@ public: private: virtual BOOL append(LLMenuItemGL* item); public: - virtual BOOL addSeparator(); + virtual BOOL addSeparator(const std::string& name = LLStringUtil::null) override final; virtual void arrange( void ); @@ -844,7 +858,7 @@ public: /*virtual*/ BOOL jumpKeysActive(); // add a vertical separator to this menu - virtual BOOL addSeparator(); + virtual BOOL addSeparator(const std::string& name = LLStringUtil::null) override final; // LLView Functionality virtual BOOL handleHover( S32 x, S32 y, MASK mask ); diff --git a/indra/llui/llscrollbar.cpp b/indra/llui/llscrollbar.cpp index bf1693876..96912a0f5 100644 --- a/indra/llui/llscrollbar.cpp +++ b/indra/llui/llscrollbar.cpp @@ -2,31 +2,25 @@ * @file llscrollbar.cpp * @brief Scrollbar UI widget * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * 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 + * 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. * - * 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 + * 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. * - * 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. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -46,6 +40,7 @@ #include "llwindow.h" #include "llcontrol.h" #include "llrender.h" +#include "lluictrlfactory.h" LLScrollbar::LLScrollbar( const std::string& name, LLRect rect, @@ -402,7 +397,7 @@ BOOL LLScrollbar::handleHover(S32 x, S32 y, MASK mask) } getWindow()->setCursor(UI_CURSOR_ARROW); - LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (active)" << LL_ENDL; + LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (active)" << LL_ENDL; handled = TRUE; } else @@ -414,7 +409,7 @@ BOOL LLScrollbar::handleHover(S32 x, S32 y, MASK mask) if( !handled ) { getWindow()->setCursor(UI_CURSOR_ARROW); - LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (inactive)" << LL_ENDL; + LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (inactive)" << LL_ENDL; handled = TRUE; } @@ -468,6 +463,13 @@ BOOL LLScrollbar::handleMouseUp(S32 x, S32 y, MASK mask) return handled; } +BOOL LLScrollbar::handleDoubleClick(S32 x, S32 y, MASK mask) +{ + // just treat a double click as a second click + return handleMouseDown(x, y, mask); +} + + void LLScrollbar::reshape(S32 width, S32 height, BOOL called_from_parent) { if (width == getRect().getWidth() && height == getRect().getHeight()) return; @@ -509,7 +511,6 @@ void LLScrollbar::draw() mCurGlowStrength = lerp(mCurGlowStrength, 0.f, LLSmoothInterpolation::getInterpolant(0.05f)); } - // Draw background and thumb. LLUIImage* rounded_rect_imagep = LLUI::getUIImage("Rounded_Square"); @@ -525,6 +526,9 @@ void LLScrollbar::draw() } else { + // Thumb + LLRect outline_rect = mThumbRect; + outline_rect.stretch(2); // Background rounded_rect_imagep->drawSolid(mOrientation == HORIZONTAL ? SCROLLBAR_SIZE : 0, mOrientation == VERTICAL ? SCROLLBAR_SIZE : 0, @@ -532,9 +536,6 @@ void LLScrollbar::draw() mOrientation == VERTICAL ? getRect().getHeight() - 2 * SCROLLBAR_SIZE : getRect().getHeight(), mTrackColor); - // Thumb - LLRect outline_rect = mThumbRect; - outline_rect.stretch(2); if (gFocusMgr.getKeyboardFocus() == this) { @@ -636,3 +637,8 @@ void LLScrollbar::onLineDownBtnPressed( const LLSD& data ) { changeLine( mStepSize, TRUE ); } + +void LLScrollbar::setThickness(S32 thickness) +{ + mThickness = thickness < 0 ? SCROLLBAR_SIZE : thickness; +} diff --git a/indra/llui/llscrollbar.h b/indra/llui/llscrollbar.h index fab34326c..2482cce2f 100644 --- a/indra/llui/llscrollbar.h +++ b/indra/llui/llscrollbar.h @@ -2,31 +2,25 @@ * @file llscrollbar.h * @brief Scrollbar UI widget * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * 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 + * Copyright (C) 2010, Linden Research, Inc. * - * 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 + * 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. * - * 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. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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$ */ @@ -36,6 +30,7 @@ #include "stdtypes.h" #include "lluictrl.h" #include "v4color.h" +#include "llbutton.h" // // Constants @@ -59,6 +54,7 @@ public: callback_t change_callback, S32 step_size = 1); +public: virtual ~LLScrollbar(); virtual void setValue(const LLSD& value); @@ -67,6 +63,7 @@ public: virtual BOOL handleKeyHere(KEY key, MASK mask); virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); + virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask); virtual BOOL handleHover(S32 x, S32 y, MASK mask); virtual BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, @@ -104,6 +101,9 @@ public: void onLineUpBtnPressed(const LLSD& data); void onLineDownBtnPressed(const LLSD& data); + S32 getThickness() const { return mThickness; } + void setThickness(S32 thickness); + void setTrackColor( const LLColor4& color ) { mTrackColor = color; } void setThumbColor( const LLColor4& color ) { mThumbColor = color; } void setHighlightColor( const LLColor4& color ) { mHighlightColor = color; } @@ -145,5 +145,4 @@ private: }; - #endif // LL_SCROLLBAR_H diff --git a/indra/llui/llscrollcontainer.cpp b/indra/llui/llscrollcontainer.cpp index eee41b491..778329d1d 100644 --- a/indra/llui/llscrollcontainer.cpp +++ b/indra/llui/llscrollcontainer.cpp @@ -218,6 +218,15 @@ BOOL LLScrollContainer::handleKeyHere(KEY key, MASK mask) return FALSE; } +BOOL LLScrollContainer::handleUnicodeCharHere(llwchar uni_char) +{ + if (mScrolledView && mScrolledView->handleUnicodeCharHere(uni_char)) + { + return TRUE; + } + return FALSE; +} + BOOL LLScrollContainer::handleScrollWheel( S32 x, S32 y, S32 clicks ) { // Give event to my child views - they may have scroll bars @@ -262,7 +271,6 @@ BOOL LLScrollContainer::handleDragAndDrop(S32 x, S32 y, MASK mask, EAcceptance* accept, std::string& tooltip_msg) { - //S32 scrollbar_size = SCROLLBAR_SIZE; // Scroll folder view if needed. Never accepts a drag or drop. *accept = ACCEPT_NO; BOOL handled = autoScroll(x, y); @@ -413,6 +421,7 @@ void LLScrollContainer::calcVisibleSize( S32 *visible_width, S32 *visible_height } } + void LLScrollContainer::draw() { S32 scrollbar_size = SCROLLBAR_SIZE; @@ -525,7 +534,7 @@ bool LLScrollContainer::addChild(LLView* view, S32 tab_group) void LLScrollContainer::updateScroll() { - if (!mScrolledView) + if (!getVisible() || !mScrolledView) { return; } @@ -626,6 +635,7 @@ LLRect LLScrollContainer::getVisibleContentRect() visible_rect.translate(-contents_rect.mLeft, -contents_rect.mBottom); return visible_rect; } + LLRect LLScrollContainer::getContentWindowRect() { updateScroll(); @@ -729,6 +739,13 @@ S32 LLScrollContainer::getBorderWidth() const return 0; } +void LLScrollContainer::setSize(S32 size) +{ + mSize = size; + mScrollbar[VERTICAL]->setThickness(size); + mScrollbar[HORIZONTAL]->setThickness(size); +} + // virtual LLXMLNodePtr LLScrollContainer::getXML(bool save_children) const { diff --git a/indra/llui/llscrollcontainer.h b/indra/llui/llscrollcontainer.h index 8239789b3..c40b95cbe 100644 --- a/indra/llui/llscrollcontainer.h +++ b/indra/llui/llscrollcontainer.h @@ -2,31 +2,25 @@ * @file llscrollcontainer.h * @brief LLScrollContainer class header file. * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * 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 + * Copyright (C) 2010, Linden Research, Inc. * - * 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 + * 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. * - * 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. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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$ */ @@ -78,7 +72,7 @@ public: void setReserveScrollCorner( BOOL b ) { mReserveScrollCorner = b; } LLRect getVisibleContentRect(); LLRect getContentWindowRect(); - const LLRect& getScrolledViewRect() const { return mScrolledView ? mScrolledView->getRect() : LLRect::null; } + virtual const LLRect& getScrolledViewRect() const { return mScrolledView ? mScrolledView->getRect() : LLRect::null; } void pageUp(S32 overlap = 0); void pageDown(S32 overlap = 0); void goToTop(); @@ -90,6 +84,7 @@ public: // LLView functionality virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); virtual BOOL handleKeyHere(KEY key, MASK mask); + virtual BOOL handleUnicodeCharHere(llwchar uni_char); virtual BOOL handleScrollWheel( S32 x, S32 y, S32 clicks ); virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, @@ -105,9 +100,14 @@ public: virtual LLXMLNodePtr getXML(bool save_children) const; static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); + S32 getSize() const { return mSize; } + void setSize(S32 thickness); + +protected: + LLView* mScrolledView; + private: void init(); - // internal scrollbar handlers virtual void scrollHorizontal( S32 new_pos ); virtual void scrollVertical( S32 new_pos ); @@ -117,7 +117,6 @@ public: private: LLScrollbar* mScrollbar[SCROLLBAR_COUNT]; - LLView* mScrolledView; S32 mSize; BOOL mIsOpaque; LLColor4 mBackgroundColor; diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index f46775f6f..78c3c750f 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -2036,6 +2036,11 @@ void LLScrollListCtrl::setFilter(const std::string& filter) adjustScrollbar(unfiltered_count); } +void LLScrollListCtrl::setContextMenu(const std::string& menu) +{ + setContextMenu(LLUICtrlFactory::instance().buildMenu(menu, LLMenuGL::sMenuContainer)); +} + BOOL LLScrollListCtrl::handleHover(S32 x,S32 y,MASK mask) { @@ -2695,51 +2700,32 @@ void LLScrollListCtrl::setScrollListParameters(LLXMLNodePtr node) if (node->hasAttribute("menu_num")) { - // Some scroll lists use common menus identified by number - // 0 is menu_avs_list.xml, 1 will be for groups, 2 could be for lists of objects + // Some UI uses common menus identified by number + // 0 is avatars, 1 will be for groups, others could be for lists of objects or locations or experiences S32 menu_num; node->getAttributeS32("menu_num", menu_num); - setContextMenu(menu_num); + mPopupMenu = sMenus[menu_num]; } else if (node->hasAttribute("menu_file")) { - std::string menu_file; - node->getAttributeString("menu_file", menu_file); - mPopupMenu = LLUICtrlFactory::getInstance()->buildMenu(menu_file, LLMenuGL::sMenuContainer); + std::string menu; + node->getAttributeString("menu_file", menu); + if (!menu.empty()) setContextMenu(menu); } -} - -// static -LLView* LLScrollListCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) -{ - LLRect rect; - createRect(node, rect, parent, LLRect()); - - BOOL multi_select = false; - node->getAttributeBOOL("multi_select", multi_select); - BOOL draw_border = true; - node->getAttributeBOOL("draw_border", draw_border); - BOOL draw_heading = false; - node->getAttributeBOOL("draw_heading", draw_heading); - S32 search_column = 0; - node->getAttributeS32("search_column", search_column); - S32 sort_column = -1; - node->getAttributeS32("sort_column", sort_column); - BOOL sort_ascending = true; - node->getAttributeBOOL("sort_ascending", sort_ascending); - - LLScrollListCtrl* scroll_list = new LLScrollListCtrl("scroll_list", rect, NULL, multi_select, draw_border, draw_heading); if (node->hasAttribute("heading_height")) { S32 heading_height; node->getAttributeS32("heading_height", heading_height); - scroll_list->setHeadingHeight(heading_height); + setHeadingHeight(heading_height); } - scroll_list->setScrollListParameters(node); - scroll_list->initFromXML(node, parent); - scroll_list->setSearchColumn(search_column); + S32 search_column = 0; + node->getAttributeS32("search_column", search_column); + BOOL sort_ascending = true; + node->getAttributeBOOL("sort_ascending", sort_ascending); + + setSearchColumn(search_column); LLSD columns; S32 index = 0; @@ -2750,7 +2736,7 @@ LLView* LLScrollListCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFac { if (child->hasName("column") || child->hasName("columns") || child->hasName(kidcolumn) || child->hasName(kidcolumns)) { - std::string labelname(""); + std::string labelname; if (child->getAttributeString("label", labelname)) columns[index]["label"] = labelname; else if (child->getAttributeString("image", labelname)) @@ -2773,9 +2759,9 @@ LLView* LLScrollListCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFac } else // Singu Note: if a scroll list does not provide sort_direction, provide sort_ascending to sort as expected { - bool sort_ascending = true; - child->getAttribute_bool("sort_ascending", sort_ascending); - columns[index]["sort_ascending"] = sort_ascending; + bool col_sort_ascending = sort_ascending; + child->getAttribute_bool("sort_ascending", col_sort_ascending); + columns[index]["sort_ascending"] = col_sort_ascending; } S32 columnwidth = -1; @@ -2801,12 +2787,7 @@ LLView* LLScrollListCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFac ++index; } } - scroll_list->setColumnHeadings(columns); - - if (sort_column >= 0) - { - scroll_list->sortByColumnIndex(sort_column, sort_ascending); - } + setColumnHeadings(columns); const std::string kidrow(nodename + "row"); const std::string kidrows(nodename + "rows"); @@ -2851,25 +2832,53 @@ LLView* LLScrollListCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFac } } if(explicit_column) - scroll_list->addElement(row); + addElement(row); else { LLSD entry_id; if(id_found) entry_id = id; - scroll_list->addSimpleElement(value,ADD_BOTTOM,entry_id); + addSimpleElement(value,ADD_BOTTOM,entry_id); } } } - scroll_list->setCommentText(node->getTextContents()); + S32 sort_column = -1; + node->getAttributeS32("sort_column", sort_column); + if (sort_column >= 0) + { + sortByColumnIndex(sort_column, sort_ascending); + } + + setCommentText(node->getTextContents()); +} + +// static +LLView* LLScrollListCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) +{ + LLRect rect; + createRect(node, rect, parent, LLRect()); + + BOOL multi_select = false; + node->getAttributeBOOL("multi_select", multi_select); + + BOOL draw_border = true; + node->getAttributeBOOL("draw_border", draw_border); + + BOOL draw_heading = false; + node->getAttributeBOOL("draw_heading", draw_heading); + + LLScrollListCtrl* scroll_list = new LLScrollListCtrl("scroll_list", rect, NULL, multi_select, draw_border, draw_heading); + + scroll_list->setScrollListParameters(node); + scroll_list->initFromXML(node, parent); return scroll_list; } // LLEditMenuHandler functions // virtual -void LLScrollListCtrl::copy() +void LLScrollListCtrl::copy() const { std::string buffer; for (auto item : getAllSelected()) diff --git a/indra/llui/llscrolllistctrl.h b/indra/llui/llscrolllistctrl.h index c09af350a..c1dcf8eed 100644 --- a/indra/llui/llscrolllistctrl.h +++ b/indra/llui/llscrolllistctrl.h @@ -202,7 +202,7 @@ public: virtual S32 getFirstSelectedIndex() const; std::vector getAllSelected() const; uuid_vec_t getSelectedIDs() const override final; //Helper. Much like getAllSelected, but just provides a LLUUID vec - S32 getNumSelected() const override final; + S32 getNumSelected() const; LLScrollListItem* getLastSelectedItem() const { return mLastSelected; } // iterate over all items @@ -254,9 +254,18 @@ public: bool filterItem(LLScrollListItem* item); void setFilter(const std::string& filter); - // support right-click context menus for avatar/group lists + // Context Menus void setContextMenu(LLMenuGL* menu) { mPopupMenu = menu; } - void setContextMenu(S32 index) { mPopupMenu = sMenus[index]; } + void setContextMenu(U8 index) { mPopupMenu = sMenus[index]; } + void setContextMenu(const std::string& menu); + + Type getSelectedType() const override + { + for (auto i = 0; mPopupMenu && i < COUNT; ++i) + if (sMenus[i] == mPopupMenu) + return (Type)i; + return LFIDBearer::getSelectedType(); + } // Overridden from LLView /*virtual*/ void draw(); @@ -313,7 +322,7 @@ public: virtual void scrollToShowSelected(); // LLEditMenuHandler functions - virtual void copy(); + void copy() const override final; virtual BOOL canCopy() const; virtual void cut(); virtual BOOL canCut() const; diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp index a9eb63a40..6de751197 100644 --- a/indra/llui/lltabcontainer.cpp +++ b/indra/llui/lltabcontainer.cpp @@ -1896,3 +1896,8 @@ void LLTabContainer::commitHoveredButton(S32 x, S32 y) } } +S32 LLTabContainer::getTotalTabWidth() const +{ + return mTotalTabWidth; +} + diff --git a/indra/llui/lltabcontainer.h b/indra/llui/lltabcontainer.h index de5a51639..311e14b30 100644 --- a/indra/llui/lltabcontainer.h +++ b/indra/llui/lltabcontainer.h @@ -98,6 +98,7 @@ public: S32 getIndexForPanel(LLPanel* panel); S32 getPanelIndexByTitle(const std::string& title); LLPanel* getPanelByName(const std::string& name); + S32 getTotalTabWidth() const; void setCurrentTabName(const std::string& name); void selectFirstTab(); diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index 25400455b..b0001df24 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -244,8 +244,6 @@ private: /////////////////////////////////////////////////////////////////// -LLTextEditor::is_friend_signal_t* LLTextEditor::mIsFriendSignal = nullptr; -LLTextEditor::is_blocked_signal_t* LLTextEditor::mIsObjectBlockedSignal = nullptr; LLTextEditor::LLTextEditor( const std::string& name, @@ -372,36 +370,46 @@ LLTextEditor::~LLTextEditor() menu->die(); mPopupMenuHandle.markDead(); } - /* Singu Note: Static this, we'll use it wherever we can! - delete mIsFriendSignal; - delete mIsObjectBlockedSignal;*/ } const std::string& LLTextEditor::getMenuSegmentUrl() const { auto segment = getSegmentAtLocalPos(mLastContextMenuX, mLastContextMenuY); - auto style = segment->getStyle(); + auto style = segment ? segment->getStyle() : nullptr; return style ? style->getLinkHREF() : LLStringUtil::null; } -static LLTextEditor* get_focused_text_editor() +static LFIDBearer::Type get_type_from_url(const std::string& url) { - auto* te = -#ifdef SHOW_ASSERT - dynamic_cast -#else - static_cast -#endif - (gFocusMgr.getKeyboardFocus()); - llassert(te); // This listener only applies to text editors - return te; + auto pos = url.find("/app/"); + if (pos != std::string::npos && pos + 10 <= url.size()) + { + auto type = url.substr(pos + 5, 5); + return type == "agent" ? LFIDBearer::AVATAR + : type == "group" ? LFIDBearer::GROUP + : type == "experience" ? LFIDBearer::EXPERIENCE + : LFIDBearer::OBJECT; + } + return LFIDBearer::NONE; +} + +LLUUID LLTextEditor::getStringUUIDSelectedItem() const +{ + const auto& url = getMenuSegmentUrl(); + const auto& type = get_type_from_url(url); + return type == LFIDBearer::NONE ? LLUUID::null : LLUUID(type == OBJECT ? LLUrlAction::getObjectId(url) : LLUrlAction::getUserID(url)); +} + +LFIDBearer::Type LLTextEditor::getSelectedType() const +{ + return get_type_from_url(getMenuSegmentUrl()); } class CopyRawText : public LLMemberListener { bool handleEvent(LLPointer, const LLSD& userdata) override { - get_focused_text_editor()->copyRaw(); + LFIDBearer::getActive()->copyRaw(); return true; } }; @@ -415,16 +423,11 @@ class TextEditorVisible : public LLMemberListener } }; -static const std::string& get_focused_url() -{ - return get_focused_text_editor()->getMenuSegmentUrl(); -} - class ContextUrl : public LLMemberListener { bool handleEvent(LLPointer, const LLSD& userdata) override { - const auto& url = get_focused_url(); + const auto& url = LFIDBearer::getActive()->getMenuSegmentUrl(); const auto& op = userdata.asStringRef(); if (op == "Open") LLUrlAction::openURL(url); else if (op == "OpenInternal") LLUrlAction::openURLInternal(url); @@ -433,10 +436,6 @@ class ContextUrl : public LLMemberListener else if (op == "Block") LLUrlAction::blockObject(url); else if (op == "Unblock") LLUrlAction::unblockObject(url); else if (op == "Teleport") LLUrlAction::teleportToLocation(url); - else if (op == "ShowProfile") LLUrlAction::showProfile(url); - else if (op == "AddFriend") LLUrlAction::addFriend(url); - else if (op == "RemoveFriend") LLUrlAction::removeFriend(url); - else if (op == "SendIM") LLUrlAction::sendIM(url); else if (op == "ShowOnMap") LLUrlAction::showLocationOnMap(url); else if (op == "CopyLabel") LLUrlAction::copyLabelToClipboard(url); else if (op == "CopyUrl") LLUrlAction::copyURLToClipboard(url); @@ -444,67 +443,15 @@ class ContextUrl : public LLMemberListener } }; -class ContextIDUrl : public LLMemberListener -{ -protected: - std::string getID(const std::string& type) const - { - const auto& url = get_focused_url(); - // Empty works like avatar and group, "object" is an object (you needed to be told this) - return type.empty() ? LLUrlAction::getUserID(url) : LLUrlAction::getObjectId(url); - } -}; - -class ContextUrlCopy : public ContextIDUrl +class ContextUrlCopy : public LLMemberListener { bool handleEvent(LLPointer, const LLSD& userdata) override { - LLView::getWindow()->copyTextToClipboard(utf8str_to_wstring(getID(userdata.asStringRef()))); + LLView::getWindow()->copyTextToClipboard(utf8str_to_wstring(LFIDBearer::getActiveSelectedID().asString())); return true; } }; -class ContextUrlExt : public ContextIDUrl -{ - bool handleEvent(LLPointer, const LLSD& userdata) override - { - std::string cmd = userdata.asStringRef(); - std::string type; - const auto sep = cmd.find(','); - if (sep != std::string::npos) - { - type = cmd.substr(sep); - cmd = cmd.substr(0, sep); - } - mExtCallback(cmd, LLUUID(getID(type))); - return true; - } - LLTextEditor::ext_slurl_cb mExtCallback; -public: - ContextUrlExt(LLTextEditor::ext_slurl_cb cb) : mExtCallback(cb) {} -}; - -class ContextUrlExtVisible : public ContextIDUrl -{ - bool handleEvent(LLPointer, const LLSD& userdata) override - { - std::string cmd = userdata["data"]; - std::string type; - const auto sep = cmd.find(','); - if (sep != std::string::npos) - { - type = cmd.substr(sep); - cmd = cmd.substr(0, sep); - } - - LLMenuGL::sMenuContainer->findControl(userdata["control"].asString())->setValue(mExtVCB(cmd, LLUUID(getID(type)))); - return true; - } - LLTextEditor::ext_slurl_visible_cb mExtVCB; -public: - ContextUrlExtVisible(LLTextEditor::ext_slurl_visible_cb vcb) : mExtVCB(vcb) {} -}; - void LLTextEditor::spell_correct(void* data) { @@ -581,14 +528,12 @@ void LLTextEditor::spell_add(void* data) } //static -void LLTextEditor::addMenuListeners(ext_slurl_cb cb, ext_slurl_visible_cb vcb) +void LLTextEditor::addMenuListeners() { (new CopyRawText)->registerListener(LLMenuGL::sMenuContainer, "CopyRawText"); (new TextEditorVisible)->registerListener(LLMenuGL::sMenuContainer, "TextEditorVisible"); (new ContextUrl)->registerListener(LLMenuGL::sMenuContainer, "Text.Url"); (new ContextUrlCopy)->registerListener(LLMenuGL::sMenuContainer, "Text.Url.CopyUUID"); - (new ContextUrlExt(cb))->registerListener(LLMenuGL::sMenuContainer, "Text.Url.Ext"); - (new ContextUrlExtVisible(vcb))->registerListener(LLMenuGL::sMenuContainer, "Text.Url.ExtVisible"); } void LLTextEditor::setTrackColor( const LLColor4& color ) @@ -767,34 +712,6 @@ LLMenuGL* LLTextEditor::createUrlContextMenu(S32 x, S32 y, const std::string &in // create and return the context menu from the XUI file llassert(LLMenuGL::sMenuContainer != NULL); auto menu = LLUICtrlFactory::instance().buildMenu(xui_file, LLMenuGL::sMenuContainer); - if (menu) - { - if (mIsFriendSignal) - { - bool isFriend = *(*mIsFriendSignal)(LLUUID(LLUrlAction::getUserID(url))); - LLView* addFriendButton = menu->findChild("add_friend"); - LLView* removeFriendButton = menu->findChild("remove_friend"); - - if (addFriendButton && removeFriendButton) - { - addFriendButton->setVisible(!isFriend); - removeFriendButton->setVisible(isFriend); - } - } - - if (mIsObjectBlockedSignal) - { - bool is_blocked = *(*mIsObjectBlockedSignal)(LLUUID(LLUrlAction::getObjectId(url)), LLUrlAction::getObjectName(url)); - LLView* blockButton = menu->findChild("block_object"); - LLView* unblockButton = menu->findChild("unblock_object"); - - if (blockButton && unblockButton) - { - blockButton->setVisible(!is_blocked); - unblockButton->setVisible(is_blocked); - } - } - } return menu; } @@ -1575,9 +1492,7 @@ BOOL LLTextEditor::handleRightMouseDown( S32 x, S32 y, MASK mask ) mLastContextMenuX = x; mLastContextMenuY = y; - menu->buildDrawLabels(); - menu->updateParent(LLMenuGL::sMenuContainer); - LLMenuGL::showPopup(this, menu, x, y); + showMenu(this, menu, x, y); } return TRUE; } @@ -2302,7 +2217,7 @@ BOOL LLTextEditor::canCopy() const } // copy selection to clipboard -void LLTextEditor::copy(bool raw) +void LLTextEditor::copy(bool raw) const { if( !canCopy() ) { @@ -4295,6 +4210,12 @@ void LLTextEditor::appendTextImpl(const std::string &new_text, const LLStyleSP s }; auto append_link = [&](const std::string& link, LLStyleSP link_style) { + if (!link_style->isLink()) + { + appendAndHighlightText(link, part, style); + return; + } + if (style) // Respect styling { const auto& text_style = *style; @@ -4308,8 +4229,9 @@ void LLTextEditor::appendTextImpl(const std::string &new_text, const LLStyleSP s if (always_underline) link_style->mUnderline = true; appendAndHighlightText(link, part, link_style, !always_underline/*match.underlineOnHoverOnly()*/); }; - const auto&& cb = force_replace_links ? boost::bind(&LLTextEditor::replaceUrl, this, _1, _2, _3) : LLUrlLabelCallback(); - while (!text.empty() && LLUrlRegistry::instance().findUrl(text, match, cb)) + const auto&& cb = force_replace_links ? boost::bind(&LLTextEditor::replaceUrl, this, _1, _2, _3) : static_cast(LLUrlRegistryNullCallback); + auto& urlr = LLUrlRegistry::instance(); + while (!text.empty() && urlr.findUrl(text, match, cb)) { start = match.getStart(); end = match.getEnd()+1; @@ -4432,7 +4354,7 @@ void LLTextEditor::appendAndHighlightText(const std::string& new_text, S32 highl std::string::size_type start = 0; /*std::string::size_type pos = new_text.find('\n',start); - while(pos!=-1) + while(pos != std::string::npos) { if(pos!=start) { @@ -5173,24 +5095,6 @@ BOOL LLTextEditor::exportBuffer(std::string &buffer ) return TRUE; } -boost::signals2::connection LLTextEditor::setIsFriendCallback(const is_friend_signal_t::slot_type& cb) -{ - if (!mIsFriendSignal) - { - mIsFriendSignal = new is_friend_signal_t(); - } - return mIsFriendSignal->connect(cb); -} - -boost::signals2::connection LLTextEditor::setIsObjectBlockedCallback(const is_blocked_signal_t::slot_type& cb) -{ - if (!mIsObjectBlockedSignal) - { - mIsObjectBlockedSignal = new is_blocked_signal_t(); - } - return mIsObjectBlockedSignal->connect(cb); -} - ////////////////////////////////////////////////////////////////////////// // LLTextSegment diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h index a18907749..6ce91abb7 100644 --- a/indra/llui/lltexteditor.h +++ b/indra/llui/lltexteditor.h @@ -43,6 +43,7 @@ #include "lleditmenuhandler.h" #include "llpreeditor.h" +#include "lfidbearer.h" class LLFontGL; class LLKeywordToken; @@ -50,6 +51,7 @@ class LLMenuGL; class LLTextCmd; class LLTextEditor : public LLUICtrl, LLEditMenuHandler, protected LLPreeditor +, public LFIDBearer { public: // @@ -71,16 +73,12 @@ public: const std::string& getMenuSegmentUrl() const; + LLUUID getStringUUIDSelectedItem() const override final; + Type getSelectedType() const override final; + typedef boost::signals2::signal keystroke_signal_t; - typedef boost::signals2::signal is_friend_signal_t; - typedef boost::signals2::signal is_blocked_signal_t; - static boost::signals2::connection setIsFriendCallback(const is_friend_signal_t::slot_type& cb); - static boost::signals2::connection setIsObjectBlockedCallback(const is_blocked_signal_t::slot_type& cb); - - typedef std::function ext_slurl_cb; - typedef std::function ext_slurl_visible_cb; - static void addMenuListeners(ext_slurl_cb cb, ext_slurl_visible_cb vcb); + static void addMenuListeners(); void setKeystrokeCallback(const keystroke_signal_t::slot_type& callback); @@ -131,9 +129,9 @@ public: virtual BOOL canRedo() const; virtual void cut(); virtual BOOL canCut() const; - void copy(bool raw); - void copyRaw() { copy(true); } - virtual void copy() { copy(false); } + void copy(bool raw) const; + void copyRaw() const { copy(true); } + void copy() const override final { copy(false); } virtual BOOL canCopy() const; virtual void paste(); virtual BOOL canPaste() const; @@ -468,10 +466,6 @@ protected: void (*mOnScrollEndCallback)(void*); void *mOnScrollEndData; - // Used to check if user with given ID is avatar's friend - static is_friend_signal_t* mIsFriendSignal; - static is_blocked_signal_t* mIsObjectBlockedSignal; - LLWString mPreeditWString; LLWString mPreeditOverwrittenWString; std::vector mPreeditPositions; diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp index a737c446f..18330a1bc 100644 --- a/indra/llui/llurlentry.cpp +++ b/indra/llui/llurlentry.cpp @@ -1,5 +1,3 @@ -// This is an open source non-commercial project. Dear PVS-Studio, please check it. -// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com /** * @file llurlentry.cpp * @author Martin Reddy @@ -40,6 +38,7 @@ #include "lltrans.h" //#include "lluicolortable.h" #include "message.h" +#include "llexperiencecache.h" #include #include // @@ -72,7 +71,7 @@ std::string LLUrlEntryBase::getIcon(const std::string &url) LLStyleSP LLUrlEntryBase::getStyle() const { - static LLUICachedControl color("HTMLLinkColor"); + static const LLUICachedControl color("HTMLLinkColor"); LLStyleSP style_params(new LLStyle(true, color, LLStringUtil::null)); //style_params->mUnderline = true; // Singu Note: We're not gonna bother here, underlining on hover return style_params; @@ -230,7 +229,7 @@ static std::string getStringAfterToken(const std::string& str, const std::string size_t pos = str.find(token); if (pos == std::string::npos) { - return std::string(); + return LLStringUtil::null; } pos += token.size(); @@ -385,9 +384,9 @@ bool LLUrlEntryInvalidSLURL::isSLURLvalid(const std::string &url) const if (path_parts == actual_parts) { // handle slurl with (X,Y,Z) coordinates - LLStringUtil::convertToS32(path_array[path_parts-3],x); - LLStringUtil::convertToS32(path_array[path_parts-2],y); - LLStringUtil::convertToS32(path_array[path_parts-1],z); + LLStringUtil::convertToS32(path_array[path_parts-3].asString(),x); + LLStringUtil::convertToS32(path_array[path_parts-2].asString(),y); + LLStringUtil::convertToS32(path_array[path_parts-1].asString(),z); if((x>= 0 && x<= 256) && (y>= 0 && y<= 256) && (z>= 0)) { @@ -398,8 +397,8 @@ bool LLUrlEntryInvalidSLURL::isSLURLvalid(const std::string &url) const { // handle slurl with (X,Y) coordinates - LLStringUtil::convertToS32(path_array[path_parts-2],x); - LLStringUtil::convertToS32(path_array[path_parts-1],y); + LLStringUtil::convertToS32(path_array[path_parts-2].asString(),x); + LLStringUtil::convertToS32(path_array[path_parts-1].asString(),y); ; if((x>= 0 && x<= 256) && (y>= 0 && y<= 256)) { @@ -409,7 +408,7 @@ bool LLUrlEntryInvalidSLURL::isSLURLvalid(const std::string &url) const else if (path_parts == (actual_parts-2)) { // handle slurl with (X) coordinate - LLStringUtil::convertToS32(path_array[path_parts-1],x); + LLStringUtil::convertToS32(path_array[path_parts-1].asString(),x); if(x>= 0 && x<= 256) { return TRUE; @@ -427,6 +426,7 @@ LLUrlEntrySLURL::LLUrlEntrySLURL() // see http://slurl.com/about.php for details on the SLURL format mPattern = boost::regex("https?://(maps.secondlife.com|slurl.com)/secondlife/[^ /]+(/\\d+){0,3}(/?(\\?\\S*)?)?", boost::regex::perl|boost::regex::icase); + mIcon = "Hand"; mMenuName = "menu_url_slurl.xml"; mTooltip = LLTrans::getString("TooltipSLURL"); } @@ -643,10 +643,11 @@ bool LLUrlEntryAgent::underlineOnHoverOnly(const std::string &string) const std::string LLUrlEntryAgent::getLabel(const std::string &url, const LLUrlLabelCallback &cb) { + static std::string name_wait_str = LLTrans::getString("LoadingData"); if (!gCacheName) { // probably at the login screen, use short string for layout - return LLTrans::getString("LoadingData"); + return name_wait_str; } std::string agent_id_string = getIDStringFromUrl(url); @@ -673,19 +674,16 @@ std::string LLUrlEntryAgent::getLabel(const std::string &url, const LLUrlLabelCa } else { - if (cb) - { - auto connection = LLAvatarNameCache::get(agent_id, boost::bind(&LLUrlEntryAgent::onAvatarNameCache, this, _1, _2)); - mAvatarNameCacheConnections.emplace(agent_id, connection); - addObserver(agent_id_string, url, cb); - } - return LLTrans::getString("LoadingData"); + auto connection = LLAvatarNameCache::get(agent_id, boost::bind(&LLUrlEntryAgent::onAvatarNameCache, this, _1, _2)); + mAvatarNameCacheConnections.emplace(agent_id, connection); + addObserver(agent_id_string, url, cb); + return name_wait_str; } } LLStyleSP LLUrlEntryAgent::getStyle() const { - static LLUICachedControl color("HTMLAgentColor"); + static const LLUICachedControl color("HTMLAgentColor"); LLStyleSP style_params(new LLStyle(true, color, LLStringUtil::null)); return style_params; } @@ -762,10 +760,11 @@ void LLUrlEntryAgentName::onAvatarNameCache(const LLUUID& id, std::string LLUrlEntryAgentName::getLabel(const std::string &url, const LLUrlLabelCallback &cb) { + static std::string name_wait_str = LLTrans::getString("LoadingData"); if (!gCacheName) { // probably at the login screen, use short string for layout - return LLTrans::getString("LoadingData"); + return name_wait_str; } std::string agent_id_string = getIDStringFromUrl(url); @@ -788,19 +787,16 @@ std::string LLUrlEntryAgentName::getLabel(const std::string &url, const LLUrlLab } else { - if (cb) - { - auto connection = LLAvatarNameCache::get(agent_id, boost::bind(&LLUrlEntryAgentName::onAvatarNameCache, this, _1, _2)); - mAvatarNameCacheConnections.emplace(agent_id, connection); - addObserver(agent_id_string, url, cb); - } - return LLTrans::getString("LoadingData"); + auto connection = LLAvatarNameCache::get(agent_id, boost::bind(&LLUrlEntryAgentName::onAvatarNameCache, this, _1, _2)); + mAvatarNameCacheConnections.emplace(agent_id, connection); + addObserver(agent_id_string, url, cb); + return name_wait_str; } } LLStyleSP LLUrlEntryAgentName::getStyle() const { - static LLUICachedControl color("HTMLAgentColor"); + static const LLUICachedControl color("HTMLAgentColor"); LLStyleSP style_params(new LLStyle(true, color, LLStringUtil::null)); return style_params; } @@ -927,13 +923,10 @@ std::string LLUrlEntryGroup::getLabel(const std::string &url, const LLUrlLabelCa } else { - if (cb) - { - gCacheName->getGroup(group_id, - boost::bind(&LLUrlEntryGroup::onGroupNameReceived, - this, _1, _2, _3)); - addObserver(group_id_string, url, cb); - } + gCacheName->getGroup(group_id, + boost::bind(&LLUrlEntryGroup::onGroupNameReceived, + this, _1, _2, _3)); + addObserver(group_id_string, url, cb); return LLTrans::getString("LoadingData"); } } @@ -1037,7 +1030,7 @@ std::string LLUrlEntryParcel::getLabel(const std::string &url, const LLUrlLabelC std::string parcel_id_string = unescapeUrl(path_array[2]); // parcel id // Add an observer to call LLUrlLabelCallback when we have parcel name. - if (cb) addObserver(parcel_id_string, url, cb); + addObserver(parcel_id_string, url, cb); LLUUID parcel_id(parcel_id_string); @@ -1084,11 +1077,8 @@ void LLUrlEntryParcel::processParcelInfo(const LLParcelData& parcel_data) parcel_data.sim_name.c_str(), region_x, region_y, region_z); } - for (std::set::iterator iter = sParcelInfoObservers.begin(); - iter != sParcelInfoObservers.end(); - ++iter) + for (auto url_entry : sParcelInfoObservers) { - LLUrlEntryParcel* url_entry = *iter; if (url_entry) { url_entry->onParcelInfoReceived(parcel_data.parcel_id.asString(), label); @@ -1432,8 +1422,9 @@ std::string LLUrlEntryNoLink::getLabel(const std::string &url, const LLUrlLabelC LLStyleSP LLUrlEntryNoLink::getStyle() const { // Don't render as URL (i.e. no context menu or hand cursor). - // Singu Note: What the heck? No, that's misleading!! - return LLUrlEntryBase::getStyle(); + LLStyleSP style(new LLStyle()); + style->setLinkHREF(" "); + return style; } @@ -1502,13 +1493,65 @@ std::string LLUrlEntryEmail::getUrl(const std::string &string) const return escapeUrl(string); } +LLUrlEntryExperienceProfile::LLUrlEntryExperienceProfile() +{ + mPattern = boost::regex(APP_HEADER_REGEX "/experience/[\\da-f-]+/\\w+\\S*", + boost::regex::perl|boost::regex::icase); + mIcon = "Generic_Experience"; + mMenuName = "menu_url_experience.xml"; +} + +std::string LLUrlEntryExperienceProfile::getLabel(const std::string& url, const LLUrlLabelCallback& cb) +{ + if (!gCacheName) + { + // probably at the login screen, use short string for layout + return LLTrans::getString("LoadingData"); + } + + std::string experience_id_string = getIDStringFromUrl(url); + if (experience_id_string.empty()) + { + // something went wrong, just give raw url + return unescapeUrl(url); + } + + LLUUID experience_id(experience_id_string); + if (experience_id.isNull()) + { + return LLTrans::getString("ExperienceNameNull"); + } + + const LLSD& experience_details = LLExperienceCache::instance().get(experience_id); + if (!experience_details.isUndefined()) + { + std::string experience_name_string = experience_details[LLExperienceCache::NAME].asString(); + return experience_name_string.empty() ? LLTrans::getString("ExperienceNameUntitled") : experience_name_string; + } + + addObserver(experience_id_string, url, cb); + LLExperienceCache::instance().get(experience_id, boost::bind(&LLUrlEntryExperienceProfile::onExperienceDetails, this, _1)); + return LLTrans::getString("LoadingData"); + +} + +void LLUrlEntryExperienceProfile::onExperienceDetails(const LLSD& experience_details) +{ + std::string name = experience_details[LLExperienceCache::NAME].asString(); + if(name.empty()) + { + name = LLTrans::getString("ExperienceNameUntitled"); + } + callObservers(experience_details[LLExperienceCache::EXPERIENCE_ID].asString(), name, LLStringUtil::null); +} + // // // LLUrlEntryJIRA describes a Jira Issue Tracker entry // LLUrlEntryJira::LLUrlEntryJira() { - mPattern = boost::regex("((?:ALCH|SV|BUG|CHOP|FIRE|MAINT|OPEN|SCR|STORM|SVC|VWR|WEB)-\\d+)", + mPattern = boost::regex("(\\b(?:ALCH|SV|BUG|CHOP|FIRE|MAINT|OPEN|SCR|STORM|SVC|VWR|WEB)-\\d+)", boost::regex::perl); mMenuName = "menu_url_http.xml"; mTooltip = LLTrans::getString("TooltipHttpUrl"); @@ -1532,10 +1575,9 @@ std::string LLUrlEntryJira::getUrl(const std::string &url) const (url.find("SV") != std::string::npos) ? "https://singularityviewer.atlassian.net/browse/%1%" : (url.find("FIRE") != std::string::npos) ? - "http://jira.phoenixviewer.com/browse/%1%" : + "https://jira.firestormviewer.com/browse/%1%" : "http://jira.secondlife.com/browse/%1%" ) % url).str(); } // - diff --git a/indra/llui/llurlentry.h b/indra/llui/llurlentry.h index 01f1fb1ae..6c382aa26 100644 --- a/indra/llui/llurlentry.h +++ b/indra/llui/llurlentry.h @@ -42,7 +42,7 @@ class LLAvatarName; typedef boost::signals2::signal LLUrlLabelSignal; -typedef LLUrlLabelSignal::slot_function_type LLUrlLabelCallback; +typedef LLUrlLabelSignal::slot_type LLUrlLabelCallback; /// /// LLUrlEntryBase is the base class of all Url types registered in the @@ -132,7 +132,7 @@ protected: /// /// LLUrlEntryHTTP Describes generic http: and https: Urls /// -class LLUrlEntryHTTP : public LLUrlEntryBase +class LLUrlEntryHTTP final : public LLUrlEntryBase { public: LLUrlEntryHTTP(); @@ -144,7 +144,7 @@ public: /// /// LLUrlEntryHTTPLabel Describes generic http: and https: Urls with custom labels /// -class LLUrlEntryHTTPLabel : public LLUrlEntryBase +class LLUrlEntryHTTPLabel final : public LLUrlEntryBase { public: LLUrlEntryHTTPLabel(); @@ -156,7 +156,7 @@ public: /// /// LLUrlEntryHTTPNoProtocol Describes generic Urls like www.google.com /// -class LLUrlEntryHTTPNoProtocol : public LLUrlEntryBase +class LLUrlEntryHTTPNoProtocol final : public LLUrlEntryBase { public: LLUrlEntryHTTPNoProtocol(); @@ -166,7 +166,7 @@ public: std::string getTooltip(const std::string &url) const override; }; -class LLUrlEntryInvalidSLURL : public LLUrlEntryBase +class LLUrlEntryInvalidSLURL final : public LLUrlEntryBase { public: LLUrlEntryInvalidSLURL(); @@ -180,7 +180,7 @@ public: /// /// LLUrlEntrySLURL Describes http://slurl.com/... Urls /// -class LLUrlEntrySLURL : public LLUrlEntryBase +class LLUrlEntrySLURL final : public LLUrlEntryBase { public: LLUrlEntrySLURL(); @@ -205,7 +205,7 @@ public: /// /// LLUrlEntrySeconlifeURLs Describes *secondlife.com and *lindenlab.com Urls /// -class LLUrlEntrySimpleSecondlifeURL : public LLUrlEntrySecondlifeURL +class LLUrlEntrySimpleSecondlifeURL final : public LLUrlEntrySecondlifeURL { public: LLUrlEntrySimpleSecondlifeURL(); @@ -281,7 +281,7 @@ private: /// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/completename /// that displays the full display name + user name for an avatar /// such as "James Linden (james.linden)" -class LLUrlEntryAgentCompleteName : public LLUrlEntryAgentName +class LLUrlEntryAgentCompleteName final : public LLUrlEntryAgentName { public: LLUrlEntryAgentCompleteName(); @@ -289,7 +289,7 @@ private: /*virtual*/ std::string getName(const LLAvatarName& avatar_name) override; }; -class LLUrlEntryAgentLegacyName : public LLUrlEntryAgentName +class LLUrlEntryAgentLegacyName final : public LLUrlEntryAgentName { public: LLUrlEntryAgentLegacyName(); @@ -302,7 +302,7 @@ private: /// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/displayname /// that displays the just the display name for an avatar /// such as "James Linden" -class LLUrlEntryAgentDisplayName : public LLUrlEntryAgentName +class LLUrlEntryAgentDisplayName final : public LLUrlEntryAgentName { public: LLUrlEntryAgentDisplayName(); @@ -315,7 +315,7 @@ private: /// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/username /// that displays the just the display name for an avatar /// such as "james.linden" -class LLUrlEntryAgentUserName : public LLUrlEntryAgentName +class LLUrlEntryAgentUserName final : public LLUrlEntryAgentName { public: LLUrlEntryAgentUserName(); @@ -323,11 +323,25 @@ private: /*virtual*/ std::string getName(const LLAvatarName& avatar_name) override; }; +/// +/// LLUrlEntryExperienceProfile Describes a Second Life experience profile Url, e.g., +/// secondlife:///app/experience/0e346d8b-4433-4d66-a6b0-fd37083abc4c/profile +/// that displays the experience name +class LLUrlEntryExperienceProfile final : public LLUrlEntryBase +{ +public: + LLUrlEntryExperienceProfile(); + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) override; +private: + void onExperienceDetails(const LLSD& experience_details); +}; + + /// /// LLUrlEntryGroup Describes a Second Life group Url, e.g., /// secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/about /// -class LLUrlEntryGroup : public LLUrlEntryBase +class LLUrlEntryGroup final : public LLUrlEntryBase { public: LLUrlEntryGroup(); @@ -342,7 +356,7 @@ private: /// LLUrlEntryInventory Describes a Second Life inventory Url, e.g., /// secondlife:///app/inventory/0e346d8b-4433-4d66-a6b0-fd37083abc4c/select /// -class LLUrlEntryInventory : public LLUrlEntryBase +class LLUrlEntryInventory final : public LLUrlEntryBase { public: LLUrlEntryInventory(); @@ -354,7 +368,7 @@ private: /// LLUrlEntryObjectIM Describes a Second Life inspector for the object Url, e.g., /// secondlife:///app/objectim/7bcd7864-da6b-e43f-4486-91d28a28d95b?name=Object&owner=3de548e1-57be-cfea-2b78-83ae3ad95998&slurl=Danger!%20Danger!/200/200/30/&groupowned=1 /// -class LLUrlEntryObjectIM : public LLUrlEntryBase +class LLUrlEntryObjectIM final : public LLUrlEntryBase { public: LLUrlEntryObjectIM(); @@ -367,7 +381,7 @@ private: /// LLUrlEntryParcel Describes a Second Life parcel Url, e.g., /// secondlife:///app/parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/about /// -class LLUrlEntryParcel : public LLUrlEntryBase +class LLUrlEntryParcel final : public LLUrlEntryBase { public: struct LLParcelData @@ -414,7 +428,7 @@ private: /// LLUrlEntryPlace Describes a Second Life location Url, e.g., /// secondlife://Ahern/50/50/50 /// -class LLUrlEntryPlace : public LLUrlEntryBase +class LLUrlEntryPlace final : public LLUrlEntryBase { public: LLUrlEntryPlace(); @@ -426,7 +440,7 @@ public: /// LLUrlEntryRegion Describes a Second Life location Url, e.g., /// secondlife:///app/region/Ahern/128/128/0 /// -class LLUrlEntryRegion : public LLUrlEntryBase +class LLUrlEntryRegion final : public LLUrlEntryBase { public: LLUrlEntryRegion(); @@ -438,7 +452,7 @@ public: /// LLUrlEntryTeleport Describes a Second Life teleport Url, e.g., /// secondlife:///app/teleport/Ahern/50/50/50/ /// -class LLUrlEntryTeleport : public LLUrlEntryBase +class LLUrlEntryTeleport final : public LLUrlEntryBase { public: LLUrlEntryTeleport(); @@ -450,7 +464,7 @@ public: /// LLUrlEntrySL Describes a generic SLURL, e.g., a Url that starts /// with secondlife:// (used as a catch-all for cases not matched above) /// -class LLUrlEntrySL : public LLUrlEntryBase +class LLUrlEntrySL final : public LLUrlEntryBase { public: LLUrlEntrySL(); @@ -461,7 +475,7 @@ public: /// LLUrlEntrySLLabel Describes a generic SLURL, e.g., a Url that starts /// with secondlife:// with the ability to specify a custom label. /// -class LLUrlEntrySLLabel : public LLUrlEntryBase +class LLUrlEntrySLLabel final : public LLUrlEntryBase { public: LLUrlEntrySLLabel(); @@ -475,7 +489,7 @@ public: /// LLUrlEntryWorldMap Describes a Second Life worldmap Url, e.g., /// secondlife:///app/worldmap/Ahern/50/50/50 /// -class LLUrlEntryWorldMap : public LLUrlEntryBase +class LLUrlEntryWorldMap final : public LLUrlEntryBase { public: LLUrlEntryWorldMap(); @@ -486,7 +500,7 @@ public: /// /// LLUrlEntryNoLink lets us turn of URL detection with ... tags /// -class LLUrlEntryNoLink : public LLUrlEntryBase +class LLUrlEntryNoLink final : public LLUrlEntryBase { public: LLUrlEntryNoLink(); @@ -498,7 +512,7 @@ public: /// /// LLUrlEntryIcon describes an icon with ... tags /// -class LLUrlEntryIcon : public LLUrlEntryBase +class LLUrlEntryIcon final : public LLUrlEntryBase { public: LLUrlEntryIcon(); @@ -510,7 +524,7 @@ public: /// /// LLUrlEntryEmail Describes a generic mailto: Urls /// -class LLUrlEntryEmail : public LLUrlEntryBase +class LLUrlEntryEmail final : public LLUrlEntryBase { public: LLUrlEntryEmail(); @@ -522,7 +536,7 @@ public: /// /// LLUrlEntryJira describes a Jira Issue /// -class LLUrlEntryJira : public LLUrlEntryBase +class LLUrlEntryJira final : public LLUrlEntryBase { public: LLUrlEntryJira(); diff --git a/indra/llui/llurlmatch.cpp b/indra/llui/llurlmatch.cpp index 717db6280..240e04ef0 100644 --- a/indra/llui/llurlmatch.cpp +++ b/indra/llui/llurlmatch.cpp @@ -58,7 +58,7 @@ void LLUrlMatch::setValues(U32 start, U32 end, const std::string &url, const std mTooltip = tooltip; mIcon = icon; mStyle = style; - mStyle->setLinkHREF(url); + mStyle->setLinkHREF(mStyle->isLink() ? LLStringUtil::null : url); // Singu Note: This hack exists in lieu of no link flag mMenuName = menu; mLocation = location; mID = id; diff --git a/indra/llui/llurlregistry.cpp b/indra/llui/llurlregistry.cpp index 908531b0b..c7dba05e4 100644 --- a/indra/llui/llurlregistry.cpp +++ b/indra/llui/llurlregistry.cpp @@ -73,6 +73,7 @@ LLUrlRegistry::LLUrlRegistry() registerUrl(new LLUrlEntryObjectIM()); registerUrl(new LLUrlEntryPlace()); registerUrl(new LLUrlEntryInventory()); + registerUrl(new LLUrlEntryExperienceProfile()); //LLUrlEntrySL and LLUrlEntrySLLabel have more common pattern, //so it should be registered in the end of list registerUrl(new LLUrlEntrySL()); diff --git a/indra/lscript/lscript_byteformat.h b/indra/lscript/lscript_byteformat.h index 49e78e717..679714e59 100644 --- a/indra/lscript/lscript_byteformat.h +++ b/indra/lscript/lscript_byteformat.h @@ -355,6 +355,10 @@ typedef enum e_lscript_state_event_type LSTT_REMOTE_DATA, LSTT_HTTP_RESPONSE, LSTT_HTTP_REQUEST, + LSTT_EXPERMISSIONS, + LSTT_TRANSACTION_RESULT, + LSTT_PATH_UPDATE, + LSTT_EXPERMISSIONS_DENIED, LSTT_EOF, LSTT_STATE_BEGIN = LSTT_STATE_ENTRY, @@ -397,7 +401,11 @@ const U64 LSCRIPTStateBitField[LSTT_EOF] = 0x0000000040000000, // LSTT_OBJECT_REZ 0x0000000080000000, // LSTT_REMOTE_DATA 0x0000000100000000LL, // LSTT_HTTP_RESPOSE - 0x0000000200000000LL // LSTT_HTTP_REQUEST + 0x0000000200000000LL, // LSTT_HTTP_REQUEST + 0x0000000400000000LL, // LSTT_EXPERMISSIONS + 0x0000000800000000LL, // LSTT_TRANSACTION_RESULT + 0x0000001000000000LL, // LSTT_PATH_UPDATE + 0x0000002000000000LL, //LSTT_EXPERMISSIONS_DENIED }; inline S32 get_event_handler_jump_position(U64 bit_field, LSCRIPTStateEventType type) @@ -511,6 +519,7 @@ typedef enum e_lscript_runtime_faults LSRF_TOO_MANY_LISTENS, LSRF_NESTING_LISTS, LSRF_CLI, + LSRF_INVALID_STATE, LSRF_EOF } LSCRIPTRunTimeFaults; @@ -551,10 +560,10 @@ const U32 LSCRIPTRunTimePermissionBits[SCRIPT_PERMISSION_EOF] = (0x1 << 10),// SCRIPT_PERMISSION_TRACK_CAMERA (0x1 << 11),// SCRIPT_PERMISSION_CONTROL_CAMERA (0x1 << 12),// SCRIPT_PERMISSION_TELEPORT - (0x1 << 13),// SCRIPT_PERMISSION_EXPERIENCE, - (0x1 << 14),// SCRIPT_PERMISSION_SILENT_ESTATE_MANAGEMENT, - (0x1 << 15),// SCRIPT_PERMISSION_OVERRIDE_ANIMATIONS, - (0x1 << 16),// SCRIPT_PERMISSION_RETURN_OBJECTS, + (0x1 << 13),// SCRIPT_PERMISSION_EXPERIENCE + (0x1 << 14),// SCRIPT_PERMISSION_SILENT_ESTATE_MANAGEMENT + (0x1 << 15),// SCRIPT_PERMISSION_OVERRIDE_ANIMATIONS + (0x1 << 16),// SCRIPT_PERMISSION_RETURN_OBJECTS }; // http_request string constants diff --git a/indra/lscript/lscript_compile/indra.l b/indra/lscript/lscript_compile/indra.l index f7e592afb..3fb834d17 100644 --- a/indra/lscript/lscript_compile/indra.l +++ b/indra/lscript/lscript_compile/indra.l @@ -685,6 +685,23 @@ void parse_string(); "STATUS_INTERNAL_ERROR" { count(); yylval.ival = LSL_STATUS_INTERNAL_ERROR; return(INTEGER_CONSTANT); } "STATUS_WHITELIST_FAILED" { count(); yylval.ival = LSL_STATUS_WHITELIST_FAILED; return(INTEGER_CONSTANT); } +"XP_ERROR_NONE" { const char* sval= "no error"; yylval.sval = new char[strlen(sval)+1]; strcpy(yylval.sval, sval); return(STRING_CONSTANT); } +"XP_ERROR_THROTTLED" { const char* sval= "exceeded throttle"; yylval.sval = new char[strlen(sval)+1]; strcpy(yylval.sval, sval); return(STRING_CONSTANT); } +"XP_ERROR_EXPERIENCES_DISABLED" { const char* sval= "experiences are disabled"; yylval.sval = new char[strlen(sval)+1]; strcpy(yylval.sval, sval); return(STRING_CONSTANT); } +"XP_ERROR_INVALID_PARAMETERS" { const char* sval= "invalid parameters"; yylval.sval = new char[strlen(sval)+1]; strcpy(yylval.sval, sval); return(STRING_CONSTANT); } +"XP_ERROR_NOT_PERMITTED" { const char* sval= "operation not permitted"; yylval.sval = new char[strlen(sval)+1]; strcpy(yylval.sval, sval); return(STRING_CONSTANT); } +"XP_ERROR_NO_EXPERIENCE" { const char* sval= "script not associated with an experience";yylval.sval = new char[strlen(sval)+1]; strcpy(yylval.sval, sval); return(STRING_CONSTANT); } +"XP_ERROR_NOT_FOUND" { const char* sval= "not found"; yylval.sval = new char[strlen(sval)+1]; strcpy(yylval.sval, sval); return(STRING_CONSTANT); } +"XP_ERROR_INVALID_EXPERIENCE" { const char* sval= "invalid experience"; yylval.sval = new char[strlen(sval)+1]; strcpy(yylval.sval, sval); return(STRING_CONSTANT); } +"XP_ERROR_EXPERIENCE_DISABLED" { const char* sval= "experience is disabled"; yylval.sval = new char[strlen(sval)+1]; strcpy(yylval.sval, sval); return(STRING_CONSTANT); } +"XP_ERROR_EXPERIENCE_SUSPENDED" { const char* sval= "experience is suspended"; yylval.sval = new char[strlen(sval)+1]; strcpy(yylval.sval, sval); return(STRING_CONSTANT); } +"XP_ERROR_UNKNOWN_ERROR" { const char* sval= "unknown error"; yylval.sval = new char[strlen(sval)+1]; strcpy(yylval.sval, sval); return(STRING_CONSTANT); } +"XP_ERROR_QUOTA_EXCEEDED" { const char* sval= "experience data quota exceeded"; yylval.sval = new char[strlen(sval)+1]; strcpy(yylval.sval, sval); return(STRING_CONSTANT); } +"XP_ERROR_STORE_DISABLED" { const char* sval= "key-value store is disabled"; yylval.sval = new char[strlen(sval)+1]; strcpy(yylval.sval, sval); return(STRING_CONSTANT); } +"XP_ERROR_STORAGE_EXCEPTION" { const char* sval= "key-value store communication failed"; yylval.sval = new char[strlen(sval)+1]; strcpy(yylval.sval, sval); return(STRING_CONSTANT); } +"XP_ERROR_KEY_NOT_FOUND" { const char* sval= "key doesn't exist"; yylval.sval = new char[strlen(sval)+1]; strcpy(yylval.sval, sval); return(STRING_CONSTANT); } +"XP_ERROR_RETRY_UPDATE" { const char* sval= "retry update"; yylval.sval = new char[strlen(sval)+1]; strcpy(yylval.sval, sval); return(STRING_CONSTANT); } + "PROFILE_SCRIPT_NONE" { count(); yylval.ival = LSL_PROFILE_SCRIPT_NONE; return(INTEGER_CONSTANT); } "PROFILE_SCRIPT_MEMORY" { count(); yylval.ival = LSL_PROFILE_SCRIPT_MEMORY; return(INTEGER_CONSTANT); } diff --git a/indra/lscript/lscript_compile/indra.y b/indra/lscript/lscript_compile/indra.y index febf5f675..3e4b6c6ce 100644 --- a/indra/lscript/lscript_compile/indra.y +++ b/indra/lscript/lscript_compile/indra.y @@ -179,6 +179,8 @@ %type money %type email %type run_time_permissions +%type experience_permissions +%type experience_permissions_denied %type inventory %type attach %type dataserver @@ -787,6 +789,16 @@ event $$ = new LLScriptEventHandler(gLine, gColumn, $1, $2); gAllocationManager->addAllocation($$); } + | experience_permissions compound_statement + { + $$ = new LLScriptEventHandler(gLine, gColumn, $1, $2); + gAllocationManager->addAllocation($$); + } + | experience_permissions_denied compound_statement + { + $$ = new LLScriptEventHandler(gLine, gColumn, $1, $2); + gAllocationManager->addAllocation($$); + } | inventory compound_statement { $$ = new LLScriptEventHandler(gLine, gColumn, $1, $2); @@ -1039,6 +1051,28 @@ run_time_permissions } ; +experience_permissions + : EXPERIENCE_PERMISSIONS '(' LLKEY IDENTIFIER ')' + { + LLScriptIdentifier *id1 = new LLScriptIdentifier(gLine, gColumn, $4); + gAllocationManager->addAllocation(id1); + $$ = new LLScriptEXPEvent(gLine, gColumn, id1); + gAllocationManager->addAllocation($$); + } + ; + +experience_permissions_denied + : EXPERIENCE_PERMISSIONS_DENIED '(' LLKEY IDENTIFIER ',' INTEGER IDENTIFIER ')' + { + LLScriptIdentifier *id1 = new LLScriptIdentifier(gLine, gColumn, $4); + gAllocationManager->addAllocation(id1); + LLScriptIdentifier *id2 = new LLScriptIdentifier(gLine, gColumn, $7); + gAllocationManager->addAllocation(id2); + $$ = new LLScriptEXPDeniedEvent(gLine, gColumn, id1, id2); + gAllocationManager->addAllocation($$); + } + ; + inventory : INVENTORY '(' INTEGER IDENTIFIER ')' { diff --git a/indra/lscript/lscript_compile/lscript_tree.cpp b/indra/lscript/lscript_compile/lscript_tree.cpp index b737bff75..e5e7bb3d0 100644 --- a/indra/lscript/lscript_compile/lscript_tree.cpp +++ b/indra/lscript/lscript_compile/lscript_tree.cpp @@ -3712,6 +3712,155 @@ S32 LLScriptNoSensorEvent::getSize() return 0; } +void LLScriptEXPEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePass pass, LSCRIPTPruneType ptype, BOOL &prunearg, LLScriptScope *scope, LSCRIPTType &type, LSCRIPTType basetype, U64 &count, LLScriptByteCodeChunk *chunk, LLScriptByteCodeChunk *heap, S32 stacksize, LLScriptScopeEntry *entry, S32 entrycount, LLScriptLibData **ldata) +{ + if (gErrorToText.getErrors()) + { + return; + } + switch(pass) + { + case LSCP_PRETTY_PRINT: + case LSCP_EMIT_ASSEMBLY: + fdotabs(fp, tabs, tabsize); + fprintf(fp, "experience_permissions( key "); + mName->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, " )\n"); + break; + case LSCP_SCOPE_PASS1: + checkForDuplicateHandler(fp, this, scope, "experience_permissions"); + if (scope->checkEntry(mName->mName)) + { + gErrorToText.writeError(fp, this, LSERROR_DUPLICATE_NAME); + } + else + { + mName->mScopeEntry = scope->addEntry(mName->mName, LIT_VARIABLE, LST_KEY); + } + break; + case LSCP_RESOURCE: + { + // we're just tryng to determine how much space the variable needs + if (mName->mScopeEntry) + { + mName->mScopeEntry->mOffset = (S32)count; + mName->mScopeEntry->mSize = 4; + count += mName->mScopeEntry->mSize; + } + } + break; + + case LSCP_EMIT_BYTE_CODE: + { +#ifdef LSL_INCLUDE_DEBUG_INFO + char name[] = "experience_permissions"; + chunk->addBytes(name, strlen(name) + 1); + chunk->addBytes(mName->mName, strlen(mName->mName) + 1); +#endif + } + break; + case LSCP_EMIT_CIL_ASSEMBLY: + fdotabs(fp, tabs, tabsize); + fprintf(fp, "experience_permissions( valuetype [ScriptTypes]LindenLab.SecondLife.Key "); + mName->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, " )"); + break; + default: + mName->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + break; + } +} + +S32 LLScriptEXPEvent::getSize() +{ + // key = 4 + return 4; +} + + +void LLScriptEXPDeniedEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePass pass, LSCRIPTPruneType ptype, BOOL &prunearg, LLScriptScope *scope, LSCRIPTType &type, LSCRIPTType basetype, U64 &count, LLScriptByteCodeChunk *chunk, LLScriptByteCodeChunk *heap, S32 stacksize, LLScriptScopeEntry *entry, S32 entrycount, LLScriptLibData **ldata) +{ + if (gErrorToText.getErrors()) + { + return; + } + switch(pass) + { + case LSCP_PRETTY_PRINT: + case LSCP_EMIT_ASSEMBLY: + fdotabs(fp, tabs, tabsize); + fprintf(fp, "experience_permissions_denied( key "); + mName->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, ", integer "); + mReason->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, " )\n"); + break; + case LSCP_SCOPE_PASS1: + checkForDuplicateHandler(fp, this, scope, "experience_permissions_denied"); + if (scope->checkEntry(mName->mName)) + { + gErrorToText.writeError(fp, this, LSERROR_DUPLICATE_NAME); + } + else + { + mName->mScopeEntry = scope->addEntry(mName->mName, LIT_VARIABLE, LST_KEY); + } + if (scope->checkEntry(mReason->mName)) + { + gErrorToText.writeError(fp, this, LSERROR_DUPLICATE_NAME); + } + else + { + mReason->mScopeEntry = scope->addEntry(mReason->mName, LIT_VARIABLE, LST_INTEGER); + } + break; + case LSCP_RESOURCE: + { + // we're just trying to determine how much space the variable needs + if (mName->mScopeEntry) + { + mName->mScopeEntry->mOffset = (S32)count; + mName->mScopeEntry->mSize = 4; + count += mName->mScopeEntry->mSize; + + mReason->mScopeEntry->mOffset = (S32)count; + mReason->mScopeEntry->mSize = 4; + count += mReason->mScopeEntry->mSize; + } + } + break; + + case LSCP_EMIT_BYTE_CODE: + { +#ifdef LSL_INCLUDE_DEBUG_INFO + char name[] = "experience_permissions_denied"; + chunk->addBytes(name, strlen(name) + 1); + chunk->addBytes(mName->mName, strlen(mName->mName) + 1); + chunk->addBytes(mReason->mName, strlen(mReason->mName) + 1); +#endif + } + break; + case LSCP_EMIT_CIL_ASSEMBLY: + fdotabs(fp, tabs, tabsize); + fprintf(fp, "experience_permissions_denied( valuetype [ScriptTypes]LindenLab.SecondLife.Key "); + mName->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, ", int32 "); + mReason->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, " )"); + break; + default: + mName->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + mReason->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + break; + } +} + +S32 LLScriptEXPDeniedEvent::getSize() +{ + // key = 4 + integer + return LSCRIPTDataSize[LST_KEY]+LSCRIPTDataSize[LST_INTEGER]; +} + void LLScriptAtTarget::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePass pass, LSCRIPTPruneType ptype, BOOL &prunearg, LLScriptScope *scope, LSCRIPTType &type, LSCRIPTType basetype, U64 &count, LLScriptByteCodeChunk *chunk, LLScriptByteCodeChunk *heap, S32 stacksize, LLScriptScopeEntry *entry, S32 entrycount, LLScriptLibData **ldata) { if (gErrorToText.getErrors()) @@ -8577,6 +8726,7 @@ void LLScriptReturn::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePa } } prunearg = TRUE; + break; case LSCP_TYPE: // if there is a return expression, it must be promotable to the return type of the function if (mExpression) @@ -9775,7 +9925,13 @@ void LLScriptEventHandler::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCom mScopeEntry->mFunctionArgs.addType(LST_STRING); mScopeEntry->mFunctionArgs.addType(LST_STRING); break; - + case LSTT_EXPERMISSIONS: + mScopeEntry->mFunctionArgs.addType(LST_KEY); + break; + case LSTT_EXPERMISSIONS_DENIED: + mScopeEntry->mFunctionArgs.addType(LST_KEY); + mScopeEntry->mFunctionArgs.addType(LST_INTEGER); + break; default: break; } diff --git a/indra/lscript/lscript_compile/lscript_tree.h b/indra/lscript/lscript_compile/lscript_tree.h index 8131003c3..c7be5396a 100644 --- a/indra/lscript/lscript_compile/lscript_tree.h +++ b/indra/lscript/lscript_compile/lscript_tree.h @@ -633,6 +633,39 @@ public: LLScriptIdentifier *mRTPermissions; }; +class LLScriptEXPEvent : public LLScriptEvent +{ +public: + LLScriptEXPEvent(S32 line, S32 col, LLScriptIdentifier *name) + : LLScriptEvent(line, col, LSTT_EXPERMISSIONS), mName(name) + { + } + + ~LLScriptEXPEvent() {} + + void recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePass pass, LSCRIPTPruneType ptype, BOOL &prunearg, LLScriptScope *scope, LSCRIPTType &type, LSCRIPTType basetype, U64 &count, LLScriptByteCodeChunk *chunk, LLScriptByteCodeChunk *heap, S32 stacksize, LLScriptScopeEntry *entry, S32 entrycount, LLScriptLibData **ldata); + S32 getSize(); + + LLScriptIdentifier *mName; +}; + +class LLScriptEXPDeniedEvent : public LLScriptEvent +{ +public: + LLScriptEXPDeniedEvent(S32 line, S32 col, LLScriptIdentifier *name, LLScriptIdentifier *reason) + : LLScriptEvent(line, col, LSTT_EXPERMISSIONS_DENIED), mName(name), mReason(reason) + { + } + + ~LLScriptEXPDeniedEvent() {} + + void recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePass pass, LSCRIPTPruneType ptype, BOOL &prunearg, LLScriptScope *scope, LSCRIPTType &type, LSCRIPTType basetype, U64 &count, LLScriptByteCodeChunk *chunk, LLScriptByteCodeChunk *heap, S32 stacksize, LLScriptScopeEntry *entry, S32 entrycount, LLScriptLibData **ldata); + S32 getSize(); + + LLScriptIdentifier *mName; + LLScriptIdentifier *mReason; +}; + class LLScriptChatEvent : public LLScriptEvent { public: diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 57ad1b0b2..550d2d11d 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -51,9 +51,9 @@ include(ZLIB) include(URIPARSER) -if(FMODSTUDIO) +if(USE_FMODSTUDIO) include_directories(${FMODSTUDIO_INCLUDE_DIR}) -endif(FMODSTUDIO) +endif(USE_FMODSTUDIO) if(USE_CRASHPAD) include_directories(${CRASHPAD_INCLUDE_DIRS}) @@ -181,6 +181,7 @@ set(viewer_SOURCE_FILES lleventinfo.cpp lleventnotifier.cpp lleventpoll.cpp + llexperiencelog.cpp llexternaleditor.cpp llface.cpp llfasttimerview.cpp @@ -221,6 +222,9 @@ set(viewer_SOURCE_FILES llfloatereditui.cpp llfloaterenvsettings.cpp llfloaterevent.cpp + llfloaterexperiencepicker.cpp + llfloaterexperienceprofile.cpp + llfloaterexperiences.cpp llfloaterexploreanimations.cpp llfloaterexploresounds.cpp llfloaterfeed.cpp @@ -320,6 +324,7 @@ set(viewer_SOURCE_FILES llhudtext.cpp llhudview.cpp llimpanel.cpp + llimprocessing.cpp llimview.cpp llinventoryactions.cpp llinventorybridge.cpp @@ -382,11 +387,16 @@ set(viewer_SOURCE_FILES llpaneldisplay.cpp llpaneleditwearable.cpp llpanelevent.cpp + llpanelexperiencelisteditor.cpp + llpanelexperiencelog.cpp + llpanelexperiencepicker.cpp + llpanelexperiences.cpp llpanelface.cpp llpanelgeneral.cpp llpanelgroup.cpp llpanelgroupbulk.cpp llpanelgroupbulkban.cpp + llpanelgroupexperiences.cpp llpanelgroupgeneral.cpp llpanelgroupinvite.cpp llpanelgrouplandmoney.cpp @@ -617,9 +627,6 @@ set(viewer_SOURCE_FILES wlfPanel_AdvSettings.cpp ) -set(VIEWER_BINARY_NAME "singularity-bin" CACHE STRING - "The name of the viewer executable to create.") - set(viewer_HEADER_FILES CMakeLists.txt ViewerInstall.cmake @@ -718,6 +725,7 @@ set(viewer_HEADER_FILES lleventinfo.h lleventnotifier.h lleventpoll.h + llexperiencelog.h llexternaleditor.h llface.h llfasttimerview.h @@ -758,6 +766,9 @@ set(viewer_HEADER_FILES llfloatereditui.h llfloaterenvsettings.h llfloaterevent.h + llfloaterexperiencepicker.h + llfloaterexperienceprofile.h + llfloaterexperiences.h llfloaterexploreanimations.h llfloaterexploresounds.h llfloaterfeed.h @@ -857,6 +868,7 @@ set(viewer_HEADER_FILES llhudtext.h llhudview.h llimpanel.h + llimprocessing.h llimview.h llinventorybridge.h llinventoryclipboard.h @@ -919,12 +931,17 @@ set(viewer_HEADER_FILES llpaneldisplay.h llpaneleditwearable.h llpanelevent.h + llpanelexperiencelisteditor.h + llpanelexperiencelog.h + llpanelexperiencepicker.h + llpanelexperiences.h llpanelface.h llpanelgeneral.h llpanelgroup.h llpanelgroupbulk.h llpanelgroupbulkban.h llpanelgroupbulkimpl.h + llpanelgroupexperiences.h llpanelgroupgeneral.h llpanelgroupinvite.h llpanelgrouplandmoney.h @@ -1165,12 +1182,12 @@ set(viewer_HEADER_FILES source_group("CMake Rules" FILES ViewerInstall.cmake) +#build_data.json creation moved to viewer_manifest.py MAINT-6413 # the viewer_version.txt file created here is for passing to viewer_manifest and autobuild # the summary.json file is created for the benefit of the TeamCity builds, where # it is used to provide descriptive information to the build results page add_custom_target(generate_viewer_version ALL COMMAND ${CMAKE_COMMAND} -E echo ${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION} > ${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt - COMMAND ${CMAKE_COMMAND} -E echo {"Type":"viewer","Version":"${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION}"} > ${CMAKE_BINARY_DIR}/summary.json COMMENT "Generating viewer_version.txt for manifest processing" ) @@ -1239,11 +1256,11 @@ if (WINDOWS) llwindebug.h ) - if (NVAPI) + if (USE_NVAPI) set(APPVWRW32_COMPILE_FLAGS "${APPVWRW32_COMPILE_FLAGS} -DUSE_NVAPI=1") - else (NVAPI) + else (USE_NVAPI) set(APPVWRW32_COMPILE_FLAGS "${APPVWRW32_COMPILE_FLAGS} -UUSE_NVAPI") - endif (NVAPI) + endif (USE_NVAPI) set_source_files_properties(llappviewerwin32.cpp PROPERTIES COMPILE_FLAGS "${APPVWRW32_COMPILE_FLAGS}") # Replace the icons with the appropriate ones for the channel @@ -1434,9 +1451,10 @@ if (OPENAL) list(APPEND LLSTARTUP_COMPILE_DEFINITIONS "LL_OPENAL=1") endif (OPENAL) -if (FMODSTUDIO) +if (USE_FMODSTUDIO) list(APPEND LLSTARTUP_COMPILE_DEFINITIONS "LL_FMODSTUDIO=1") -endif (FMODSTUDIO) + set_source_files_properties(llpanellogin.cpp PROPERTIES COMPILE_DEFINITIONS "LL_FMODSTUDIO=1") +endif (USE_FMODSTUDIO) set_source_files_properties(llstartup.cpp PROPERTIES COMPILE_DEFINITIONS "${LLSTARTUP_COMPILE_DEFINITIONS}") @@ -1463,8 +1481,7 @@ if(USE_PRECOMPILED_HEADERS) ${CMAKE_CURRENT_SOURCE_DIR}/llviewerprecompiledheaders.cpp) endif(USE_PRECOMPILED_HEADERS) -set(PACKAGE OFF CACHE BOOL - "Add a package target that builds an installer package.") +option(PACKAGE "Add a package target that builds an installer package." ON) if (WINDOWS) set(release_flags "/MAP") @@ -1535,20 +1552,20 @@ if (WINDOWS) ) endif (ADDRESS_SIZE EQUAL 64) - if (FMODSTUDIO) - if (WORD_SIZE EQUAL 64) + if (USE_FMODSTUDIO) + if (ADDRESS_SIZE EQUAL 64) list(APPEND COPY_INPUT_DEPENDENCIES ${SHARED_LIB_STAGING_DIR}/Release/fmod64.dll ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/fmod64.dll ${SHARED_LIB_STAGING_DIR}/Debug/fmodL64.dll ) - else (WORD_SIZE EQUAL 64) + else (ADDRESS_SIZE EQUAL 64) list(APPEND COPY_INPUT_DEPENDENCIES ${SHARED_LIB_STAGING_DIR}/Release/fmod.dll ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/fmod.dll ) - endif (WORD_SIZE EQUAL 64) - endif (FMODSTUDIO) + endif (ADDRESS_SIZE EQUAL 64) + endif (USE_FMODSTUDIO) if(MSVC_IDE) set(VIEWER_BUILD_DEST_DIR "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}") @@ -1567,7 +1584,7 @@ if (WINDOWS) --branding_id=${VIEWER_BRANDING_ID} --build=${CMAKE_CURRENT_BINARY_DIR} --buildtype=${CMAKE_BUILD_TYPE} - --configuration=${VIEWER_BUILD_DEST_DIR} + --configuration=${VIEWER_BUILD_DEST_DIR} --dest=${VIEWER_BUILD_DEST_DIR} --grid=${GRID} --channel=${VIEWER_CHANNEL} @@ -1611,7 +1628,7 @@ if (WINDOWS) --buildtype=${CMAKE_BUILD_TYPE} --channel=${VIEWER_CHANNEL} --versionfile=${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt - --configuration=${VIEWER_BUILD_DEST_DIR} + --configuration=${VIEWER_BUILD_DEST_DIR} --dest=${VIEWER_BUILD_DEST_DIR} --grid=${GRID} --source=${CMAKE_CURRENT_SOURCE_DIR} @@ -1806,7 +1823,7 @@ if (DARWIN) ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py ) - add_dependencies(${VIEWER_BINARY_NAME} SLPlugin media_plugin_libvlc media_plugin_webkit basic_plugin_filepicker) + add_dependencies(${VIEWER_BINARY_NAME} SLPlugin media_plugin_libvlc media_plugin_cef basic_plugin_filepicker) if (PACKAGE) add_custom_target(llpackage ALL DEPENDS ${VIEWER_BINARY_NAME}) @@ -1840,7 +1857,7 @@ if (INSTALL) include(${CMAKE_CURRENT_SOURCE_DIR}/ViewerInstall.cmake) endif (INSTALL) -if (PACKAGE AND USE_CRASHPAD) +if (FALSE) # Breakpad symbol-file generation set(SYMBOL_NAME ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${VIEWER_CHANNEL_NOSPACE}-${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION}-symbols) @@ -1868,7 +1885,7 @@ if (PACKAGE AND USE_CRASHPAD) if (LINUX) list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_CURRENT_BINARY_DIR}/packaged") set(VIEWER_SYMBOL_FILE "${SYMBOL_NAME}-${AUTOBUILD_PLATFORM_NAME}.tar.bz2") - set(VIEWER_EXE_GLOBS "${VIEWER_BRANDING_ID}-do-not-run-directly SLPlugin") + set(VIEWER_EXE_GLOBS "do-not-directly-run-${VIEWER_BINARY_NAME} SLPlugin") set(VIEWER_LIB_GLOB "*${CMAKE_SHARED_MODULE_SUFFIX}*") set(VIEWER_COPY_MANIFEST copy_l_viewer_manifest) endif (LINUX) diff --git a/indra/newview/NACLantispam.cpp b/indra/newview/NACLantispam.cpp index dfeb7a5c9..584f9e319 100644 --- a/indra/newview/NACLantispam.cpp +++ b/indra/newview/NACLantispam.cpp @@ -14,457 +14,300 @@ */ #include "llviewerprecompiledheaders.h" + #include "NACLantispam.h" -#include "llviewercontrol.h" -#include "llnotificationsutil.h" -#include "llviewerobjectlist.h" #include "llagent.h" +#include "llavataractions.h" +#include "llcallbacklist.h" // For idle cleaning +#include "llnotificationsutil.h" #include "lltrans.h" +#include "llviewerobjectlist.h" + #include #include +class NACLAntiSpamQueue +{ + friend class NACLAntiSpamRegistry; +public: + const U32& getAmount() const { return mAmount; } + const U32& getTime() const { return mTime; } +protected: + NACLAntiSpamQueue(const U32& time, const U32& amount) : mTime(time), mAmount(amount) {} + void setAmount(const U32& amount) { mAmount = amount; } + void setTime(const U32& time) { mTime = time; } + void block(const LLUUID& source) { mEntries[source.asString()].block(); } + void reset() { mEntries.clear(); } + // Returns 0 if unblocked/disabled, 1 if check results in a new block, 2 if by an existing block + U8 check(const LLUUID& source, const U32& multiplier) + { + const auto key = source.asString(); + auto it = mEntries.find(key); + if (it != mEntries.end()) + return it->second.blockIfNeeded(mAmount * multiplier, mTime); + mEntries[key]; // Default construct an Entry + return 0U; + } + void idle() + { + // Clean out old unblocked entries + const auto time_limit = mTime + 1; // One second after time has gone up, the next offense would reset anyway + for (auto it = mEntries.begin(); it != mEntries.end();) + { + const auto& entry = it->second; + if (entry.getBlocked() || entry.withinBlockTime(time_limit)) + ++it; + else it = mEntries.erase(it); + } + } + +private: + class Entry + { + friend class NACLAntiSpamQueue; + protected: + void reset() { updateTime(); mAmount = 1; mBlocked = false; } + const U32& getAmount() const { return mAmount; } + const std::time_t& getTime() const { return mTime; } + void updateTime() { mTime = time(nullptr); } + void block() { mBlocked = true; } + bool withinBlockTime(const U32& time_limit) const { return (time(nullptr) - mTime) <= time_limit; } + U8 blockIfNeeded(const U32& amount, const U32& time_limit) + { + if (mBlocked) return 2U; // Already blocked + if (withinBlockTime(time_limit)) + { + if (++mAmount > amount) + { + block(); + return 1U; + } + } + else reset(); // Enough time has passed to forgive or not already in list + return 0U; + } + bool getBlocked() const { return mBlocked; } + private: + U32 mAmount = 1; + std::time_t mTime = time(nullptr); + bool mBlocked = false; + }; + boost::unordered_map mEntries; + U32 mAmount, mTime; +}; + bool can_block(const LLUUID& id) { - if (id.isNull() || gAgent.getID() == id) return false; //Can't block system or self. - if (const LLViewerObject* obj = gObjectList.findObject(id)) //From an object, - return !obj->permYouOwner(); //not own object. + if (id.isNull() || gAgentID == id) return false; // Can't block system or self. + if (const LLViewerObject* obj = gObjectList.findObject(id)) // From an object, + return !obj->permYouOwner(); // not own object. return true; } -U32 NACLAntiSpamRegistry::globalAmount; -U32 NACLAntiSpamRegistry::globalTime; -bool NACLAntiSpamRegistry::bGlobalQueue; -NACLAntiSpamQueue* NACLAntiSpamRegistry::queues[NACLAntiSpamRegistry::QUEUE_MAX] = {0}; -boost::unordered_map NACLAntiSpamRegistry::globalEntries; -boost::unordered_map::iterator NACLAntiSpamRegistry::it2; +bool is_collision_sound(const std::string& sound) +{ + // The following sounds will be ignored for purposes of spam protection. They have been gathered from wiki documentation of frequent official sounds. + const std::array COLLISION_SOUNDS = { + "dce5fdd4-afe4-4ea1-822f-dd52cac46b08", + "51011582-fbca-4580-ae9e-1a5593f094ec", + "68d62208-e257-4d0c-bbe2-20c9ea9760bb", + "75872e8c-bc39-451b-9b0b-042d7ba36cba", + "6a45ba0b-5775-4ea8-8513-26008a17f873", + "992a6d1b-8c77-40e0-9495-4098ce539694", + "2de4da5a-faf8-46be-bac6-c4d74f1e5767", + "6e3fb0f7-6d9c-42ca-b86b-1122ff562d7d", + "14209133-4961-4acc-9649-53fc38ee1667", + "bc4a4348-cfcc-4e5e-908e-8a52a8915fe6", + "9e5c1297-6eed-40c0-825a-d9bcd86e3193", + "e534761c-1894-4b61-b20c-658a6fb68157", + "8761f73f-6cf9-4186-8aaa-0948ed002db1", + "874a26fd-142f-4173-8c5b-890cd846c74d", + "0e24a717-b97e-4b77-9c94-b59a5a88b2da", + "75cf3ade-9a5b-4c4d-bb35-f9799bda7fb2", + "153c8bf7-fb89-4d89-b263-47e58b1b4774", + "55c3e0ce-275a-46fa-82ff-e0465f5e8703", + "24babf58-7156-4841-9a3f-761bdbb8e237", + "aca261d8-e145-4610-9e20-9eff990f2c12", + "0642fba6-5dcf-4d62-8e7b-94dbb529d117", + "25a863e8-dc42-4e8a-a357-e76422ace9b5", + "9538f37c-456e-4047-81be-6435045608d4", + "8c0f84c3-9afd-4396-b5f5-9bca2c911c20", + "be582e5d-b123-41a2-a150-454c39e961c8", + "c70141d4-ba06-41ea-bcbc-35ea81cb8335", + "7d1826f4-24c4-4aac-8c2e-eff45df37783", + "063c97d3-033a-4e9b-98d8-05c8074922cb", + "00000000-0000-0000-0000-000000000120" + }; -// The following sounds will be ignored for purposes of spam protection. They have been gathered from wiki documentation of frequent official sounds. -const std::string COLLISION_SOUNDS[] ={"dce5fdd4-afe4-4ea1-822f-dd52cac46b08","51011582-fbca-4580-ae9e-1a5593f094ec","68d62208-e257-4d0c-bbe2-20c9ea9760bb","75872e8c-bc39-451b-9b0b-042d7ba36cba","6a45ba0b-5775-4ea8-8513-26008a17f873","992a6d1b-8c77-40e0-9495-4098ce539694","2de4da5a-faf8-46be-bac6-c4d74f1e5767","6e3fb0f7-6d9c-42ca-b86b-1122ff562d7d","14209133-4961-4acc-9649-53fc38ee1667","bc4a4348-cfcc-4e5e-908e-8a52a8915fe6","9e5c1297-6eed-40c0-825a-d9bcd86e3193","e534761c-1894-4b61-b20c-658a6fb68157","8761f73f-6cf9-4186-8aaa-0948ed002db1","874a26fd-142f-4173-8c5b-890cd846c74d","0e24a717-b97e-4b77-9c94-b59a5a88b2da","75cf3ade-9a5b-4c4d-bb35-f9799bda7fb2","153c8bf7-fb89-4d89-b263-47e58b1b4774","55c3e0ce-275a-46fa-82ff-e0465f5e8703","24babf58-7156-4841-9a3f-761bdbb8e237","aca261d8-e145-4610-9e20-9eff990f2c12","0642fba6-5dcf-4d62-8e7b-94dbb529d117","25a863e8-dc42-4e8a-a357-e76422ace9b5","9538f37c-456e-4047-81be-6435045608d4","8c0f84c3-9afd-4396-b5f5-9bca2c911c20","be582e5d-b123-41a2-a150-454c39e961c8","c70141d4-ba06-41ea-bcbc-35ea81cb8335","7d1826f4-24c4-4aac-8c2e-eff45df37783","063c97d3-033a-4e9b-98d8-05c8074922cb","00000000-0000-0000-0000-000000000120"}; -const int COLLISION_SOUNDS_SIZE=29; - -// NaClAntiSpamQueueEntry - -NACLAntiSpamQueueEntry::NACLAntiSpamQueueEntry() -{ - entryTime=0; - entryAmount=0; - blocked=false; + for (const auto& collision : COLLISION_SOUNDS) + if (collision == sound) + return true; + return false; } -void NACLAntiSpamQueueEntry::clearEntry() -{ - entryTime=0; - entryAmount=0; - blocked=false; -} -U32 NACLAntiSpamQueueEntry::getEntryAmount() const -{ - return entryAmount; -} -U32 NACLAntiSpamQueueEntry::getEntryTime() const -{ - return entryTime; -} -void NACLAntiSpamQueueEntry::updateEntryAmount() -{ - entryAmount++; -} -void NACLAntiSpamQueueEntry::updateEntryTime() -{ - entryTime=time(0); -} -void NACLAntiSpamQueueEntry::setBlocked() -{ - blocked=true; -} -bool NACLAntiSpamQueueEntry::getBlocked() const -{ - return blocked; -} - -// NaClAntiSpamQueue - -NACLAntiSpamQueue::NACLAntiSpamQueue(U32 time, U32 amount) -{ - queueTime=time; - queueAmount=amount; -} -void NACLAntiSpamQueue::setAmount(U32 amount) -{ - queueAmount=amount; -} -void NACLAntiSpamQueue::setTime(U32 time) -{ - queueTime=time; -} -U32 NACLAntiSpamQueue::getAmount() const -{ - return queueAmount; -} -U32 NACLAntiSpamQueue::getTime() const -{ - return queueTime; -} -void NACLAntiSpamQueue::clearEntries() -{ - for(it = entries.begin(); it != entries.end(); it++) - { - it->second->clearEntry(); - } -} -void NACLAntiSpamQueue::purgeEntries() -{ - for(it = entries.begin(); it != entries.end(); it++) - { - delete it->second; - } - entries.clear(); -} -void NACLAntiSpamQueue::blockEntry(LLUUID& source) -{ - it=entries.find(source.asString()); - if(it == entries.end()) - { - entries[source.asString()]=new NACLAntiSpamQueueEntry(); - } - entries[source.asString()]->setBlocked(); -} -int NACLAntiSpamQueue::checkEntry(LLUUID& name, U32 multiplier) -// Returns 0 if unblocked/disabled, 1 if check results in a new block, 2 if by an existing block -{ - static LLCachedControl enabled(gSavedSettings,"AntiSpamEnabled",false); - if(!enabled) return 0; - it=entries.find(name.asString()); - if(it != entries.end()) - { - if(it->second->getBlocked()) return 2; - U32 eTime=it->second->getEntryTime(); - U32 currentTime=time(0); - if((currentTime-eTime) <= queueTime) - { - it->second->updateEntryAmount(); - U32 eAmount=it->second->getEntryAmount(); - if(eAmount > (queueAmount*multiplier)) - { - it->second->setBlocked(); - return 1; - } - else - return 0; - } - else - { - it->second->clearEntry(); - it->second->updateEntryAmount(); - it->second->updateEntryTime(); - return 0; - } - } - else - { - //LL_DEBUGS() << "[antispam] New queue entry:" << name.asString() << LL_ENDL; - entries[name.asString()]=new NACLAntiSpamQueueEntry(); - entries[name.asString()]->updateEntryAmount(); - entries[name.asString()]->updateEntryTime(); - return 0; - } -} - // NaClAntiSpamRegistry -static const char* QUEUE_NAME[NACLAntiSpamRegistry::QUEUE_MAX] = { -"Chat", -"Inventory", -"Instant Message", -"calling card", -"sound", -"Sound Preload", -"Script Dialog", -"Teleport"}; +constexpr std::array QUEUE_NAME = { + "Chat", + "Inventory", + "Instant Message", + "calling card", + "sound", + "Sound Preload", + "Script Dialog", + "Teleport" +}; -NACLAntiSpamRegistry::NACLAntiSpamRegistry(U32 time, U32 amount) +NACLAntiSpamRegistry::NACLAntiSpamRegistry() { - globalTime=time; - globalAmount=amount; - static LLCachedControl _NACL_AntiSpamGlobalQueue(gSavedSettings,"_NACL_AntiSpamGlobalQueue"); - bGlobalQueue=_NACL_AntiSpamGlobalQueue; - for(int queue = 0; queue < QUEUE_MAX; ++queue) + auto control = gSavedSettings.getControl("_NACL_AntiSpamTime"); + const U32 time = control->get().asInteger(); + mConnections[0] = control->getSignal()->connect(boost::bind(&NACLAntiSpamRegistry::handleNaclAntiSpamTimeChanged, _2)); + + control = gSavedSettings.getControl("_NACL_AntiSpamAmount"); + const U32 amount = control->get().asInteger(); + mConnections[1] = control->getSignal()->connect(boost::bind(&NACLAntiSpamRegistry::handleNaclAntiSpamAmountChanged, _2)); + + control = gSavedSettings.getControl("_NACL_AntiSpamGlobalQueue"); + mConnections[2] = control->getSignal()->connect(boost::bind(&NACLAntiSpamRegistry::handleNaclAntiSpamGlobalQueueChanged, _2)); + initializeQueues(control->get(), time, amount); +} + +void NACLAntiSpamRegistry::initializeQueues(bool global, const U32& time, const U32& amount) +{ + if (global) // If Global, initialize global queue + mGlobalQueue.reset(new NACLAntiSpamQueue(time, amount)); + else { - queues[queue] = new NACLAntiSpamQueue(time,amount); + mQueues.reset(new std::array{{ + NACLAntiSpamQueue(time, amount), // QUEUE_CHAT + NACLAntiSpamQueue(time, amount), // QUEUE_INVENTORY + NACLAntiSpamQueue(time, amount), // QUEUE_IM + NACLAntiSpamQueue(time, amount), // QUEUE_CALLING_CARD + NACLAntiSpamQueue(time, amount), // QUEUE_SOUND + NACLAntiSpamQueue(time, amount), // QUEUE_SOUND_PRELOAD + NACLAntiSpamQueue(time, amount), // QUEUE_SCRIPT_DIALOG + NACLAntiSpamQueue(time, amount) // QUEUE_TELEPORT + }}); } } -//static -const char* NACLAntiSpamRegistry::getQueueName(U32 queue_id) + +constexpr const char* getQueueName(const NACLAntiSpamRegistry::Type& name) { - if(queue_id >= QUEUE_MAX) - return "Unknown"; - return QUEUE_NAME[queue_id]; + return name >= QUEUE_NAME.size() ? "Unknown" : QUEUE_NAME[name]; } -//static -void NACLAntiSpamRegistry::registerQueues(U32 time, U32 amount) -{ - globalTime=time; - globalAmount=amount; - static LLCachedControl _NACL_AntiSpamGlobalQueue(gSavedSettings,"_NACL_AntiSpamGlobalQueue"); - bGlobalQueue=_NACL_AntiSpamGlobalQueue; - for(int queue = 0; queue < QUEUE_MAX; ++queue) - { - queues[queue] = new NACLAntiSpamQueue(time,amount); - } -} -//static -/*void NACLAntiSpamRegistry::registerQueue(U32 name, U32 time, U32 amount) -{ - it=queues.find(name); - if(it == queues.end()) - { - queues[name]=new NACLAntiSpamQueue(time,amount); - } -}*/ -//static -void NACLAntiSpamRegistry::setRegisteredQueueTime(U32 name, U32 time) -{ - if(name >= QUEUE_MAX || queues[name] == 0) - { - LL_ERRS("AntiSpam") << "CODE BUG: Attempting to set time of antispam queue that was outside of the reasonable range of queues or not created. Queue: " << getQueueName(name) << LL_ENDL; - return; - } - - queues[name]->setTime(time); -} -//static -void NACLAntiSpamRegistry::setRegisteredQueueAmount(U32 name, U32 amount) -{ - if(name >= QUEUE_MAX || queues[name] == 0) - { - LL_ERRS("AntiSpam") << "CODE BUG: Attempting to set amount for antispam queue that was outside of the reasonable range of queues or not created. Queue: " << getQueueName(name) << LL_ENDL; - return; - } - - queues[name]->setAmount(amount); -} -//static + void NACLAntiSpamRegistry::setAllQueueTimes(U32 time) { - globalTime=time; - for(int queue = 0; queue < QUEUE_MAX; ++queue) - if( queues[queue] ) - queues[queue]->setTime(time); + if (mGlobalQueue) mGlobalQueue->setTime(time); + else for(auto& queue : *mQueues) queue.setTime(time); } -//static + void NACLAntiSpamRegistry::setAllQueueAmounts(U32 amount) { - globalAmount=amount; - for(int queue = 0; queue < QUEUE_MAX; ++queue) + if (mGlobalQueue) mGlobalQueue->setAmount(amount); + else for (U8 queue = 0U; queue < QUEUE_MAX; ++queue) { - if(!queues[queue]) continue; - if(queue == QUEUE_SOUND || queue == QUEUE_SOUND_PRELOAD) - queues[queue]->setAmount(amount*5); + auto& q = (*mQueues)[queue]; + if (queue == QUEUE_SOUND || queue == QUEUE_SOUND_PRELOAD) + q.setAmount(amount*5); else - queues[queue]->setAmount(amount); + q.setAmount(amount); } } -//static -void NACLAntiSpamRegistry::clearRegisteredQueue(U32 name) + +void NACLAntiSpamRegistry::blockOnQueue(const Type& name, const LLUUID& source) { - if(name >= QUEUE_MAX || queues[name] == 0) - { - LL_ERRS("AntiSpam") << "CODE BUG: Attempting to clear antispam queue that was outside of the reasonable range of queues or not created. Queue: " << getQueueName(name) << LL_ENDL; - return; - } - - queues[name]->clearEntries(); + if (name >= QUEUE_MAX) + LL_ERRS("AntiSpam") << "CODE BUG: Attempting to use a antispam queue that was outside of the reasonable range of queues. Queue: " << getQueueName(name) << LL_ENDL; + else (mGlobalQueue ? *mGlobalQueue : (*mQueues)[name]).block(source); } -//static -void NACLAntiSpamRegistry::purgeRegisteredQueue(U32 name) -{ - if(name >= QUEUE_MAX || queues[name] == 0) - { - LL_ERRS("AntiSpam") << "CODE BUG: Attempting to purge antispam queue that was outside of the reasonable range of queues or not created. Queue: " << getQueueName(name) << LL_ENDL; - return; - } - - queues[name]->purgeEntries(); -} -//static -void NACLAntiSpamRegistry::blockOnQueue(U32 name, LLUUID& source) -{ - if(bGlobalQueue) - { - NACLAntiSpamRegistry::blockGlobalEntry(source); - } - else - { - if(name >= QUEUE_MAX || queues[name] == 0) - { - LL_ERRS("AntiSpam") << "CODE BUG: Attempting to use a antispam queue that was outside of the reasonable range of queues or not created. Queue: " << getQueueName(name) << LL_ENDL; - return; - } - queues[name]->blockEntry(source); - } -} -//static -void NACLAntiSpamRegistry::blockGlobalEntry(LLUUID& source) -{ - it2=globalEntries.find(source.asString()); - if(it2 == globalEntries.end()) - { - globalEntries[source.asString()]=new NACLAntiSpamQueueEntry(); - } - globalEntries[source.asString()]->setBlocked(); -} -//static -bool NACLAntiSpamRegistry::checkQueue(U32 name, LLUUID& source, U32 multiplier) + +bool NACLAntiSpamRegistry::checkQueue(const Type& name, const LLUUID& source, const LFIDBearer::Type& type, const U32& multiplier) //returns true if blocked { + if (name >= QUEUE_MAX) + { + LL_ERRS("AntiSpam") << "CODE BUG: Attempting to check antispam queue that was outside of the reasonable range of queues. Queue: " << getQueueName(name) << LL_ENDL; + return false; + } + if (!can_block(source)) return false; - int result; - if(bGlobalQueue) + auto& queue = mGlobalQueue ? *mGlobalQueue : (*mQueues)[name]; + const auto result = queue.check(source, multiplier); + if (!result) return false; // Safe + + if (result != 2 // Not previously blocked + && gSavedSettings.getBOOL("AntiSpamNotify")) // and Just blocked! { - result=NACLAntiSpamRegistry::checkGlobalEntry(source,multiplier); - } - else - { - if(name >= QUEUE_MAX || queues[name] == 0) - { - LL_ERRS("AntiSpam") << "CODE BUG: Attempting to check antispam queue that was outside of the reasonable range of queues or not created. Queue: " << getQueueName(name) << LL_ENDL; - return false; - } - result=queues[name]->checkEntry(source,multiplier); - } - if(result == 0) //Safe - return false; - else if(result == 2) //Previously blocked - { - return true; - } - else //Just blocked! - { - if(gSavedSettings.getBOOL("AntiSpamNotify")) - { - LLSD args; - args["SOURCE"] = source.asString().c_str(); - args["TYPE"] = LLTrans::getString(getQueueName(name)); - args["AMOUNT"] = boost::lexical_cast(multiplier * queues[name]->getAmount()); - args["TIME"] = boost::lexical_cast(queues[name]->getTime()); - LLNotificationsUtil::add("AntiSpamBlock", args); - } - return true; + const std::string get_slurl_for(const LLUUID& id, const LFIDBearer::Type& type); + const auto slurl = get_slurl_for(source, type); + LLSD args; + args["SOURCE"] = slurl.empty() ? source.asString() : slurl; + args["TYPE"] = LLTrans::getString(getQueueName(name)); + args["AMOUNT"] = (LLSD::Integer)(multiplier * queue.getAmount()); + args["TIME"] = (LLSD::Integer)queue.getTime(); + LLNotificationsUtil::add("AntiSpamBlock", args); } + return true; } -// Global queue stoof -//static -void NACLAntiSpamRegistry::setGlobalQueue(bool value) +void NACLAntiSpamRegistry::idle() { - NACLAntiSpamRegistry::purgeAllQueues(); - bGlobalQueue=value; + if (mGlobalQueue) mGlobalQueue->idle(); + else for (auto& queue : *mQueues) queue.idle(); } -//static -void NACLAntiSpamRegistry::setGlobalAmount(U32 amount) + +void NACLAntiSpamRegistry::resetQueues() { - globalAmount=amount; + if (mGlobalQueue) mGlobalQueue->reset(); + else for (auto& queue : *mQueues) queue.reset(); + + LL_INFOS() << "AntiSpam Queues Reset" << LL_ENDL; } -//static -void NACLAntiSpamRegistry::setGlobalTime(U32 time) -{ - globalTime=time; -} -//static -void NACLAntiSpamRegistry::clearAllQueues() -{ - if(bGlobalQueue) - NACLAntiSpamRegistry::clearGlobalEntries(); - else - for(int queue = 0; queue < QUEUE_MAX; ++queue) - { - if(queues[queue]) queues[queue]->clearEntries(); - } -} -//static + void NACLAntiSpamRegistry::purgeAllQueues() { - if(bGlobalQueue) - NACLAntiSpamRegistry::purgeGlobalEntries(); + // Note: These resets are upon the unique_ptr, not the Queue itself! + if (mGlobalQueue) + mGlobalQueue.reset(); else - for(int queue = 0; queue < QUEUE_MAX; ++queue) - { - if(queues[queue]) queues[queue]->purgeEntries(); - } - LL_INFOS() << "AntiSpam Queues Purged" << LL_ENDL; -} -//static -int NACLAntiSpamRegistry::checkGlobalEntry(LLUUID& name, U32 multiplier) -{ - static LLCachedControl enabled(gSavedSettings,"AntiSpamEnabled",false); - if(!enabled) return 0; - it2=globalEntries.find(name.asString()); - if(it2 != globalEntries.end()) - { - if(it2->second->getBlocked()) return 2; - U32 eTime=it2->second->getEntryTime(); - U32 currentTime=time(0); - if((currentTime-eTime) <= globalTime) - { - it2->second->updateEntryAmount(); - U32 eAmount=it2->second->getEntryAmount(); - if(eAmount > (globalAmount*multiplier)) - return 1; - else - return 0; - } - else - { - it2->second->clearEntry(); - it2->second->updateEntryAmount(); - it2->second->updateEntryTime(); - return 0; - } - } - else - { - globalEntries[name.asString()]=new NACLAntiSpamQueueEntry(); - globalEntries[name.asString()]->updateEntryAmount(); - globalEntries[name.asString()]->updateEntryTime(); - return 0; - } -} -//static -void NACLAntiSpamRegistry::clearGlobalEntries() -{ - for(it2 = globalEntries.begin(); it2 != globalEntries.end(); it2++) - { - it2->second->clearEntry(); - } -} -//static -void NACLAntiSpamRegistry::purgeGlobalEntries() -{ - for(it2 = globalEntries.begin(); it2 != globalEntries.end(); it2++) - { - delete it2->second; - it2->second = 0; - } - globalEntries.clear(); + mQueues.reset(); } -//Handlers -//static +// Handlers +// static +void NACLAntiSpamRegistry::startup() +{ + auto onAntiSpamToggle = [](const LLControlVariable*, const LLSD& value) { + if (value.asBoolean()) instance(); + else deleteSingleton(); + }; + auto control = gSavedSettings.getControl("AntiSpamEnabled"); + control->getSignal()->connect(onAntiSpamToggle); + onAntiSpamToggle(control, control->get()); +} + +// static bool NACLAntiSpamRegistry::handleNaclAntiSpamGlobalQueueChanged(const LLSD& newvalue) { - setGlobalQueue(newvalue.asBoolean()); + if (instanceExists()) + { + auto& inst = instance(); + inst.purgeAllQueues(); + inst.initializeQueues(newvalue.asBoolean(), gSavedSettings.getU32("_NACL_AntiSpamTime"), gSavedSettings.getU32("_NACL_AntiSpamAmount")); + } return true; } //static bool NACLAntiSpamRegistry::handleNaclAntiSpamTimeChanged(const LLSD& newvalue) { - setAllQueueTimes(newvalue.asInteger()); + if (auto inst = getIfExists()) inst->setAllQueueTimes(newvalue.asInteger()); return true; } //static bool NACLAntiSpamRegistry::handleNaclAntiSpamAmountChanged(const LLSD& newvalue) { - setAllQueueAmounts(newvalue.asInteger()); + if (auto inst = getIfExists()) inst->setAllQueueAmounts(newvalue.asInteger()); return true; -} - +} \ No newline at end of file diff --git a/indra/newview/NACLantispam.h b/indra/newview/NACLantispam.h index 321bbde72..33c6d39d7 100644 --- a/indra/newview/NACLantispam.h +++ b/indra/newview/NACLantispam.h @@ -13,72 +13,22 @@ * 0. You just DO WHAT THE FUCK YOU WANT TO. */ -#ifndef NACLANTISPAM_H -#define NACLANTISPAM_H +#pragma once +#include #include #include "stdtypes.h" +#include "lfidbearer.h" #include "lluuid.h" -class NACLAntiSpamQueueEntry + +class NACLAntiSpamQueue; +class NACLAntiSpamRegistry final : public LLSingleton { - friend class NACLAntiSpamQueue; - friend class NACLAntiSpamRegistry; -protected: - NACLAntiSpamQueueEntry(); - void clearEntry(); - U32 getEntryAmount() const; - U32 getEntryTime() const; - void updateEntryAmount(); - void updateEntryTime(); - bool getBlocked() const; - void setBlocked(); -private: - U32 entryAmount; - U32 entryTime; - bool blocked; -}; -class NACLAntiSpamQueue -{ - friend class NACLAntiSpamRegistry; + friend class LLSingleton; + NACLAntiSpamRegistry(); public: - U32 getAmount() const; - U32 getTime() const; -protected: - NACLAntiSpamQueue(U32 time, U32 amount); - void setAmount(U32 amount); - void setTime(U32 time); - void clearEntries(); - void purgeEntries(); - void blockEntry(LLUUID& source); - int checkEntry(LLUUID& source, U32 multiplier); -private: - boost::unordered_map entries; - boost::unordered_map::iterator it; - U32 queueAmount; - U32 queueTime; -}; -class NACLAntiSpamRegistry -{ -public: - NACLAntiSpamRegistry(U32 time=2, U32 amount=10); - static void registerQueues(U32 time=2, U32 amount=10); -// static void registerQueue(U32 name, U32 time, U32 amount); - static void setRegisteredQueueTime(U32 name, U32 time); - static void setRegisteredQueueAmount(U32 name,U32 amount); - static void setAllQueueTimes(U32 amount); - static void setAllQueueAmounts(U32 time); - static bool checkQueue(U32 name, LLUUID& source, U32 multiplier=1); - static bool handleNaclAntiSpamGlobalQueueChanged(const LLSD& newvalue); - static bool handleNaclAntiSpamTimeChanged(const LLSD& newvalue); - static bool handleNaclAntiSpamAmountChanged(const LLSD& newvalue); - static void clearRegisteredQueue(U32 name); - static void purgeRegisteredQueue(U32 name); - static void clearAllQueues(); - static void purgeAllQueues(); - static void setGlobalQueue(bool value); - static void setGlobalAmount(U32 amount); - static void setGlobalTime(U32 time); - static void blockOnQueue(U32 name,LLUUID& owner_id); - enum { + static void startup(); + + enum Type : U8 { QUEUE_CHAT, QUEUE_INVENTORY, QUEUE_IM, @@ -89,22 +39,19 @@ public: QUEUE_TELEPORT, QUEUE_MAX }; + bool checkQueue(const Type& name, const LLUUID& source, const LFIDBearer::Type& type = LFIDBearer::AVATAR, const U32& multiplier = 1); + void blockOnQueue(const Type& name, const LLUUID& owner_id); + void idle(); + void resetQueues(); private: - static const char* getQueueName(U32 queue_id); - static NACLAntiSpamQueue* queues[QUEUE_MAX]; - static boost::unordered_map globalEntries; - static boost::unordered_map::iterator it2; - static U32 globalTime; - static U32 globalAmount; - static bool bGlobalQueue; - - static int checkGlobalEntry(LLUUID& source, U32 multiplier); - static void clearGlobalEntries(); - static void purgeGlobalEntries(); - static void blockGlobalEntry(LLUUID& source); + void setAllQueueTimes(U32 amount); + void setAllQueueAmounts(U32 time); + void purgeAllQueues(); + void initializeQueues(bool global, const U32& time, const U32& amount); + static bool handleNaclAntiSpamGlobalQueueChanged(const LLSD& newvalue); + static bool handleNaclAntiSpamTimeChanged(const LLSD& newvalue); + static bool handleNaclAntiSpamAmountChanged(const LLSD& newvalue); + std::unique_ptr> mQueues; + std::unique_ptr mGlobalQueue; + std::array mConnections; }; - -extern const std::string COLLISION_SOUNDS[]; -extern const int COLLISION_SOUNDS_SIZE; - -#endif //NACLANTISPAM_H diff --git a/indra/newview/alfloaterregiontracker.cpp b/indra/newview/alfloaterregiontracker.cpp index cc58da211..f95967367 100644 --- a/indra/newview/alfloaterregiontracker.cpp +++ b/indra/newview/alfloaterregiontracker.cpp @@ -117,6 +117,9 @@ void ALFloaterRegionTracker::refresh() { saved_selected_values.push_back(item->getValue().asString()); } + S32 saved_scroll_pos = mRegionScrollList->getScrollPos(); + auto sort_column_name = mRegionScrollList->getSortColumnName(); + auto sort_asending = mRegionScrollList->getSortAscending(); mRegionScrollList->deleteAllItems(); const std::string& cur_region_name = gAgent.getRegion()->getName(); @@ -172,8 +175,11 @@ void ALFloaterRegionTracker::refresh() mRegionScrollList->addRow(row); } } + + mRegionScrollList->sortByColumn(sort_column_name, sort_asending); if (!saved_selected_values.empty()) mRegionScrollList->selectMultiple(saved_selected_values); + mRegionScrollList->setScrollPos(saved_scroll_pos); } BOOL ALFloaterRegionTracker::tick() diff --git a/indra/newview/app_settings/default_grids.xml b/indra/newview/app_settings/default_grids.xml index f258b23d3..78c82ebdb 100644 --- a/indra/newview/app_settings/default_grids.xml +++ b/indra/newview/app_settings/default_grids.xml @@ -2,7 +2,7 @@ - default_grids_version22 + default_grids_version23 @@ -11,7 +11,7 @@ gridnameSecond Life platformSecondLife loginurihttps://login.agni.lindenlab.com/cgi-bin/login.cgi - loginpagehttp://viewer-login.agni.lindenlab.com/ + loginpagehttps://viewer-splash.secondlife.com/ helperurihttps://secondlife.com/helpers/ websitehttp://secondlife.com/ supporthttp://secondlife.com/support/ @@ -26,7 +26,7 @@ gridnicksecondlife_beta gridnameSecond Life BETA helperurihttp://aditi-secondlife.webdev.lindenlab.com/helpers/ - loginpagehttp://viewer-login.agni.lindenlab.com/ + loginpagehttps://viewer-splash.secondlife.com/ loginurihttps://login.aditi.lindenlab.com/cgi-bin/login.cgi passwordhttp://secondlife.com/account/request.php platformSecondLife diff --git a/indra/newview/app_settings/lsl_functions_sl.xml b/indra/newview/app_settings/lsl_functions_sl.xml index 7799b74a4..7bb14209c 100644 --- a/indra/newview/app_settings/lsl_functions_sl.xml +++ b/indra/newview/app_settings/lsl_functions_sl.xml @@ -1052,5 +1052,28 @@ llGetMaxScaleFactor + + llAgentInExperience + + llGetExperienceDetails + + llRequestExperiencePermissions + + llReadKeyValue + + llCreateKeyValue + + llUpdateKeyValue + + llDeleteKeyValue + + llDataSizeKeyValue + + llKeysKeyValue + + llKeyCountKeyValue + + llGetExperienceErrorMessage + diff --git a/indra/newview/app_settings/mime_types.xml b/indra/newview/app_settings/mime_types.xml index 0f78823b3..9182f5742 100644 --- a/indra/newview/app_settings/mime_types.xml +++ b/indra/newview/app_settings/mime_types.xml @@ -133,6 +133,17 @@ media_plugin_libvlc + + + + movie + + + media_plugin_example + + + LogChatColor + + Comment + Color of chat messages loaded from your log + Persist + 1 + Type + Color4 + Value + + 0.5 + 0.5 + 0.5 + 1.0 + + IsCOA + 1 + UISndAlert Comment @@ -2538,6 +2556,17 @@ This should be as low as possible, but too low may break functionality 1 + CrashHostUrl + + Comment + A URL pointing to a crash report handler; overrides cluster negotiation to locate crash handler. + Persist + 1 + Type + String + Value + + AFKTimeout Comment @@ -7482,6 +7511,54 @@ This should be as low as possible, but too low may break functionality 0 + FloaterExperiencePickerRect + + Comment + Rectangle for experience picker floater + Persist + 1 + Type + Rect + Value + + 300 + 600 + 800 + 700 + + + FloaterExperienceProfileRect + + Comment + Rectangle for experience profile floaters + Persist + 1 + Type + Rect + Value + + 377 + 650 + 345 + 128 + + + FloaterExperiencesRect + + Comment + Rectangle for experiences floater + Persist + 1 + Type + Rect + Value + + 300 + 600 + 700 + 700 + + FloaterFindRect2 Comment @@ -8239,7 +8316,7 @@ This should be as low as possible, but too low may break functionality 0 512 - 480 + 500 0 @@ -11659,17 +11736,6 @@ This should be as low as possible, but too low may break functionality Value 344 - RevokePermsOnStandUp - - Comment - When enabled, revokes any permission granted to an object you don't own and from which your avatar is standing up - Persist - 1 - Type - Boolean - Value - 0 - PickerContextOpacity Comment @@ -14561,6 +14627,17 @@ This should be as low as possible, but too low may break functionality Value 1 + RevokePermsOnStandUp + + Comment + When enabled, revokes any permission granted to an object you don't own and from which your avatar is standing up + Persist + 1 + Type + Boolean + Value + 0 + RevokePermsOnStopAnimation Comment diff --git a/indra/newview/app_settings/settings_ascent.xml b/indra/newview/app_settings/settings_ascent.xml index 65398b513..0c74e3164 100644 --- a/indra/newview/app_settings/settings_ascent.xml +++ b/indra/newview/app_settings/settings_ascent.xml @@ -91,6 +91,17 @@ Value 1 + ProfileNameSystem + + Comment + For a name displayed on its profile. 0 = Old Style, 1 = Display Names and Username, 2 = Displayname only, 3 = Old Style (Display Name) + Persist + 1 + Type + S32 + Value + 1 + RadarNameSystem Comment @@ -135,6 +146,28 @@ Value /resync + AlchemyChatCommandSetChatChannel + + Comment + Command to set nearby chat channel + Persist + 1 + Type + String + Value + /setchannel + + AlchemyChatCommandSetHome + + Comment + Command to set the avatar home + Persist + 1 + Type + String + Value + /sethome + AlchemyConnectToNeighbors Comment @@ -201,6 +234,17 @@ Value 1 + AlchemyNearbyChatChannel + + Comment + Chat channel used for sending nearby chat from the viewer + Persist + 0 + Type + S32 + Value + 0 + AlchemyRainbowEffects Comment @@ -521,6 +565,17 @@ Value 1 + AlchemyDisableSimCamConstraint + + Comment + Disable the push the simulator applies when camera collides with objects + Persist + 1 + Type + Boolean + Value + 0 + AscentFlyAlwaysEnabled Comment @@ -763,6 +818,17 @@ Value key2name + AscentCmdLineKeyToNameNameSystem + + Comment + For key to name command defined by AscentCmdLineKeyToName, the format to show the key's name in. 0 = Old Style, 1 = Display Names and Username, 2 = Displayname only, 3 = Old Style (Display Name) + Persist + 1 + Type + S32 + Value + 1 + AscentCmdLineOfferTp Comment @@ -840,17 +906,6 @@ Value /open - SinguCompleteNameProfiles - - Comment - Use the complete name "Display Name (legacy.name)" in profiles, instead of following the choice set by PhoenixNameSystem. - Persist - 1 - Type - Boolean - Value - 0 - SinguDefaultEaseIn Comment @@ -873,6 +928,17 @@ Value 0 + SinguFollowDistance + + Comment + Distance at which to follow objects and avatars at, from menus that offer follow (minimum 0.5) + Persist + 1 + Type + F32 + Value + 1.0 + SinguLastKnownReleaseBuild Comment @@ -1109,6 +1175,17 @@ Changing this setting only affects new text. Value 1 + LiruUseMarkedColor + + Comment + Whether or not to use the color of marks done on radar and minimap to color tags and chat from those individuals + Persist + 1 + Type + Boolean + Value + 1 + OBJExportNotifyFailed Comment @@ -1567,6 +1644,19 @@ Changing this setting only affects new text. IsCOA 1 + ToolbarVisibleExperiences + + Comment + Whether or not the button for the experiences floater is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + ToolbarVisibleFastTimers Comment diff --git a/indra/newview/ascentprefschat.cpp b/indra/newview/ascentprefschat.cpp index 084cc448f..25d196435 100644 --- a/indra/newview/ascentprefschat.cpp +++ b/indra/newview/ascentprefschat.cpp @@ -70,7 +70,10 @@ LLPrefsAscentChat::LLPrefsAscentChat() } childSetEnabled("reset_antispam", started); - getChild("reset_antispam")->setCommitCallback(boost::bind(NACLAntiSpamRegistry::purgeAllQueues)); + getChild("reset_antispam")->setCommitCallback([](LLUICtrl* ctrl, const LLSD& param) { + if (auto inst = NACLAntiSpamRegistry::getIfExists()) + inst->resetQueues(); + }); getChild("autoreplace")->setCommitCallback(boost::bind(LLFloaterAutoReplaceSettings::showInstance, LLSD())); getChild("KeywordsOn")->setCommitCallback(boost::bind(&LLPrefsAscentChat::onCommitKeywords, this, _1)); @@ -257,6 +260,7 @@ void LLPrefsAscentChat::refreshValues() mFriendNames = gSavedSettings.getS32("FriendNameSystem"); mGroupMembersNames = gSavedSettings.getS32("GroupMembersNameSystem"); mLandManagementNames = gSavedSettings.getS32("LandManagementNameSystem"); + mProfileNames = gSavedSettings.getS32("ProfileNameSystem"); mRadarNames = gSavedSettings.getS32("RadarNameSystem"); mSpeakerNames = gSavedSettings.getS32("SpeakerNameSystem"); @@ -454,6 +458,7 @@ void LLPrefsAscentChat::cancel() gSavedSettings.setS32("FriendNameSystem", mFriendNames); gSavedSettings.setS32("GroupMembersNameSystem", mGroupMembersNames); gSavedSettings.setS32("LandManagementNameSystem", mLandManagementNames); + gSavedSettings.setS32("ProfileNameSystem", mProfileNames); gSavedSettings.setS32("RadarNameSystem", mRadarNames); gSavedSettings.setS32("SpeakerNameSystem", mSpeakerNames); diff --git a/indra/newview/ascentprefschat.h b/indra/newview/ascentprefschat.h index 2521b2039..0f0dc9baa 100644 --- a/indra/newview/ascentprefschat.h +++ b/indra/newview/ascentprefschat.h @@ -91,6 +91,7 @@ private: S32 mFriendNames; S32 mGroupMembersNames; S32 mLandManagementNames; + S32 mProfileNames; S32 mRadarNames; S32 mSpeakerNames; diff --git a/indra/newview/ascentprefsvan.cpp b/indra/newview/ascentprefsvan.cpp index 0c6216647..0bb200636 100644 --- a/indra/newview/ascentprefsvan.cpp +++ b/indra/newview/ascentprefsvan.cpp @@ -130,7 +130,6 @@ void LLPrefsAscentVan::refreshValues() mAnnounceStreamMetadata = gSavedSettings.getBOOL("AnnounceStreamMetadata"); mInactiveFloaterTransparency = gSavedSettings.getF32("InactiveFloaterTransparency"); mActiveFloaterTransparency = gSavedSettings.getF32("ActiveFloaterTransparency"); - mCompleteNameProfiles = gSavedSettings.getBOOL("SinguCompleteNameProfiles"); mScriptErrorsStealFocus = gSavedSettings.getBOOL("LiruScriptErrorsStealFocus"); mConnectToNeighbors = gSavedSettings.getBOOL("AlchemyConnectToNeighbors"); mRestartMinimized = gSavedSettings.getBOOL("LiruRegionRestartMinimized"); @@ -205,7 +204,6 @@ void LLPrefsAscentVan::cancel() gSavedSettings.setBOOL("AnnounceStreamMetadata", mAnnounceStreamMetadata); gSavedSettings.setF32("InactiveFloaterTransparency", mInactiveFloaterTransparency); gSavedSettings.setF32("ActiveFloaterTransparency", mActiveFloaterTransparency); - gSavedSettings.setBOOL("SinguCompleteNameProfiles", mCompleteNameProfiles); gSavedSettings.setBOOL("LiruScriptErrorsStealFocus", mScriptErrorsStealFocus); gSavedSettings.setBOOL("AlchemyConnectToNeighbors", mConnectToNeighbors); gSavedSettings.setBOOL("LiruRegionRestartMinimized", mRestartMinimized); diff --git a/indra/newview/ascentprefsvan.h b/indra/newview/ascentprefsvan.h index d8e27338e..b29f5147d 100644 --- a/indra/newview/ascentprefsvan.h +++ b/indra/newview/ascentprefsvan.h @@ -63,7 +63,6 @@ private: bool mAnnounceSnapshots; bool mAnnounceStreamMetadata; F32 mInactiveFloaterTransparency, mActiveFloaterTransparency; - bool mCompleteNameProfiles; bool mScriptErrorsStealFocus; bool mConnectToNeighbors; bool mRestartMinimized; diff --git a/indra/newview/chatbar_as_cmdline.cpp b/indra/newview/chatbar_as_cmdline.cpp index c70eec31b..2f5da6a33 100644 --- a/indra/newview/chatbar_as_cmdline.cpp +++ b/indra/newview/chatbar_as_cmdline.cpp @@ -236,6 +236,7 @@ struct ProfCtrlListAccum : public LLControlGroup::ApplyFunctor #endif //PROF_CTRL_CALLS void spew_key_to_name(const LLUUID& targetKey, const LLAvatarName& av_name) { + static const LLCachedControl ns(gSavedSettings, "AscentCmdLineKeyToNameNameSystem"); cmdline_printchat(llformat("%s: %s", targetKey.asString().c_str(), av_name.getNSName().c_str())); } bool cmd_line_chat(std::string data, EChatType type) @@ -255,12 +256,14 @@ bool cmd_line_chat(std::string data, EChatType type) static LLCachedControl sPosCommand(gSavedSettings, "AscentCmdLinePos"); static LLCachedControl sRezPlatCommand(gSavedSettings, "AscentCmdLineRezPlatform"); static LLCachedControl sHomeCommand(gSavedSettings, "AscentCmdLineTeleportHome"); + static LLCachedControl sSetHomeCommand(gSavedSettings, "AlchemyChatCommandSetHome", "/sethome"); static LLCachedControl sCalcCommand(gSavedSettings, "AscentCmdLineCalc"); static LLCachedControl sMapToCommand(gSavedSettings, "AscentCmdLineMapTo"); static LLCachedControl sClearCommand(gSavedSettings, "AscentCmdLineClearChat"); static LLCachedControl sRegionMsgCommand(gSavedSettings, "SinguCmdLineRegionSay"); static LLCachedControl sTeleportToCam(gSavedSettings, "AscentCmdTeleportToCam"); static LLCachedControl sHoverHeight(gSavedSettings, "AlchemyChatCommandHoverHeight", "/hover"); + static LLCachedControl sSetNearbyChatChannelCmd(gSavedSettings, "AlchemyChatCommandSetChatChannel", "/setchannel"); static LLCachedControl sResyncAnimCommand(gSavedSettings, "AlchemyChatCommandResyncAnim", "/resync"); static LLCachedControl sKeyToName(gSavedSettings, "AscentCmdLineKeyToName"); static LLCachedControl sOfferTp(gSavedSettings, "AscentCmdLineOfferTp"); @@ -364,6 +367,11 @@ bool cmd_line_chat(std::string data, EChatType type) gAgent.teleportHome(); return false; } + else if (cmd == utf8str_tolower(sSetHomeCommand)) // sethome + { + gAgent.setStartPosition(START_LOCATION_ID_HOME); + return false; + } else if (cmd == utf8str_tolower(sCalcCommand))//Cryogenic Blitz { if (data.length() > cmd.length() + 1) @@ -447,6 +455,15 @@ bool cmd_line_chat(std::string data, EChatType type) } return false; } + else if (cmd == utf8str_tolower(sSetNearbyChatChannelCmd)) // Set nearby chat channel + { + S32 chan; + if (input >> chan) + { + gSavedSettings.setS32("AlchemyNearbyChatChannel", chan); + return false; + } + } else if (cmd == utf8str_tolower(sTeleportToCam)) { gAgent.teleportViaLocation(gAgentCamera.getCameraPositionGlobal()); diff --git a/indra/newview/gpu_table.txt b/indra/newview/gpu_table.txt index 618c8970e..af5aa6a12 100644 --- a/indra/newview/gpu_table.txt +++ b/indra/newview/gpu_table.txt @@ -438,6 +438,12 @@ NVIDIA GTX 770 .*NVIDIA .*GTX *77.* 3 1 NVIDIA GTX 780 .*NVIDIA .*GTX *78.* 3 1 NVIDIA GTX 970 .*NVIDIA .*GTX *97.* 3 1 NVIDIA GTX 980 .*NVIDIA .*GTX *98.* 3 1 +NVIDIA GTX 1050 .*NVIDIA.*GTX 105.* 3 1 +NVIDIA GTX 1060 .*NVIDIA.*GTX 106.* 3 1 +NVIDIA GTX 1070 .*NVIDIA.*GTX 107.* 3 1 +NVIDIA GTX 1080 .*NVIDIA.*GTX 108.* 3 1 +NVIDIA GTX 1650 .*NVIDIA.*GTX 165.* 3 1 +NVIDIA GTX 1660 .*NVIDIA.*GTX 166.* 3 1 NVIDIA GTX TITAN .*NVIDIA .*GTX *TITAN.* 3 1 NVIDIA GeForce/Quadro RTX .*(GeForce|Quadro) .*RTX.* 3 1 NVIDIA RTX TITAN .*NVIDIA .*RTX.*TITAN.* 3 1 diff --git a/indra/newview/installers/windows/installer_template.nsi b/indra/newview/installers/windows/installer_template.nsi index b2d52808a..04c810ed7 100644 --- a/indra/newview/installers/windows/installer_template.nsi +++ b/indra/newview/installers/windows/installer_template.nsi @@ -1,6 +1,7 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Second Life setup.nsi -;; Copyright 2004-2015, Linden Research, Inc. +;; secondlife setup.nsi +;; Copyright 2004-2011, Linden Research, Inc. +;; Copyright 2013-2015 Alchemy Viewer Project ;; ;; This library is free software; you can redistribute it and/or ;; modify it under the terms of the GNU Lesser General Public @@ -94,18 +95,6 @@ ;File Handling SetOverwrite on -;-------------------------------- -;Version Information - - VIProductVersion "${VERSION_LONG}" - VIAddVersionKey "ProductName" "Singularity Viewer Installer" - VIAddVersionKey "Comments" "A viewer for the meta-verse!" - VIAddVersionKey "CompanyName" "${VENDORSTR}" - VIAddVersionKey "LegalCopyright" "Copyright © 2010-2019, ${VENDORSTR}" - VIAddVersionKey "FileDescription" "${APPNAME} Installer" - VIAddVersionKey "ProductVersion" "${VERSION_LONG}" - VIAddVersionKey "FileVersion" "${VERSION_LONG}" - ;-------------------------------- ;Interface Settings @@ -198,6 +187,18 @@ !include "%%SOURCE%%\installers\windows\lang_tr.nsi" !include "%%SOURCE%%\installers\windows\lang_zh.nsi" +;-------------------------------- +;Version Information + + VIProductVersion "${VERSION_LONG}" + VIAddVersionKey /LANG=${LANG_ENGLISH} "ProductName" "Singularity Viewer Installer" + VIAddVersionKey /LANG=${LANG_ENGLISH} "Comments" "A viewer for the meta-verse!" + VIAddVersionKey /LANG=${LANG_ENGLISH} "CompanyName" "${VENDORSTR}" + VIAddVersionKey /LANG=${LANG_ENGLISH} "LegalCopyright" "Copyright © 2010-2020, ${VENDORSTR}" + VIAddVersionKey /LANG=${LANG_ENGLISH} "FileDescription" "${APPNAME} Installer" + VIAddVersionKey /LANG=${LANG_ENGLISH} "ProductVersion" "${VERSION_LONG}" + VIAddVersionKey /LANG=${LANG_ENGLISH} "FileVersion" "${VERSION_LONG}" + ;-------------------------------- ;Reserve Files @@ -206,7 +207,7 @@ ;because this will make your installer start faster. !insertmacro MUI_RESERVEFILE_LANGDLL - ReserveFile "${NSISDIR}\Plugins\x86-unicode\nsisdl.dll" + ReserveFile "${NSISDIR}\Plugins\x86-unicode\NSISdl.dll" ReserveFile "${NSISDIR}\Plugins\x86-unicode\nsDialogs.dll" ReserveFile "${NSISDIR}\Plugins\x86-unicode\StartMenu.dll" ReserveFile "${NSISDIR}\Plugins\x86-unicode\StdUtils.dll" @@ -408,7 +409,41 @@ Section "Viewer" ;This placeholder is replaced by the complete list of all the files in the installer, by viewer_manifest.py %%INSTALL_FILES%% - + + ;Create temp dir and set out dir to it + CreateDirectory "$TEMP\AlchemyInst" + SetOutPath "$TEMP\AlchemyInst" + + ;Download LibVLC +!ifdef WIN64_BIN_BUILD + NSISdl::download "http://download.videolan.org/pub/videolan/vlc/3.0.8/win64/vlc-3.0.8-win64.7z" "$TEMP\AlchemyInst\libvlc.7z" +!else + NSISdl::download "http://download.videolan.org/pub/videolan/vlc/3.0.8/win32/vlc-3.0.8-win32.7z" "$TEMP\AlchemyInst\libvlc.7z" +!endif + Nsis7z::ExtractWithDetails "$TEMP\AlchemyInst\libvlc.7z" "Unpacking media plugins %s..." + Rename "$TEMP\AlchemyInst\vlc-3.0.8\libvlc.dll" "$INSTDIR\llplugin\libvlc.dll" + Rename "$TEMP\AlchemyInst\vlc-3.0.8\libvlccore.dll" "$INSTDIR\llplugin\libvlccore.dll" + Rename "$TEMP\AlchemyInst\vlc-3.0.8\plugins" "$INSTDIR\llplugin\plugins" + + ;Download and install VC redist +!ifdef WIN64_BIN_BUILD + NSISdl::download "https://aka.ms/vs/16/release/vc_redist.x64.exe" "$TEMP\AlchemyInst\vc_redist_16.x64.exe" + ExecWait "$TEMP\AlchemyInst\vc_redist_16.x64.exe /install /passive /norestart" + + NSISdl::download "https://aka.ms/highdpimfc2013x64enu" "$TEMP\AlchemyInst\vc_redist_12.x64.exe" + ExecWait "$TEMP\AlchemyInst\vc_redist_12.x64.exe /install /passive /norestart" +!else + NSISdl::download "https://aka.ms/vs/16/release/vc_redist.x86.exe" "$TEMP\AlchemyInst\vc_redist_16.x86.exe" + ExecWait "$TEMP\AlchemyInst\vc_redist_16.x86.exe /install /passive /norestart" + + NSISdl::download "https://aka.ms/highdpimfc2013x86enu" "$TEMP\AlchemyInst\vc_redist_12.x86.exe" + ExecWait "$TEMP\AlchemyInst\vc_redist_12.x86.exe /install /passive /norestart" +!endif + + ;Remove temp dir and reset out to inst dir + RMDir /r "$TEMP\AlchemyInst\" + SetOutPath "$INSTDIR" + ;Pass the installer's language to the client to use as a default StrCpy $SHORTCUT_LANG_PARAM "--set InstallLanguage $(LanguageCode)" @@ -425,6 +460,7 @@ Section "Viewer" WriteINIStr "$SMPROGRAMS\$STARTMENUFOLDER\SL Create Account.url" "InternetShortcut" "URL" "http://join.secondlife.com/" WriteINIStr "$SMPROGRAMS\$STARTMENUFOLDER\SL Your Account.url" "InternetShortcut" "URL" "http://www.secondlife.com/account/" WriteINIStr "$SMPROGRAMS\$STARTMENUFOLDER\SL Scripting Language Help.url" "InternetShortcut" "URL" "http://wiki.secondlife.com/wiki/LSL_Portal" + !insertmacro MUI_STARTMENU_WRITE_END ;Other shortcuts diff --git a/indra/newview/jcfloaterareasearch.cpp b/indra/newview/jcfloaterareasearch.cpp index 4c5ad09e1..ae970ebc3 100644 --- a/indra/newview/jcfloaterareasearch.cpp +++ b/indra/newview/jcfloaterareasearch.cpp @@ -80,13 +80,21 @@ BOOL JCFloaterAreaSearch::postBuild() mResultList = getChild("result_list"); mResultList->setDoubleClickCallback(boost::bind(&JCFloaterAreaSearch::onDoubleClick,this)); mResultList->sortByColumn("Name", TRUE); + auto tp = getChild("TP"); + auto look = getChild("Look"); + mResultList->setCommitOnSelectionChange(true); + mResultList->setCommitCallback([=](LLUICtrl* ctrl, const LLSD& param){ + bool enabled = mResultList->getNumSelected() == 1; + tp->setEnabled(enabled); + look->setEnabled(enabled); + }); mCounterText = getChild("counter"); getChild("Refresh")->setClickedCallback(boost::bind(&JCFloaterAreaSearch::onRefresh,this)); getChild("Stop")->setClickedCallback(boost::bind(&JCFloaterAreaSearch::onStop,this)); - getChild("TP")->setClickedCallback(boost::bind(&JCFloaterAreaSearch::teleportToSelected, this)); - getChild("Look")->setClickedCallback(boost::bind(&JCFloaterAreaSearch::lookAtSelected, this)); + tp->setClickedCallback(boost::bind(&JCFloaterAreaSearch::teleportToSelected, this)); + look->setClickedCallback(boost::bind(&JCFloaterAreaSearch::lookAtSelected, this)); getChild("Name query chunk")->setCommitCallback(boost::bind(&JCFloaterAreaSearch::onCommitLine,this,_1,_2,LIST_OBJECT_NAME)); getChild("Description query chunk")->setCommitCallback(boost::bind(&JCFloaterAreaSearch::onCommitLine,this,_1,_2,LIST_OBJECT_DESC)); @@ -291,6 +299,7 @@ void JCFloaterAreaSearch::processObjectPropertiesFamily(LLMessageSystem* msg, vo // We cache unknown objects (to avoid having to request them later) // and requested objects. msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_OwnerID, data->owner_id); + if (auto obj = gObjectList.findObject(object_id)) obj->mOwnerID = data->owner_id; // Singu Note: Try to get Owner whenever possible msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_GroupID, data->group_id); msg->getStringFast(_PREHASH_ObjectData, _PREHASH_Name, data->name); msg->getStringFast(_PREHASH_ObjectData, _PREHASH_Description, data->desc); diff --git a/indra/newview/jcfloaterareasearch.h b/indra/newview/jcfloaterareasearch.h index 32c40c253..033dc22ad 100644 --- a/indra/newview/jcfloaterareasearch.h +++ b/indra/newview/jcfloaterareasearch.h @@ -56,6 +56,20 @@ public: void results(); static void processObjectPropertiesFamily(LLMessageSystem* msg, void** user_data); + struct ObjectData + { + LLUUID id; + std::string name; + std::string desc; + LLUUID owner_id; + LLUUID group_id; + }; + + const ObjectData* getObjectData(const LLUUID& id) const + { + const auto& it = mCachedObjects.find(id); + return it != mCachedObjects.end() ? &it->second : nullptr; + } private: @@ -84,14 +98,6 @@ private: LLViewerRegion* mLastRegion; bool mStopped; - struct ObjectData - { - LLUUID id; - std::string name; - std::string desc; - LLUUID owner_id; - LLUUID group_id; - }; uuid_set_t mPendingObjects; boost::unordered_map mCachedObjects; diff --git a/indra/newview/lffloaterinvpanel.cpp b/indra/newview/lffloaterinvpanel.cpp index be530d1e2..b687100a0 100644 --- a/indra/newview/lffloaterinvpanel.cpp +++ b/indra/newview/lffloaterinvpanel.cpp @@ -32,48 +32,38 @@ LFFloaterInvPanel::LFFloaterInvPanel(const LLSD& cat, const std::string& name, L : LLInstanceTracker(cat) { // Setup the floater first - mPanel = new LLInventoryPanel("inv_panel", LLInventoryPanel::DEFAULT_SORT_ORDER, cat, LLRect(), model ? model : &gInventory, true); - const auto& title = name.empty() ? gInventory.getCategory(mPanel->getRootFolderID())->getName() : name; - - // Figure out a unique name for our rect control - const auto rect_control = llformat("FloaterInv%sRect", boost::algorithm::erase_all_copy(title, " ").data()); - - bool existed = gSavedSettings.controlExists(rect_control); - if (existed) // Set our initial rect to the stored control - setRectControl(rect_control); + auto mPanel = new LLInventoryPanel("inv_panel", LLInventoryPanel::DEFAULT_SORT_ORDER, cat, LLRect(), model ? model : &gInventory, true); // Load from XUI - mCommitCallbackRegistrar.add("InvPanel.Search", boost::bind(&LLInventoryPanel::setFilterSubString, boost::ref(mPanel), _2)); + mCommitCallbackRegistrar.add("InvPanel.Search", boost::bind(&LLInventoryPanel::setFilterSubString, mPanel, _2)); LLUICtrlFactory::getInstance()->buildFloater(this, "floater_inv_panel.xml"); // Now set the title + const auto& title = name.empty() ? gInventory.getCategory(mPanel->getRootFolderID())->getName() : name; setTitle(title); - // If we haven't existed before, create and set our rect control now - if (!existed) + // Figure out a unique name for our rect control + const auto rect_control = llformat("FloaterInv%sRect", boost::algorithm::erase_all_copy(title, " ").data()); + if (!gSavedSettings.controlExists(rect_control)) // If we haven't existed before, create it { S32 left, top; gFloaterView->getNewFloaterPosition(&left, &top); LLRect rect = getRect(); rect.translate(left - rect.mLeft, top - rect.mTop); - setRect(rect); gSavedSettings.declareRect(rect_control, rect, "Rectangle for " + title + " window"); - setRectControl(rect_control); } + setRectControl(rect_control); + applyRectControl(); // Set our initial rect to the stored (or just created) control // Now take care of the children LLPanel* panel = getChild("placeholder_panel"); mPanel->setRect(panel->getRect()); + mPanel->setOrigin(0, 0); mPanel->postBuild(); mPanel->setFollows(FOLLOWS_ALL); mPanel->setEnabled(true); - addChild(mPanel); - removeChild(panel); -} - -LFFloaterInvPanel::~LFFloaterInvPanel() -{ - delete mPanel; + mPanel->removeBorder(); + panel->addChild(mPanel); } // static @@ -100,15 +90,18 @@ void LFFloaterInvPanel::closeAll() } } -// virtual BOOL LFFloaterInvPanel::handleKeyHere(KEY key, MASK mask) { - if (!mPanel->hasFocus() && mask == MASK_NONE && (key == KEY_RETURN || key == KEY_DOWN)) + if (mask == MASK_NONE && (key == KEY_RETURN || key == KEY_DOWN)) { - mPanel->setFocus(true); - if (LLFolderView* root = mPanel->getRootFolder()) - root->scrollToShowSelection(); - return true; + auto& mPanel = *getChild("inv_panel"); + if (!mPanel.hasFocus()) + { + mPanel.setFocus(true); + if (LLFolderView* root = mPanel.getRootFolder()) + root->scrollToShowSelection(); + return true; + } } return LLFloater::handleKeyHere(key, mask); diff --git a/indra/newview/lffloaterinvpanel.h b/indra/newview/lffloaterinvpanel.h index 724fed98d..c65763cdd 100644 --- a/indra/newview/lffloaterinvpanel.h +++ b/indra/newview/lffloaterinvpanel.h @@ -18,18 +18,16 @@ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA */ -#ifndef LFFLOATERINVPANEL_H -#define LFFLOATERINVPANEL_H +#pragma once #include "llfloater.h" #include "llinstancetracker.h" #include "llsdutil.h" -class LFFloaterInvPanel : public LLFloater, public LLInstanceTracker +class LFFloaterInvPanel final : public LLFloater, public LLInstanceTracker { LFFloaterInvPanel(const LLSD& cat, const std::string& name = LLStringUtil::null, class LLInventoryModel* model = nullptr); - ~LFFloaterInvPanel(); public: static void show(const LLSD& cat, const std::string& name = LLStringUtil::null, LLInventoryModel* model = nullptr); // Show the floater for cat (create with other params if necessary) @@ -42,10 +40,5 @@ public: } static void closeAll(); // Called when not allowed to have inventory open - /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask); - -private: - class LLInventoryPanel* mPanel; + BOOL handleKeyHere(KEY key, MASK mask) override; }; - -#endif //LFFLOATERINVPANEL_H diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index f5ea77a9d..ed765ff27 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -38,11 +38,14 @@ #include "llanimationstates.h" #include "llcallingcard.h" #include "llcapabilitylistener.h" +#include "llcororesponder.h" #include "llconsole.h" #include "llenvmanager.h" #include "llfirstuse.h" #include "llfloatercamera.h" #include "llfloatertools.h" +#include "llfloaterpostcard.h" +#include "llfloaterpreference.h" #include "llgroupactions.h" #include "llgroupmgr.h" #include "llhomelocationresponder.h" @@ -184,10 +187,10 @@ public: LLTeleportRequestViaLandmark(const LLUUID &pLandmarkId); virtual ~LLTeleportRequestViaLandmark(); - virtual bool canRestartTeleport(); + bool canRestartTeleport() override; - virtual void startTeleport(); - virtual void restartTeleport(); + void startTeleport() override; + void restartTeleport() override; protected: inline const LLUUID &getLandmarkId() const {return mLandmarkId;}; @@ -196,15 +199,15 @@ private: LLUUID mLandmarkId; }; -class LLTeleportRequestViaLure : public LLTeleportRequestViaLandmark +class LLTeleportRequestViaLure final : public LLTeleportRequestViaLandmark { public: LLTeleportRequestViaLure(const LLUUID &pLureId, BOOL pIsLureGodLike); virtual ~LLTeleportRequestViaLure(); - virtual bool canRestartTeleport(); + bool canRestartTeleport() override; - virtual void startTeleport(); + void startTeleport() override; protected: inline BOOL isLureGodLike() const {return mIsLureGodLike;}; @@ -219,10 +222,10 @@ public: LLTeleportRequestViaLocation(const LLVector3d &pPosGlobal); virtual ~LLTeleportRequestViaLocation(); - virtual bool canRestartTeleport(); + bool canRestartTeleport() override; - virtual void startTeleport(); - virtual void restartTeleport(); + void startTeleport() override; + void restartTeleport() override; protected: inline const LLVector3d &getPosGlobal() const {return mPosGlobal;}; @@ -232,16 +235,16 @@ private: }; -class LLTeleportRequestViaLocationLookAt : public LLTeleportRequestViaLocation +class LLTeleportRequestViaLocationLookAt final : public LLTeleportRequestViaLocation { public: LLTeleportRequestViaLocationLookAt(const LLVector3d &pPosGlobal); virtual ~LLTeleportRequestViaLocationLookAt(); - virtual bool canRestartTeleport(); + bool canRestartTeleport() override; - virtual void startTeleport(); - virtual void restartTeleport(); + void startTeleport() override; + void restartTeleport() override; protected: @@ -258,12 +261,12 @@ const F32 LLAgent::TYPING_TIMEOUT_SECS = 5.f; std::map LLAgent::sTeleportErrorMessages; std::map LLAgent::sTeleportProgressMessages; -class LLAgentFriendObserver : public LLFriendObserver +class LLAgentFriendObserver final : public LLFriendObserver { public: - LLAgentFriendObserver() {} - virtual ~LLAgentFriendObserver() {} - virtual void changed(U32 mask); + LLAgentFriendObserver() = default; + virtual ~LLAgentFriendObserver() = default; + void changed(U32 mask) override; }; void LLAgentFriendObserver::changed(U32 mask) @@ -293,7 +296,7 @@ bool LLAgent::isActionAllowed(const LLSD& sdname) { bool allow_agent_voice = false; LLVoiceChannel* channel = LLVoiceChannel::getCurrentVoiceChannel(); - if (channel != NULL) + if (channel != nullptr) { if (channel->getSessionName().empty() && channel->getSessionID().isNull()) { @@ -381,6 +384,7 @@ LLAgent::LLAgent() : mAgentAccess(new LLAgentAccess(gSavedSettings)), mGodLevelChangeSignal(), + mIsCrossingRegion(false), mCanEditParcel(false), mTeleportSourceSLURL(new LLSLURL), mTeleportRequest(), @@ -907,7 +911,7 @@ void LLAgent::setRegion(LLViewerRegion *regionp) if (mRegionp) { // NaCl - Antispam Registry - NACLAntiSpamRegistry::purgeAllQueues(); + if (auto antispam = NACLAntiSpamRegistry::getIfExists()) antispam->resetQueues(); // NaCl End // We've changed regions, we're now going to change our agent coordinate frame. @@ -1612,12 +1616,14 @@ void LLAgent::startAutoPilotGlobal( mAutoPilotFlyOnStop = FALSE; } - if (distance > 30.0 && mAutoPilotAllowFlying) + bool follow = mAutoPilotBehaviorName == "Follow"; + + if (!follow && distance > 30.0 && mAutoPilotAllowFlying) { setFlying(TRUE); } - if ( distance > 1.f && + if (!follow && distance > 1.f && mAutoPilotAllowFlying && heightDelta > (sqrtf(mAutoPilotStopDistance) + 1.f)) { @@ -1689,7 +1695,7 @@ void LLAgent::startFollowPilot(const LLUUID &leader_id, BOOL allow_flying, F32 s } startAutoPilotGlobal(object->getPositionGlobal(), - std::string(), // behavior_name + "Follow", // behavior_name NULL, // target_rotation NULL, // finish_callback NULL, // callback_data @@ -1706,6 +1712,9 @@ void LLAgent::stopAutoPilot(BOOL user_cancel) { if (mAutoPilot) { + if (!user_cancel && mAutoPilotBehaviorName == "Follow") + return; // Follow means actually follow + mAutoPilot = FALSE; if (mAutoPilotUseRotation && !user_cancel) { @@ -1724,7 +1733,16 @@ void LLAgent::stopAutoPilot(BOOL user_cancel) mAutoPilotFinishedCallback(!user_cancel && dist_vec_squared(gAgent.getPositionGlobal(), mAutoPilotTargetGlobal) < (mAutoPilotStopDistance * mAutoPilotStopDistance), mAutoPilotCallbackData); mAutoPilotFinishedCallback = NULL; } + + // Sit response during follow pilot, now complete, resume follow + if (!user_cancel && mAutoPilotBehaviorName == "Sit" && mLeaderID.notNull()) + { + startFollowPilot(mLeaderID, true, gSavedSettings.getF32("SinguFollowDistance")); + return; + } + mLeaderID = LLUUID::null; + mAutoPilotNoProgressFrameCount = 0; setControlFlags(AGENT_CONTROL_STOP); @@ -1734,6 +1752,8 @@ void LLAgent::stopAutoPilot(BOOL user_cancel) LLNotificationsUtil::add("CancelledSit"); else if (mAutoPilotBehaviorName == "Attach") LLNotificationsUtil::add("CancelledAttach"); + else if (mAutoPilotBehaviorName == "Follow") + LLNotificationsUtil::add("CancelledFollow"); else LLNotificationsUtil::add("Cancelled"); } @@ -1741,28 +1761,104 @@ void LLAgent::stopAutoPilot(BOOL user_cancel) } +bool LLAgent::getAutoPilotNoProgress() const +{ + return mAutoPilotNoProgressFrameCount > AUTOPILOT_MAX_TIME_NO_PROGRESS * gFPSClamped; +} + // Returns necessary agent pitch and yaw changes, radians. //----------------------------------------------------------------------------- // autoPilot() //----------------------------------------------------------------------------- void LLAgent::autoPilot(F32 *delta_yaw) { - if (mAutoPilot) + if (mAutoPilot && isAgentAvatarValid()) { - if (!mLeaderID.isNull()) + U8 follow = mAutoPilotBehaviorName == "Follow"; + if (follow) { - LLViewerObject* object = gObjectList.findObject(mLeaderID); - if (!object) + llassert(mLeaderID.notNull()); + const auto old_pos = mAutoPilotTargetGlobal; + if (auto object = gObjectList.findObject(mLeaderID)) { - stopAutoPilot(); - return; - } - mAutoPilotTargetGlobal = object->getPositionGlobal(); - } - - if (!isAgentAvatarValid()) return; + mAutoPilotTargetGlobal = object->getPositionGlobal(); + if (const auto& av = object->asAvatar()) // Fly if avatar target is flying + { + setFlying(av->mInAir); + if (av->isSitting() && (!rlv_handler_t::isEnabled() || !gRlvHandler.hasBehaviour(RLV_BHVR_SIT))) + { + if (auto seat = av->getParent()) + { + if (gAgentAvatarp->getParent() == seat) + { + mAutoPilotNoProgressFrameCount = 0; // We may have incremented this before making it here, reset it + return; // We're seated with them, nothing more to do + } + else if (!getAutoPilotNoProgress()) + { + void handle_object_sit(LLViewerObject*, const LLVector3&); + handle_object_sit(static_cast(seat), LLVector3::zero); + follow = 2; // Indicate ground sitting is okay if we can't make it + } + else return; // If the server just wouldn't let us sit there, we won't be moving, exit here + } + else // Ground sit, but only if near enough + { + if (dist_vec(av->getPositionAgent(), getPositionAgent()) <= mAutoPilotStopDistance) // We're close enough, sit. + { + if (!gAgentAvatarp->isSittingAvatarOnGround()) + setControlFlags(AGENT_CONTROL_SIT_ON_GROUND); + mAutoPilotNoProgressFrameCount = 0; // Ground Sit may have incremented this, reset it now + return; // We're already sitting on the ground, we have nothing to do + } + else // We're not close enough yet + { + if (/*!gAgentAvatarp->isSitting() && */ // RLV takes care of sitting check for us inside standUp + getAutoPilotNoProgress()) // Only stand up if we haven't exhausted our no progress frames + standUp(); // Unsit if need be, so we can move + follow = 2; // Indicate we want to groundsit + } + } + } + else + { + if (dist_vec(av->getPositionAgent(), getPositionAgent()) <= mAutoPilotStopDistance) + { + follow = 3; // We're close enough, indicate no walking + } - if (gAgentAvatarp->mInAir && mAutoPilotAllowFlying) + if (gAgentAvatarp->isSitting()) // Leader isn't sitting, standUp if needed + { + standUp(); + mAutoPilotNoProgressFrameCount = 0; // Ground Sit may have incremented this, reset it + } + } + } + } + else // We might still have a valid avatar pos + { + const LLVector3d& get_av_pos(const LLUUID & id); + auto pos = get_av_pos(mLeaderID); + if (pos.isExactlyZero()) // Default constructed or invalid from server + { + // Wait for them for more follow pilot + return; + } + standUp(); // Leader not rendered, we mustn't be sitting + mAutoPilotNoProgressFrameCount = 0; // Ground Sit may have incremented this, reset it + mAutoPilotTargetGlobal = pos; + setFlying(true); // Should we fly here? Altitude is often invalid... + + if (dist_vec(mAutoPilotTargetGlobal, getPositionGlobal()) <= mAutoPilotStopDistance) + { + follow = 3; // We're close enough, indicate no walking + } + } + if (old_pos != mAutoPilotTargetGlobal) // Reset if position changes + mAutoPilotNoProgressFrameCount = 0; + } + + if (follow % 2 == 0 && gAgentAvatarp->mInAir && mAutoPilotAllowFlying) { setFlying(TRUE); } @@ -1774,12 +1870,15 @@ void LLAgent::autoPilot(F32 *delta_yaw) F32 target_dist = direction.magVec(); - if (target_dist >= mAutoPilotTargetDist) + if (follow % 2 == 0 && target_dist >= mAutoPilotTargetDist) { mAutoPilotNoProgressFrameCount++; - if (mAutoPilotNoProgressFrameCount > AUTOPILOT_MAX_TIME_NO_PROGRESS * gFPSClamped) + if (getAutoPilotNoProgress()) { - stopAutoPilot(); + if (follow) // Well, we tried to reach them, let's just ground sit for now. + setControlFlags(AGENT_CONTROL_SIT_ON_GROUND); + else + stopAutoPilot(); return; } } @@ -1821,6 +1920,7 @@ void LLAgent::autoPilot(F32 *delta_yaw) } *delta_yaw = yaw; + if (follow == 3) return; // We're close enough, all we need to do is turn // Compute when to start slowing down F32 slow_distance; @@ -2492,15 +2592,11 @@ void LLAgent::onAnimStop(const LLUUID& id) } else if (id == ANIM_AGENT_AWAY) { -// clearAFK(); // [RLVa:KB] - Checked: 2010-05-03 (RLVa-1.2.0g) | Added: RLVa-1.1.0g -#ifdef RLV_EXTENSION_CMD_ALLOWIDLE if (!gRlvHandler.hasBehaviour(RLV_BHVR_ALLOWIDLE)) clearAFK(); -#else - clearAFK(); -#endif // RLV_EXTENSION_CMD_ALLOWIDLE // [/RLVa:KB] +// clearAFK(); } else if (id == ANIM_AGENT_STANDUP) { @@ -2571,7 +2667,7 @@ bool LLAgent::canAccessMaturityInRegion( U64 region_handle ) const return true; } -bool LLAgent::canAccessMaturityAtGlobal( LLVector3d pos_global ) const +bool LLAgent::canAccessMaturityAtGlobal(const LLVector3d& pos_global ) const { U64 region_handle = to_region_handle_global( pos_global.mdV[0], pos_global.mdV[1] ); return canAccessMaturityInRegion( region_handle ); @@ -2618,7 +2714,7 @@ int LLAgent::convertTextToMaturity(char text) return LLAgentAccess::convertTextToMaturity(text); } -class LLMaturityPreferencesResponder : public LLHTTPClient::ResponderWithResult +class LLMaturityPreferencesResponder final : public LLHTTPClient::ResponderWithResult { LOG_CLASS(LLMaturityPreferencesResponder); public: @@ -2626,12 +2722,10 @@ public: virtual ~LLMaturityPreferencesResponder(); protected: - virtual void httpSuccess(); - virtual void httpFailure(); - - /*virtual*/ char const* getName(void) const { return "LLMaturityPreferencesResponder"; } -protected: + void httpSuccess() override; + void httpFailure() override; + char const* getName() const override { return "LLMaturityPreferencesResponder"; } private: U8 parseMaturityFromServerResponse(const LLSD &pContent) const; @@ -2832,7 +2926,7 @@ void LLAgent::sendMaturityPreferenceToServer(U8 pPreferredMaturity) boost::intrusive_ptr responderPtr = boost::intrusive_ptr(new LLMaturityPreferencesResponder(this, pPreferredMaturity, mLastKnownResponseMaturity)); // If we don't have a region, report it as an error - if (getRegion() == NULL) + if (getRegion() == nullptr) { responderPtr->failureResult(0U, "region is not defined", LLSD()); } @@ -3109,24 +3203,27 @@ void LLAgent::sendAnimationRequests(const uuid_vec_t &anim_ids, EAnimRequest req msg->addUUIDFast(_PREHASH_AgentID, getID()); msg->addUUIDFast(_PREHASH_SessionID, getSessionID()); - for (U32 i = 0; i < anim_ids.size(); i++) + for (auto anim_id : anim_ids) { - if (anim_ids[i].isNull()) + if (anim_id.isNull()) { continue; } msg->nextBlockFast(_PREHASH_AnimationList); - msg->addUUIDFast(_PREHASH_AnimID, (anim_ids[i]) ); + msg->addUUIDFast(_PREHASH_AnimID, anim_id); msg->addBOOLFast(_PREHASH_StartAnim, (request == ANIM_REQUEST_START) ? TRUE : FALSE); num_valid_anims++; } + if (!num_valid_anims) + { + msg->clearMessage(); + return; + } msg->nextBlockFast(_PREHASH_PhysicalAvatarEventList); - msg->addBinaryDataFast(_PREHASH_TypeData, NULL, 0); - if (num_valid_anims) - { - sendReliableMessage(); - } + msg->addBinaryDataFast(_PREHASH_TypeData, nullptr, 0); + + sendReliableMessage(); } void LLAgent::sendAnimationRequest(const LLUUID &anim_id, EAnimRequest request) @@ -3147,7 +3244,7 @@ void LLAgent::sendAnimationRequest(const LLUUID &anim_id, EAnimRequest request) msg->addBOOLFast(_PREHASH_StartAnim, (request == ANIM_REQUEST_START) ? TRUE : FALSE); msg->nextBlockFast(_PREHASH_PhysicalAvatarEventList); - msg->addBinaryDataFast(_PREHASH_TypeData, NULL, 0); + msg->addBinaryDataFast(_PREHASH_TypeData, nullptr, 0); sendReliableMessage(); } @@ -3171,7 +3268,7 @@ void LLAgent::sendAnimationStateReset() msg->addBOOLFast(_PREHASH_StartAnim, FALSE); msg->nextBlockFast(_PREHASH_PhysicalAvatarEventList); - msg->addBinaryDataFast(_PREHASH_TypeData, NULL, 0); + msg->addBinaryDataFast(_PREHASH_TypeData, nullptr, 0); sendReliableMessage(); } @@ -3410,8 +3507,8 @@ void LLAgent::processAgentDropGroup(LLMessageSystem *msg, void **) // Remove the group if it already exists remove it and add the new data to pick up changes. LLGroupData gd; gd.mID = group_id; - std::vector::iterator found_it = std::find(gAgent.mGroups.begin(), gAgent.mGroups.end(), gd); - if (found_it != gAgent.mGroups.end()) + auto found_it = std::find(gAgent.mGroups.cbegin(), gAgent.mGroups.cend(), gd); + if (found_it != gAgent.mGroups.cend()) { gAgent.mGroups.erase(found_it); if (gAgent.getGroupID() == group_id) @@ -3437,12 +3534,12 @@ void LLAgent::processAgentDropGroup(LLMessageSystem *msg, void **) } } -class LLAgentDropGroupViewerNode : public LLHTTPNode +class LLAgentDropGroupViewerNode final : public LLHTTPNode { - virtual void post( + void post( LLHTTPNode::ResponsePtr response, const LLSD& context, - const LLSD& input) const + const LLSD& input) const override { if ( @@ -3469,11 +3566,8 @@ class LLAgentDropGroupViewerNode : public LLHTTPNode //there is only one set of data in the AgentData block LLSD agent_data = body["AgentData"][0]; - LLUUID agent_id; - LLUUID group_id; - - agent_id = agent_data["AgentID"].asUUID(); - group_id = agent_data["GroupID"].asUUID(); + LLUUID agent_id = agent_data["AgentID"].asUUID(); + LLUUID group_id = agent_data["GroupID"].asUUID(); if (agent_id != gAgentID) { @@ -3488,8 +3582,8 @@ class LLAgentDropGroupViewerNode : public LLHTTPNode // and add the new data to pick up changes. LLGroupData gd; gd.mID = group_id; - std::vector::iterator found_it = std::find(gAgent.mGroups.begin(), gAgent.mGroups.end(), gd); - if (found_it != gAgent.mGroups.end()) + auto found_it = std::find(gAgent.mGroups.cbegin(), gAgent.mGroups.cend(), gd); + if (found_it != gAgent.mGroups.cend()) { gAgent.mGroups.erase(found_it); if (gAgent.getGroupID() == group_id) @@ -3560,8 +3654,8 @@ void LLAgent::processAgentGroupDataUpdate(LLMessageSystem *msg, void **) { need_floater_update = true; // Remove the group if it already exists remove it and add the new data to pick up changes. - std::vector::iterator found_it = std::find(gAgent.mGroups.begin(), gAgent.mGroups.end(), group); - if (found_it != gAgent.mGroups.end()) + auto found_it = std::find(gAgent.mGroups.cbegin(), gAgent.mGroups.cend(), group); + if (found_it != gAgent.mGroups.cend()) { gAgent.mGroups.erase(found_it); } @@ -3575,12 +3669,12 @@ void LLAgent::processAgentGroupDataUpdate(LLMessageSystem *msg, void **) } -class LLAgentGroupDataUpdateViewerNode : public LLHTTPNode +class LLAgentGroupDataUpdateViewerNode final : public LLHTTPNode { - virtual void post( + void post( LLHTTPNode::ResponsePtr response, const LLSD& context, - const LLSD& input) const + const LLSD& input) const override { LLSD body = input["body"]; if(body.has("body")) @@ -3620,8 +3714,8 @@ class LLAgentGroupDataUpdateViewerNode : public LLHTTPNode { need_floater_update = true; // Remove the group if it already exists remove it and add the new data to pick up changes. - std::vector::iterator found_it = std::find(gAgent.mGroups.begin(), gAgent.mGroups.end(), group); - if (found_it != gAgent.mGroups.end()) + auto found_it = std::find(gAgent.mGroups.cbegin(), gAgent.mGroups.cend(), group); + if (found_it != gAgent.mGroups.cend()) { gAgent.mGroups.erase(found_it); } @@ -3822,7 +3916,7 @@ void LLAgent::processAgentCachedTextureResponse(LLMessageSystem *mesgsys, void * return; } - if (gAgentAvatarp->isEditingAppearance()) + if (isAgentAvatarValid() && gAgentAvatarp->isEditingAppearance()) { // ignore baked textures when in customize mode return; @@ -3953,6 +4047,7 @@ void LLAgent::clearVisualParams(void *data) // protected bool LLAgent::teleportCore(bool is_local) { + LL_INFOS("Teleport") << "In teleport core!" << LL_ENDL; if ((TELEPORT_NONE != mTeleportState) && (mTeleportState != TELEPORT_PENDING)) { LL_WARNS() << "Attempt to teleport when already teleporting." << LL_ENDL; @@ -3970,7 +4065,7 @@ bool LLAgent::teleportCore(bool is_local) // Stop all animation before actual teleporting if (isAgentAvatarValid()) { - for ( LLVOAvatar::AnimIterator anim_it= gAgentAvatarp->mPlayingAnimations.begin(); + for ( auto anim_it= gAgentAvatarp->mPlayingAnimations.begin(); anim_it != gAgentAvatarp->mPlayingAnimations.end(); ++anim_it) { @@ -3989,8 +4084,7 @@ bool LLAgent::teleportCore(bool is_local) LLFloaterWorldMap::hide(); // hide land floater too - it'll be out of date - if (LLFloaterLand::findInstance()) - LLFloaterLand::hideInstance(); + if (LLFloaterLand::findInstance()) LLFloaterLand::hideInstance(); LLViewerParcelMgr::getInstance()->deselectLand(); LLViewerMediaFocus::getInstance()->clearFocus(); @@ -4431,6 +4525,7 @@ void LLAgent::setTeleportState(ETeleportState state) { case TELEPORT_NONE: mbTeleportKeepsLookAt = false; + mIsCrossingRegion = false; // Attachments getting lost on TP; finished TP break; case TELEPORT_MOVING: @@ -4763,7 +4858,7 @@ void LLAgent::sendAgentSetAppearance() // This means the baked texture IDs on the server will be untouched. // Once all textures are baked, another AvatarAppearance message will be sent to update the TEs msg->nextBlockFast(_PREHASH_ObjectData); - gMessageSystem->addBinaryDataFast(_PREHASH_TextureEntry, NULL, 0); + gMessageSystem->addBinaryDataFast(_PREHASH_TextureEntry, nullptr, 0); } @@ -4786,9 +4881,7 @@ void LLAgent::sendAgentSetAppearance() } LL_INFOS() << "Avatar XML num VisualParams transmitted = " << transmitted_params << LL_ENDL; - if(transmitted_params < 218) { - LLNotificationsUtil::add("SGIncompleteAppearance"); - } + if (transmitted_params < 218) LLNotificationsUtil::add("SGIncompleteAppearance"); sendReliableMessage(); } @@ -4803,8 +4896,96 @@ void LLAgent::sendAgentDataUpdateRequest() void LLAgent::sendAgentUserInfoRequest() { - if(getID().isNull()) + std::string cap; + + if (getID().isNull()) return; // not logged in + + if (mRegionp) + cap = mRegionp->getCapability("UserInfo"); + + if (!cap.empty()) + { + LLHTTPClient::get(cap, new LLCoroResponder( + boost::bind(&LLAgent::requestAgentUserInfoCoro, this, _1))); + } + else + { + sendAgentUserInfoRequestMessage(); + } +} + +void LLAgent::requestAgentUserInfoCoro(const LLCoroResponder& responder) +{ + const auto& result = responder.getContent(); + const auto& status = responder.getStatus(); + + if (!responder.isGoodStatus(status)) + { + LL_WARNS("UserInfo") << "Failed to get user information: " << result["message"] << "Status " << status << " Reason: " << responder.getReason() << LL_ENDL; + return; + } + + bool im_via_email; + bool is_verified_email; + std::string email; + std::string dir_visibility; + + im_via_email = result["im_via_email"].asBoolean(); + is_verified_email = result["is_verified"].asBoolean(); + email = result["email"].asString(); + dir_visibility = result["directory_visibility"].asString(); + + // TODO: This should probably be changed. I'm not entirely comfortable + // having LLAgent interact directly with the UI in this way. + LLFloaterPreference::updateUserInfo(dir_visibility, im_via_email, email, is_verified_email); + LLFloaterPostcard::updateUserInfo(email); +} + +void LLAgent::sendAgentUpdateUserInfo(bool im_via_email, const std::string& directory_visibility) +{ + std::string cap; + + if (getID().isNull()) + return; // not logged in + + if (mRegionp) + cap = mRegionp->getCapability("UserInfo"); + + if (!cap.empty()) + { + LLSD body(LLSDMap + ("dir_visibility", LLSD::String(directory_visibility)) + ("im_via_email", LLSD::Boolean(im_via_email))); + LLHTTPClient::post(cap, body, new LLCoroResponder( + boost::bind(&LLAgent::updateAgentUserInfoCoro, this, _1))); + } + else + { + sendAgentUpdateUserInfoMessage(im_via_email, directory_visibility); + } +} + + +void LLAgent::updateAgentUserInfoCoro(const LLCoroResponder& responder) +{ + const auto& result = responder.getContent(); + const auto& status = responder.getStatus(); + + if (!responder.isGoodStatus(status)) + { + LL_WARNS("UserInfo") << "Failed to set user information." << LL_ENDL; + } + else if (!result["success"].asBoolean()) + { + LL_WARNS("UserInfo") << "Failed to set user information: " << result["message"] << LL_ENDL; + } +} + +// deprecated: +// May be removed when UserInfo cap propagates to all simhosts in grid +void LLAgent::sendAgentUserInfoRequestMessage() +{ gMessageSystem->newMessageFast(_PREHASH_UserInfoRequest); gMessageSystem->nextBlockFast(_PREHASH_AgentData); gMessageSystem->addUUIDFast(_PREHASH_AgentID, getID()); @@ -4812,6 +4993,21 @@ void LLAgent::sendAgentUserInfoRequest() sendReliableMessage(); } +void LLAgent::sendAgentUpdateUserInfoMessage(bool im_via_email, const std::string& directory_visibility) +{ + gMessageSystem->newMessageFast(_PREHASH_UpdateUserInfo); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, getID()); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, getSessionID()); + gMessageSystem->nextBlockFast(_PREHASH_UserData); + gMessageSystem->addBOOLFast(_PREHASH_IMViaEMail, im_via_email); + gMessageSystem->addString("DirectoryVisibility", directory_visibility); + gAgent.sendReliableMessage(); + +} +// end deprecated +//------ + void LLAgent::observeFriends() { if(!mFriendObserver) @@ -4879,18 +5075,6 @@ const void LLAgent::getTeleportSourceSLURL(LLSLURL& slurl) const slurl = *mTeleportSourceSLURL; } -void LLAgent::sendAgentUpdateUserInfo(bool im_via_email, const std::string& directory_visibility ) -{ - gMessageSystem->newMessageFast(_PREHASH_UpdateUserInfo); - gMessageSystem->nextBlockFast(_PREHASH_AgentData); - gMessageSystem->addUUIDFast(_PREHASH_AgentID, getID()); - gMessageSystem->addUUIDFast(_PREHASH_SessionID, getSessionID()); - gMessageSystem->nextBlockFast(_PREHASH_UserData); - gMessageSystem->addBOOLFast(_PREHASH_IMViaEMail, im_via_email); - gMessageSystem->addString("DirectoryVisibility", directory_visibility); - gAgent.sendReliableMessage(); -} - void LLAgent::dumpGroupInfo() { LL_INFOS() << "group " << mGroupName << LL_ENDL; @@ -4973,6 +5157,7 @@ void LLAgent::onFoundLureDestination(LLSimInfo *siminfo) msg.append(llformat(" (%s)", maturity.c_str())); } LLChat chat(msg); + chat.mSourceType = CHAT_SOURCE_SYSTEM; LLFloaterChat::addChat(chat); } else diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h index 17042fd45..6fd97b679 100644 --- a/indra/newview/llagent.h +++ b/indra/newview/llagent.h @@ -33,8 +33,6 @@ #ifndef LL_LLAGENT_H #define LL_LLAGENT_H -#include - #include "indra_constants.h" #include "llevent.h" // LLObservable base class #include "llagentconstants.h" @@ -46,7 +44,6 @@ #include "llinventorymodel.h" #include "v3dmath.h" -#include #include #include @@ -70,6 +67,7 @@ class LLAgentAccess; class LLSLURL; class LLSimInfo; class LLTeleportRequest; +struct LLCoroResponder; typedef boost::shared_ptr LLTeleportRequestPtr; @@ -100,7 +98,7 @@ struct LLGroupData //------------------------------------------------------------------------ // LLAgent //------------------------------------------------------------------------ -class LLAgent : public LLOldEvents::LLObservable +class LLAgent final : public LLOldEvents::LLObservable { LOG_CLASS(LLAgent); @@ -248,7 +246,7 @@ public: void changeParcels(); // called by LLViewerParcelMgr when we cross a parcel boundary // Register a boost callback to be called when the agent changes parcels - typedef boost::function parcel_changed_callback_t; + typedef std::function parcel_changed_callback_t; boost::signals2::connection addParcelChangedCallback(parcel_changed_callback_t); private: @@ -593,13 +591,14 @@ public: public: BOOL getAutoPilot() const { return mAutoPilot; } LLVector3d getAutoPilotTargetGlobal() const { return mAutoPilotTargetGlobal; } - LLUUID getAutoPilotLeaderID() const { return mLeaderID; } + const LLUUID& getAutoPilotLeaderID() const { return mLeaderID; } F32 getAutoPilotStopDistance() const { return mAutoPilotStopDistance; } F32 getAutoPilotTargetDist() const { return mAutoPilotTargetDist; } BOOL getAutoPilotUseRotation() const { return mAutoPilotUseRotation; } LLVector3 getAutoPilotTargetFacing() const { return mAutoPilotTargetFacing; } F32 getAutoPilotRotationThreshold() const { return mAutoPilotRotationThreshold; } - std::string getAutoPilotBehaviorName() const { return mAutoPilotBehaviorName; } + const std::string& getAutoPilotBehaviorName() const { return mAutoPilotBehaviorName; } + bool getAutoPilotNoProgress() const; void startAutoPilotGlobal(const LLVector3d &pos_global, const std::string& behavior_name = std::string(), @@ -739,6 +738,13 @@ private: ** ** *******************************************************************************/ + // Attachments getting lost on TP +public: + void setIsCrossingRegion(bool is_crossing) { mIsCrossingRegion = is_crossing; } + bool isCrossingRegion() const { return mIsCrossingRegion; } +private: + bool mIsCrossingRegion; + // Build public: bool canEditParcel() const { return mCanEditParcel; } @@ -778,7 +784,7 @@ public: void requestEnterGodMode(); void requestLeaveGodMode(); - typedef boost::function god_level_change_callback_t; + typedef std::function god_level_change_callback_t; typedef boost::signals2::signal god_level_change_signal_t; typedef boost::signals2::connection god_level_change_slot_t; @@ -800,7 +806,7 @@ public: bool canAccessMature() const; bool canAccessAdult() const; bool canAccessMaturityInRegion( U64 region_handle ) const; - bool canAccessMaturityAtGlobal( LLVector3d pos_global ) const; + bool canAccessMaturityAtGlobal( const LLVector3d& pos_global ) const; bool prefersPG() const; bool prefersMature() const; bool prefersAdult() const; @@ -957,9 +963,17 @@ public: void sendAgentSetAppearance(); void sendAgentDataUpdateRequest(); void sendAgentUserInfoRequest(); - // IM to Email and Online visibility + +// IM to Email and Online visibility void sendAgentUpdateUserInfo(bool im_to_email, const std::string& directory_visibility); +private: + void requestAgentUserInfoCoro(const LLCoroResponder& responder); + void updateAgentUserInfoCoro(const LLCoroResponder& responder); + // DEPRECATED: may be removed when User Info cap propagates + void sendAgentUserInfoRequestMessage(); + void sendAgentUpdateUserInfoMessage(bool im_via_email, const std::string& directory_visibility); + //-------------------------------------------------------------------- // Receive //-------------------------------------------------------------------- diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp index bb3317005..727a59f4b 100644 --- a/indra/newview/llagentcamera.cpp +++ b/indra/newview/llagentcamera.cpp @@ -289,11 +289,6 @@ LLAgentCamera::~LLAgentCamera() //----------------------------------------------------------------------------- void LLAgentCamera::resetView(BOOL reset_camera, BOOL change_camera) { - if (gAgent.getAutoPilot()) - { - gAgent.stopAutoPilot(TRUE); - } - LLSelectMgr::getInstance()->unhighlightAll(); // By popular request, keep land selection while walking around. JC @@ -2517,13 +2512,13 @@ void LLAgentCamera::changeCameraToCustomizeAvatar() gAgent.sendAnimationRequest(ANIM_AGENT_CUSTOMIZE, ANIM_REQUEST_START); gAgent.setCustomAnim(TRUE); gAgentAvatarp->startMotion(ANIM_AGENT_CUSTOMIZE); - } - LLMotion* turn_motion = gAgentAvatarp->findMotion(ANIM_AGENT_CUSTOMIZE); + LLMotion* turn_motion = gAgentAvatarp->findMotion(ANIM_AGENT_CUSTOMIZE); - if (turn_motion) - { - // delay camera animation long enough to play through turn animation - setAnimationDuration(turn_motion->getDuration() + CUSTOMIZE_AVATAR_CAMERA_ANIM_SLOP); + if (turn_motion) + { + // delay camera animation long enough to play through turn animation + setAnimationDuration(turn_motion->getDuration() + CUSTOMIZE_AVATAR_CAMERA_ANIM_SLOP); + } } } // diff --git a/indra/newview/llaisapi.cpp b/indra/newview/llaisapi.cpp index c284f33e8..453b68080 100644 --- a/indra/newview/llaisapi.cpp +++ b/indra/newview/llaisapi.cpp @@ -35,13 +35,12 @@ #include "llviewerregion.h" #include "llinventoryobserver.h" #include "llviewercontrol.h" -#include ///---------------------------------------------------------------------------- /// Classes for AISv3 support. ///---------------------------------------------------------------------------- -class AISCommand : public LLHTTPClient::ResponderWithResult +class AISCommand final : public LLHTTPClient::ResponderWithCompleted { public: typedef boost::function command_func_type; @@ -60,35 +59,28 @@ public: (mCommandFunc = func)(); } - char const* getName(void) const + char const* getName(void) const override { return mName; } void markComplete() - { - mRetryPolicy->onSuccess(); - } - -protected: - /* virtual */ - void httpSuccess() { // Command func holds a reference to self, need to release it // after a success or final failure. mCommandFunc = no_op; - AISAPI::InvokeAISCommandCoro(this, getURL(), mTargetId, getContent(), mCompletionFunc, (AISAPI::COMMAND_TYPE)mType); + mRetryPolicy->onSuccess(); } - /*virtual*/ - void httpFailure() + void malformedResponse() { mStatus = HTTP_INTERNAL_ERROR_OTHER; mReason = llformat("Malformed response contents (original code: %d)", mStatus); } + + bool onFailure() { - LL_WARNS("Inventory") << dumpResponse() << LL_ENDL; - S32 status = getStatus(); - const AIHTTPReceivedHeaders& headers = getResponseHeaders(); - mRetryPolicy->onFailure(status, headers); + bool retry = mStatus != HTTP_INTERNAL_ERROR_OTHER && mStatus != 410; // We handle these and stop + LL_WARNS("Inventory") << "Inventory error: " << dumpResponse() << LL_ENDL; + if (retry) mRetryPolicy->onFailure(mStatus, getResponseHeaders()); F32 seconds_to_wait; - if (mRetryPolicy->shouldRetry(seconds_to_wait)) + if (retry && mRetryPolicy->shouldRetry(seconds_to_wait)) { doAfterInterval(mCommandFunc,seconds_to_wait); } @@ -99,6 +91,13 @@ protected: // *TODO: Notify user? This seems bad. mCommandFunc = no_op; } + return retry; + } + +protected: + void httpCompleted() override + { + AISAPI::InvokeAISCommandCoro(this, getURL(), mTargetId, getContent(), mCompletionFunc, (AISAPI::COMMAND_TYPE)mType); } command_func_type mCommandFunc; @@ -313,31 +312,97 @@ void AISAPI::UpdateItem(const LLUUID &itemId, const LLSD &updates, completion_t boost::intrusive_ptr< AISCommand > responder = new AISCommand(UPDATEITEM, "UpdateItem",itemId, callback); responder->run(boost::bind(&LLHTTPClient::patch, url, updates, responder/*,*/ DEBUG_CURLIO_PARAM(debug_off), keep_alive, (AIStateMachine*)NULL, 0)); } -void AISAPI::InvokeAISCommandCoro(LLHTTPClient::ResponderWithResult* responder, - std::string url, +void AISAPI::InvokeAISCommandCoro(AISCommand* responder, + std::string url, LLUUID targetId, LLSD result, completion_t callback, COMMAND_TYPE type) { + LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL; + + auto status = responder->getStatus(); + + if (!responder->isGoodStatus(status) || !result.isMap()) { if (!result.isMap()) { - responder->failureResult(400, "Malformed response contents", result); - return; + responder->malformedResponse(); } - ((AISCommand*)responder)->markComplete(); + else if (status == 410) //GONE + { + // Item does not exist or was already deleted from server. + // parent folder is out of sync + if (type == REMOVECATEGORY) + { + LLViewerInventoryCategory *cat = gInventory.getCategory(targetId); + if (cat) + { + LL_WARNS("Inventory") << "Purge failed for '" << cat->getName() + << "' local version:" << cat->getVersion() + << " since folder no longer exists at server. Descendent count: server == " << cat->getDescendentCount() + << ", viewer == " << cat->getViewerDescendentCount() + << LL_ENDL; + gInventory.fetchDescendentsOf(cat->getParentUUID()); + // Note: don't delete folder here - contained items will be deparented (or deleted) + // and since we are clearly out of sync we can't be sure we won't get rid of something we need. + // For example folder could have been moved or renamed with items intact, let it fetch first. + } + } + else if (type == REMOVEITEM) + { + LLViewerInventoryItem *item = gInventory.getItem(targetId); + if (item) + { + LL_WARNS("Inventory") << "Purge failed for '" << item->getName() + << "' since item no longer exists at server." << LL_ENDL; + gInventory.fetchDescendentsOf(item->getParentUUID()); + // since item not on the server and exists at viewer, so it needs an update at the least, + // so delete it, in worst case item will be refetched with new params. + gInventory.onObjectDeletedFromServer(targetId); + } + } + } + // Keep these statuses accounted for in the responder too + if (responder->onFailure()) // If we're retrying, exit early. + return; } + else responder->markComplete(); gInventory.onAISUpdateReceived("AISCommand", result); if (callback && callback != nullptr) { - LLUUID id(LLUUID::null); - - if (result.has("category_id") && (type == COPYLIBRARYCATEGORY)) +// [SL:KB] - Patch: Appearance-SyncAttach | Checked: Catznip-3.7 + uuid_list_t ids; + switch (type) { - id = result["category_id"]; + case COPYLIBRARYCATEGORY: + if (result.has("category_id")) + { + ids.insert(result["category_id"]); + } + break; + case COPYINVENTORY: + { + AISUpdate::parseUUIDArray(result, "_created_items", ids); + AISUpdate::parseUUIDArray(result, "_created_categories", ids); + } + break; + default: + break; } - callback(id); + // If we were feeling daring we'd call LLInventoryCallback::fire for every item but it would take additional work to investigate whether all LLInventoryCallback derived classes + // were designed to handle multiple fire calls (with legacy link creation only one would ever fire per link creation) so we'll be cautious and only call for the first one for now + // (note that the LL code as written below will always call fire once with the NULL UUID for anything but CopyLibraryCategoryCommand so even the above is an improvement) + callback( (!ids.empty()) ? *ids.begin() : LLUUID::null); +// [/SL:KB] +// LLUUID id(LLUUID::null); +// +// if (result.has("category_id") && (type == COPYLIBRARYCATEGORY)) +// { +// id = result["category_id"]; +// } +// +// callback(id); } } @@ -374,18 +439,17 @@ void AISUpdate::parseMeta(const LLSD& update) // parse _categories_removed -> mObjectsDeletedIds uuid_list_t cat_ids; parseUUIDArray(update,"_categories_removed",cat_ids); - for (uuid_list_t::const_iterator it = cat_ids.begin(); - it != cat_ids.end(); ++it) + for (auto cat_id : cat_ids) { - LLViewerInventoryCategory *cat = gInventory.getCategory(*it); + LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id); if(cat) { mCatDescendentDeltas[cat->getParentUUID()]--; - mObjectsDeletedIds.insert(*it); + mObjectsDeletedIds.insert(cat_id); } else { - LL_WARNS("Inventory") << "removed category not found " << *it << LL_ENDL; + LL_WARNS("Inventory") << "removed category not found " << cat_id << LL_ENDL; } } @@ -393,36 +457,34 @@ void AISUpdate::parseMeta(const LLSD& update) uuid_list_t item_ids; parseUUIDArray(update,"_category_items_removed",item_ids); parseUUIDArray(update,"_removed_items",item_ids); - for (uuid_list_t::const_iterator it = item_ids.begin(); - it != item_ids.end(); ++it) + for (auto item_id : item_ids) { - LLViewerInventoryItem *item = gInventory.getItem(*it); + LLViewerInventoryItem *item = gInventory.getItem(item_id); if(item) { mCatDescendentDeltas[item->getParentUUID()]--; - mObjectsDeletedIds.insert(*it); + mObjectsDeletedIds.insert(item_id); } else { - LL_WARNS("Inventory") << "removed item not found " << *it << LL_ENDL; + LL_WARNS("Inventory") << "removed item not found " << item_id << LL_ENDL; } } // parse _broken_links_removed -> mObjectsDeletedIds uuid_list_t broken_link_ids; parseUUIDArray(update,"_broken_links_removed",broken_link_ids); - for (uuid_list_t::const_iterator it = broken_link_ids.begin(); - it != broken_link_ids.end(); ++it) + for (auto broken_link_id : broken_link_ids) { - LLViewerInventoryItem *item = gInventory.getItem(*it); + LLViewerInventoryItem *item = gInventory.getItem(broken_link_id); if(item) { mCatDescendentDeltas[item->getParentUUID()]--; - mObjectsDeletedIds.insert(*it); + mObjectsDeletedIds.insert(broken_link_id); } else { - LL_WARNS("Inventory") << "broken link not found " << *it << LL_ENDL; + LL_WARNS("Inventory") << "broken link not found " << broken_link_id << LL_ENDL; } } @@ -764,7 +826,7 @@ void AISUpdate::parseEmbeddedCategories(const LLSD& categories) void AISUpdate::doUpdate() { - // Do version/descendent accounting. + // Do version/descendant accounting. for (std::map::const_iterator catit = mCatDescendentDeltas.begin(); catit != mCatDescendentDeltas.end(); ++catit) { @@ -785,7 +847,7 @@ void AISUpdate::doUpdate() continue; } - // If we have a known descendent count, set that now. + // If we have a known descendant count, set that now. LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id); if (cat) { @@ -822,7 +884,7 @@ void AISUpdate::doUpdate() LLUUID category_id(update_it->first); LLPointer new_category = update_it->second; // Since this is a copy of the category *before* the accounting update, above, - // we need to transfer back the updated version/descendent count. + // we need to transfer back the updated version/descendant count. LLViewerInventoryCategory* curr_cat = gInventory.getCategory(new_category->getUUID()); if (!curr_cat) { @@ -866,21 +928,19 @@ void AISUpdate::doUpdate() } // DELETE OBJECTS - for (uuid_list_t::const_iterator del_it = mObjectsDeletedIds.begin(); - del_it != mObjectsDeletedIds.end(); ++del_it) + for (auto deleted_id : mObjectsDeletedIds) { - LL_DEBUGS("Inventory") << "deleted item " << *del_it << LL_ENDL; - gInventory.onObjectDeletedFromServer(*del_it, false, false, false); + LL_DEBUGS("Inventory") << "deleted item " << deleted_id << LL_ENDL; + gInventory.onObjectDeletedFromServer(deleted_id, false, false, false); } // TODO - how can we use this version info? Need to be sure all // changes are going through AIS first, or at least through // something with a reliable responder. - for (uuid_int_map_t::iterator ucv_it = mCatVersionsUpdated.begin(); - ucv_it != mCatVersionsUpdated.end(); ++ucv_it) + for (auto& ucv_it : mCatVersionsUpdated) { - const LLUUID id = ucv_it->first; - S32 version = ucv_it->second; + const LLUUID id = ucv_it.first; + S32 version = ucv_it.second; LLViewerInventoryCategory *cat = gInventory.getCategory(id); LL_DEBUGS("Inventory") << "cat version update " << cat->getName() << " to version " << cat->getVersion() << LL_ENDL; if (cat->getVersion() != version) @@ -896,7 +956,16 @@ void AISUpdate::doUpdate() // inventory COF is maintained on the viewer through calls to // LLInventoryModel::accountForUpdate when a changing operation // is performed. This occasionally gets out of sync however. - cat->setVersion(version); + if (version != LLViewerInventoryCategory::VERSION_UNKNOWN) + { + cat->setVersion(version); + } + else + { + // We do not account for update if version is UNKNOWN, so we shouldn't rise version + // either or viewer will get stuck on descendants count -1, try to refetch folder instead + cat->fetch(); + } } } diff --git a/indra/newview/llaisapi.h b/indra/newview/llaisapi.h index 7c8293a39..b37edbc78 100644 --- a/indra/newview/llaisapi.h +++ b/indra/newview/llaisapi.h @@ -72,7 +72,7 @@ private: static std::string getInvCap(); static std::string getLibCap(); - static void InvokeAISCommandCoro( LLHTTPClient::ResponderWithResult* responder, + static void InvokeAISCommandCoro(class AISCommand* responder, std::string url, LLUUID targetId, LLSD body, completion_t callback, COMMAND_TYPE type); }; @@ -84,7 +84,10 @@ public: void parseUpdate(const LLSD& update); void parseMeta(const LLSD& update); void parseContent(const LLSD& update); - void parseUUIDArray(const LLSD& content, const std::string& name, uuid_list_t& ids); +// [SL:KB] - Patch: Appearance-SyncAttach | Checked: Catznip-3.7 + static void parseUUIDArray(const LLSD& content, const std::string& name, uuid_list_t& ids); +// [/SL:KB] +// void parseUUIDArray(const LLSD& content, const std::string& name, uuid_list_t& ids); void parseLink(const LLSD& link_map); void parseItem(const LLSD& link_map); void parseCategory(const LLSD& link_map); diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index dc7665727..6976f0050 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -2841,6 +2841,12 @@ void LLAppearanceMgr::wearInventoryCategory(LLInventoryCategory* category, bool { if(!category) return; + // Attachments getting lost on TP: + // We'll be sending the outfit change request to our current region, + // so we'll learn them if they've been sending bad kills. + // We don't take kindly to that sorta behaviour round these parts. + gAgent.setIsCrossingRegion(false); + selfClearPhases(); selfStartPhase("wear_inventory_category"); @@ -4178,7 +4184,7 @@ LLUUID LLAppearanceMgr::makeNewOutfitLinks(const std::string& new_folder_name, L // 2) Stuff with requests via makeLink and makeCopy // 3) Call dispatch() // 4) Let the LLPointer go out of scope. -class LLCreateLegacyOutfit : public LLBoostFuncInventoryCallbackFireOnce +class LLCreateLegacyOutfit final : public LLBoostFuncInventoryCallbackFireOnce { public: LLCreateLegacyOutfit(const LLUUID& folder_id, inventory_func_type fire_func, nullary_func_type destroy_func = no_op) : diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 56c2c6550..77382fd07 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -47,6 +47,7 @@ #include "llagent.h" #include "llagentcamera.h" #include "llagentwearables.h" +#include "llimprocessing.h" #include "llwindow.h" #include "llviewerstats.h" #include "llmarketplacefunctions.h" @@ -95,6 +96,7 @@ // Linden library includes #include "llavatarnamecache.h" #include "lldiriterator.h" +#include "llexperiencecache.h" #include "llimagej2c.h" #include "llmemory.h" #include "llprimitive.h" @@ -189,6 +191,7 @@ #include "llviewerthrottle.h" #include "llparcel.h" #include "llviewerassetstats.h" +#include "NACLantispam.h" #include "llmainlooprepeater.h" @@ -428,27 +431,6 @@ static void ui_audio_callback(const LLUUID& uuid) } } -void request_initial_instant_messages() -{ - static BOOL requested = FALSE; - if (!requested - && gMessageSystem - && LLMuteList::getInstance()->isLoaded() - && isAgentAvatarValid()) - { - // Auto-accepted inventory items may require the avatar object - // to build a correct name. Likewise, inventory offers from - // muted avatars require the mute list to properly mute. - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_RetrieveInstantMessages); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - gAgent.sendReliableMessage(); - requested = TRUE; - } -} - // Use these strictly for things that are constructed at startup, // or for things that are performance critical. JC static void settings_to_globals() @@ -726,6 +708,8 @@ void LLAppViewer::initCrashReporting() annotations.emplace("sentry[contexts][app][app_version]", LLVersionInfo::getVersion()); annotations.emplace("sentry[contexts][app][app_build]", LLVersionInfo::getChannelAndVersion()); + annotations.emplace("sentry[release]", LLVersionInfo::getChannelAndVersion()); + annotations.emplace("sentry[tags][second_instance]", fmt::to_string(isSecondInstance())); //annotations.emplace("sentry[tags][bitness]", fmt::to_string(ADDRESS_SIZE)); annotations.emplace("sentry[tags][bitness]", @@ -738,7 +722,6 @@ void LLAppViewer::initCrashReporting() // Optional arguments to pass to the handler std::vector arguments; - arguments.push_back("--no-upload-gzip"); arguments.push_back("--no-rate-limit"); arguments.push_back("--monitor-self"); @@ -2286,7 +2269,9 @@ bool LLAppViewer::initConfiguration() LL_INFOS() << "Loading settings file list" << settings_file_list << LL_ENDL; if (0 == settings_control.loadFromFile(settings_file_list)) { - LL_ERRS() << "Cannot load default configuration file " << settings_file_list << LL_ENDL; + OSMessageBox("Cannot load default configuration file " + settings_file_list + " The installation may be corrupted.", + LLStringUtil::null,OSMB_OK); + return false; } mSettingsLocationList = settings_control.getLLSD("Locations"); @@ -4045,7 +4030,7 @@ void LLAppViewer::idle() // here. { LAZY_FT("request_initial_instant_messages"); - request_initial_instant_messages(); + LLIMProcessing::requestOfflineMessages(); } /////////////////////////////////// @@ -4176,6 +4161,7 @@ void LLAppViewer::idle() // floating throughout the various object lists. // idleNameCache(); + if (gAgent.getRegion()) LLExperienceCache::instance().idleCoro(); gFrameStats.start(LLFrameStats::IDLE_NETWORK); stop_glerror(); @@ -4204,6 +4190,7 @@ void LLAppViewer::idle() gIdleCallbacks.callFunctions(); gInventory.idleNotifyObservers(); + if (auto antispam = NACLAntiSpamRegistry::getIfExists()) antispam->idle(); } // Metrics logging (LLViewerAssetStats, etc.) @@ -4840,6 +4827,12 @@ void LLAppViewer::disconnectViewer() } saveNameCache(); + if (LLExperienceCache::instanceExists()) + { + // TODO: LLExperienceCache::cleanup() logic should be moved to + // cleanupSingleton(). + LLExperienceCache::instance().cleanup(); + } // close inventory interface, close all windows LLPanelMainInventory::cleanup(); diff --git a/indra/newview/llassetuploadqueue.cpp b/indra/newview/llassetuploadqueue.cpp index 88695b2d1..67c7fa55c 100644 --- a/indra/newview/llassetuploadqueue.cpp +++ b/indra/newview/llassetuploadqueue.cpp @@ -171,6 +171,7 @@ void LLAssetUploadQueue::request(LLAssetUploadQueueSupplier** supplier) body["item_id"] = data.mItemId; body["is_script_running"] = data.mIsRunning; body["target"] = data.mIsTargetMono? "mono" : "lsl2"; + body["experience"] = data.mExperienceId; std::string url = ""; LLViewerObject* object = gObjectList.findObject(data.mTaskId); @@ -194,7 +195,8 @@ void LLAssetUploadQueue::queue(const std::string& filename, const LLUUID& queue_id, U8* script_data, U32 data_size, - std::string script_name) + std::string script_name, + const LLUUID& experience_id) { UploadData data; data.mTaskId = task_id; @@ -206,6 +208,7 @@ void LLAssetUploadQueue::queue(const std::string& filename, data.mData = script_data; data.mDataSize = data_size; data.mScriptName = script_name; + data.mExperienceId = experience_id; mQueue.push_back(data); diff --git a/indra/newview/llassetuploadqueue.h b/indra/newview/llassetuploadqueue.h index 930dc72a7..bc6c11cda 100644 --- a/indra/newview/llassetuploadqueue.h +++ b/indra/newview/llassetuploadqueue.h @@ -56,7 +56,8 @@ public: const LLUUID& queue_id, U8* data, U32 data_size, - std::string script_name); + std::string script_name, + const LLUUID& experience_id); bool isEmpty() const {return mQueue.empty();} @@ -75,6 +76,7 @@ private: U8* mData; U32 mDataSize; std::string mScriptName; + LLUUID mExperienceId; }; // Ownership of mSupplier passed to currently waiting responder diff --git a/indra/newview/llattachmentsmgr.cpp b/indra/newview/llattachmentsmgr.cpp index 5395d42df..2be3da1d4 100644 --- a/indra/newview/llattachmentsmgr.cpp +++ b/indra/newview/llattachmentsmgr.cpp @@ -481,13 +481,6 @@ void LLAttachmentsMgr::onAttachmentArrived(const LLUUID& inv_item_id) bool expected = mAttachmentRequests.getTime(inv_item_id, timer); LLInventoryItem *item = gInventory.getItem(inv_item_id); - if (item && boost::algorithm::contains(item->getName(), " Bridge v") && gSavedSettings.getBOOL("SGDetachBridge")) - { - LL_INFOS() << "Bridge detected! detaching" << LL_ENDL; - LLVOAvatarSelf::detachAttachmentIntoInventory(item->getUUID()); - return; - } - if (!expected) { LL_WARNS() << "ATT Attachment was unexpected or arrived after " << MAX_ATTACHMENT_REQUEST_LIFETIME << " seconds: " @@ -505,6 +498,13 @@ void LLAttachmentsMgr::onAttachmentArrived(const LLUUID& inv_item_id) mCOFLinkBatchTimer.reset(); } mRecentlyArrivedAttachments.insert(inv_item_id); + + static const LLCachedControl detach_bridge("SGDetachBridge"); + if (detach_bridge && item && boost::algorithm::contains(item->getName(), " Bridge v")) + { + LL_INFOS() << "Bridge detected! detaching" << LL_ENDL; + LLVOAvatarSelf::detachAttachmentIntoInventory(item->getUUID()); + } } void LLAttachmentsMgr::onDetachRequested(const LLUUID& inv_item_id) diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp index f7eb591ac..3685ce21b 100644 --- a/indra/newview/llavataractions.cpp +++ b/indra/newview/llavataractions.cpp @@ -374,8 +374,8 @@ void LLAvatarActions::showProfile(const LLUUID& id, bool web) // static void LLAvatarActions::showProfiles(const uuid_vec_t& ids, bool web) { - for (uuid_vec_t::const_iterator it = ids.begin(); it != ids.end(); ++it) - showProfile(*it, web); + for (const auto& id : ids) + showProfile(id, web); } //static @@ -1197,7 +1197,7 @@ void LLAvatarActions::requestFriendship(const LLUUID& target_id, const std::stri calling_card_folder_id); LLSD args; - args["TO_NAME"] = target_name; + args["TO_NAME"] = getSLURL(target_id); LLSD payload; payload["from_id"] = target_id; @@ -1245,27 +1245,31 @@ bool LLAvatarActions::isAgentMappable(const LLUUID& agent_id) ); } -// static -void LLAvatarActions::copyUUIDs(const uuid_vec_t& ids) +void copy_from_ids(const uuid_vec_t& ids, std::function func) { std::string ids_string; const std::string& separator = LLTrans::getString("words_separator"); - for (uuid_vec_t::const_iterator it = ids.begin(); it != ids.end(); ++it) + for (const auto& id : ids) { - const LLUUID& id = *it; if (id.isNull()) continue; if (!ids_string.empty()) ids_string.append(separator); - ids_string.append(id.asString()); + ids_string.append(func(id)); } if (!ids_string.empty()) gViewerWindow->getWindow()->copyTextToClipboard(utf8str_to_wstring(ids_string)); } +// static +void LLAvatarActions::copyUUIDs(const uuid_vec_t& ids) +{ + copy_from_ids(ids, [](const LLUUID& id) { return id.asString(); }); +} + std::string LLAvatarActions::getSLURL(const LLUUID& id) { return llformat("secondlife:///app/agent/%s/about", id.asString().c_str()); diff --git a/indra/newview/llchatbar.cpp b/indra/newview/llchatbar.cpp index 32323b8f5..3d8dde517 100644 --- a/indra/newview/llchatbar.cpp +++ b/indra/newview/llchatbar.cpp @@ -72,6 +72,8 @@ #include "chatbar_as_cmdline.h" // [RLVa:KB] +#include "rlvcommon.h" +#include "rlvactions.h" #include "rlvhandler.h" // [/RLVa:KB] @@ -100,25 +102,24 @@ class LLChatBarGestureObserver : public LLGestureManagerObserver { public: LLChatBarGestureObserver(LLChatBar* chat_barp) : mChatBar(chat_barp){} - virtual ~LLChatBarGestureObserver() {} - virtual void changed() { mChatBar->refreshGestures(); } + virtual ~LLChatBarGestureObserver() = default; + void changed() override { mChatBar->refreshGestures(); } private: LLChatBar* mChatBar; }; - // // Functions // LLChatBar::LLChatBar() : LLPanel(), - mInputEditor(NULL), + mInputEditor(nullptr), mGestureLabelTimer(), mLastSpecialChatChannel(0), mIsBuilt(FALSE), - mGestureCombo(NULL), - mObserver(NULL) + mGestureCombo(nullptr), + mObserver(nullptr) { setIsChrome(TRUE); @@ -132,10 +133,14 @@ LLChatBar::~LLChatBar() { LLGestureMgr::instance().removeObserver(mObserver); delete mObserver; - mObserver = NULL; + mObserver = nullptr; // LLView destructor cleans up children } +//----------------------------------------------------------------------- +// Overrides +//----------------------------------------------------------------------- + BOOL LLChatBar::postBuild() { if (LLUICtrl* history_ctrl = findChild("History")) @@ -189,7 +194,7 @@ BOOL LLChatBar::handleKeyHere( KEY key, MASK mask ) else if (mask == MASK_SHIFT) { // whisper - sendChat( CHAT_TYPE_WHISPER ); + sendChat(CHAT_TYPE_WHISPER); handled = TRUE; } else if (mask == MASK_NONE) @@ -210,6 +215,11 @@ BOOL LLChatBar::handleKeyHere( KEY key, MASK mask ) return handled; } +void LLChatBar::onFocusLost() +{ + //stopChat(); +} + void LLChatBar::refresh() { // HACK: Leave the name of the gesture in place for a few seconds. @@ -242,17 +252,16 @@ void LLChatBar::refreshGestures() //store current selection so we can maintain it std::string cur_gesture = mGestureCombo->getValue().asString(); mGestureCombo->selectFirstItem(); - std::string label = mGestureCombo->getValue().asString();; + // clear mGestureCombo->clearRows(); // collect list of unique gestures std::map unique; - LLGestureMgr::item_map_t::const_iterator it; const LLGestureMgr::item_map_t& active_gestures = LLGestureMgr::instance().getActiveGestures(); - for (it = active_gestures.begin(); it != active_gestures.end(); ++it) + for (const auto& active_gesture : active_gestures) { - LLMultiGesture* gesture = (*it).second; + LLMultiGesture* gesture = active_gesture.second; if (gesture) { if (!gesture->mTrigger.empty()) @@ -262,11 +271,9 @@ void LLChatBar::refreshGestures() } } - // add unique gestures - std::map ::iterator it2; - for (it2 = unique.begin(); it2 != unique.end(); ++it2) + for (auto& it2 : unique) { - mGestureCombo->addSimpleElement((*it2).first); + mGestureCombo->addSimpleElement(it2.first); } mGestureCombo->sortByName(); @@ -316,12 +323,12 @@ void LLChatBar::setIgnoreArrowKeys(BOOL b) } } -BOOL LLChatBar::inputEditorHasFocus() +BOOL LLChatBar::inputEditorHasFocus() const { return mInputEditor && mInputEditor->hasFocus(); } -std::string LLChatBar::getCurrentChat() +std::string LLChatBar::getCurrentChat() const { return mInputEditor ? mInputEditor->getText() : LLStringUtil::null; } @@ -390,7 +397,7 @@ LLWString LLChatBar::stripChannelNumber(const LLWString &mesg, S32* channel) pos++; } - mLastSpecialChatChannel = strtol(wstring_to_utf8str(channel_string).c_str(), NULL, 10); + mLastSpecialChatChannel = strtol(wstring_to_utf8str(channel_string).c_str(), nullptr, 10); // if(mesg[1] == '-') mLastSpecialChatChannel = -mLastSpecialChatChannel; @@ -570,9 +577,12 @@ void LLChatBar::onInputEditorKeystroke() S32 length = raw_text.length(); - //if( (length > 0) && (raw_text[0] != '/') ) // forward slash is used for escape (eg. emote) sequences -// [RLVa:KB] - Checked: 2009-07-07 (RLVa-1.0.0d) - if ( (length > 0) && (raw_text[0] != '/') && (!gRlvHandler.hasBehaviour(RLV_BHVR_REDIRCHAT)) ) +// if( (length > 0) +// && (raw_text[0] != '/') // forward slash is used for escape (eg. emote) sequences +// && (raw_text[0] != ':') // colon is used in for MUD poses +// ) +// [RLVa:KB] - Checked: 2010-03-26 (RLVa-1.2.0b) | Modified: RLVa-1.0.0d + if ( (length > 0) && (raw_text[0] != '/') && (raw_text[0] != ':') && (!RlvActions::hasBehaviour(RLV_BHVR_REDIRCHAT)) ) // [/RLVa:KB] { gAgent.startTyping(); @@ -582,21 +592,6 @@ void LLChatBar::onInputEditorKeystroke() gAgent.stopTyping(); } - /* Doesn't work -- can't tell the difference between a backspace - that killed the selection vs. backspace at the end of line. - if (length > 1 - && text[0] == '/' - && key == KEY_BACKSPACE) - { - // the selection will already be deleted, but we need to trim - // off the character before - std::string new_text = raw_text.substr(0, length-1); - mInputEditor->setText( new_text ); - mInputEditor->setCursorToEnd(); - length = length - 1; - } - */ - KEY key = gKeyboard->currentKey(); // Ignore "special" keys, like backspace, arrows, etc. @@ -622,11 +617,6 @@ void LLChatBar::onInputEditorKeystroke() mInputEditor->setSelection(length, outlength); } } - - //LL_INFOS() << "GESTUREDEBUG " << trigger - // << " len " << length - // << " outlen " << out_str.getLength() - // << LL_ENDL; } } @@ -668,11 +658,11 @@ void LLChatBar::sendChatFromViewer(const std::string &utf8text, EChatType type, void LLChatBar::sendChatFromViewer(const LLWString &wtext, EChatType type, BOOL animate) { // Look for "/20 foo" channel chats. - S32 channel = 0; + S32 channel = gSavedSettings.getS32("AlchemyNearbyChatChannel"); LLWString out_text = stripChannelNumber(wtext, &channel); std::string utf8_out_text = wstring_to_utf8str(out_text); - std::string utf8_text = wstring_to_utf8str(wtext); + utf8_text = utf8str_trim(utf8_text); if (!utf8_text.empty()) { @@ -680,17 +670,12 @@ void LLChatBar::sendChatFromViewer(const LLWString &wtext, EChatType type, BOOL } // [RLVa:KB] - Checked: 2010-03-27 (RLVa-1.2.0b) | Modified: RLVa-1.2.0b - if ( (0 == channel) && (rlv_handler_t::isEnabled()) ) + // RELEASE-RLVa: [SL-2.0.0] This entire class appears to be dead/non-functional? + if ( (0 == channel) && (RlvActions::isRlvEnabled()) ) { // Adjust the (public) chat "volume" on chat and gestures (also takes care of playing the proper animation) - if ( ((CHAT_TYPE_SHOUT == type) || (CHAT_TYPE_NORMAL == type)) && (gRlvHandler.hasBehaviour(RLV_BHVR_CHATNORMAL)) ) - type = CHAT_TYPE_WHISPER; - else if ( (CHAT_TYPE_SHOUT == type) && (gRlvHandler.hasBehaviour(RLV_BHVR_CHATSHOUT)) ) - type = CHAT_TYPE_NORMAL; - else if ( (CHAT_TYPE_WHISPER == type) && (gRlvHandler.hasBehaviour(RLV_BHVR_CHATWHISPER)) ) - type = CHAT_TYPE_NORMAL; - - animate &= !gRlvHandler.hasBehaviour( (!RlvUtil::isEmote(utf8_text)) ? RLV_BHVR_REDIRCHAT : RLV_BHVR_REDIREMOTE ); + type = RlvActions::checkChatVolume(type); + animate &= !RlvActions::hasBehaviour( (!RlvUtil::isEmote(utf8_text)) ? RLV_BHVR_REDIRCHAT : RLV_BHVR_REDIREMOTE ); } // [/RLVa:KB] @@ -731,23 +716,19 @@ void LLChatBar::sendChatFromViewer(const LLWString &wtext, EChatType type, BOOL send_chat_from_viewer(utf8_out_text, type, channel); } -// [RLVa:KB] - Checked: 2009-07-07 (RLVa-1.0.0d) | Modified: RLVa-0.2.2a +//void send_chat_from_viewer(const std::string& utf8_out_text, EChatType type, S32 channel) +// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0b) | Modified: RLVa-0.2.2a void send_chat_from_viewer(std::string utf8_out_text, EChatType type, S32 channel) // [/RLVa:KB] { // [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0b) | Modified: RLVa-1.2.0a // Only process chat messages (ie not CHAT_TYPE_START, CHAT_TYPE_STOP, etc) - if ( (rlv_handler_t::isEnabled()) && ( (CHAT_TYPE_WHISPER == type) || (CHAT_TYPE_NORMAL == type) || (CHAT_TYPE_SHOUT == type) ) ) + if ( (RlvActions::isRlvEnabled()) && ( (CHAT_TYPE_WHISPER == type) || (CHAT_TYPE_NORMAL == type) || (CHAT_TYPE_SHOUT == type) ) ) { if (0 == channel) { - // (We already did this before, but LLChatHandler::handle() calls this directly) - if ( ((CHAT_TYPE_SHOUT == type) || (CHAT_TYPE_NORMAL == type)) && (gRlvHandler.hasBehaviour(RLV_BHVR_CHATNORMAL)) ) - type = CHAT_TYPE_WHISPER; - else if ( (CHAT_TYPE_SHOUT == type) && (gRlvHandler.hasBehaviour(RLV_BHVR_CHATSHOUT)) ) - type = CHAT_TYPE_NORMAL; - else if ( (CHAT_TYPE_WHISPER == type) && (gRlvHandler.hasBehaviour(RLV_BHVR_CHATWHISPER)) ) - type = CHAT_TYPE_NORMAL; + // Clamp the volume of the chat if needed + type = RlvActions::checkChatVolume(type); // Redirect chat if needed if ( ( (gRlvHandler.hasBehaviour(RLV_BHVR_REDIRCHAT) || (gRlvHandler.hasBehaviour(RLV_BHVR_REDIREMOTE)) ) && @@ -763,7 +744,7 @@ void send_chat_from_viewer(std::string utf8_out_text, EChatType type, S32 channe else { // Don't allow chat on a non-public channel if sendchannel restricted (unless the channel is an exception) - if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SENDCHANNEL)) && (!gRlvHandler.isException(RLV_BHVR_SENDCHANNEL, channel)) ) + if (!RlvActions::canSendChannel(channel)) return; // Don't allow chat on debug channel if @sendchat, @redirchat or @rediremote restricted (shows as public chat on viewers) @@ -836,33 +817,29 @@ void send_chat_from_viewer(std::string utf8_out_text, EChatType type, S32 channe void really_send_chat_from_viewer(const std::string& utf8_out_text, EChatType type, S32 channel) { LLMessageSystem* msg = gMessageSystem; - // - if(channel >= 0) + if (channel >= 0) { - // - msg->newMessageFast(_PREHASH_ChatFromViewer); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_ChatData); - msg->addStringFast(_PREHASH_Message, utf8_out_text); - msg->addU8Fast(_PREHASH_Type, type); - msg->addS32("Channel", channel); - // + msg->newMessageFast(_PREHASH_ChatFromViewer); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_ChatData); + msg->addStringFast(_PREHASH_Message, utf8_out_text); + msg->addU8Fast(_PREHASH_Type, type); + msg->addS32("Channel", channel); } else { - msg->newMessage("ScriptDialogReply"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID()); - msg->addUUID("SessionID", gAgent.getSessionID()); - msg->nextBlock("Data"); - msg->addUUID("ObjectID", gAgent.getID()); + msg->newMessageFast(_PREHASH_ScriptDialogReply); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_Data); + msg->addUUIDFast(_PREHASH_ObjectID, gAgent.getID()); msg->addS32("ChatChannel", channel); - msg->addS32("ButtonIndex", 0); - msg->addString("ButtonLabel", utf8_out_text); + msg->addS32Fast(_PREHASH_ButtonIndex, 0); + msg->addStringFast(_PREHASH_ButtonLabel, utf8_out_text); } - // gAgent.sendReliableMessage(); LLViewerStats::getInstance()->incStat(LLViewerStats::ST_CHAT_COUNT); @@ -895,7 +872,7 @@ void LLChatBar::onCommitGesture(LLUICtrl* ctrl) } } mGestureLabelTimer.start(); - if (mGestureCombo != NULL) + if (mGestureCombo != nullptr) { // free focus back to chat bar mGestureCombo->setFocus(FALSE); @@ -907,24 +884,39 @@ void toggleChatHistory() LLFloaterChat::toggleInstance(LLSD()); } +// +// LLChatCommandHandler +// -class LLChatHandler : public LLCommandHandler +class LLChatCommandHandler final : public LLCommandHandler { public: // not allowed from outside the app - LLChatHandler() : LLCommandHandler("chat", UNTRUSTED_BLOCK) { } + LLChatCommandHandler() : LLCommandHandler("chat", UNTRUSTED_BLOCK) { } // Your code here bool handle(const LLSD& tokens, const LLSD& query_map, - LLMediaCtrl* web) + LLMediaCtrl* web) override { - if (tokens.size() < 2) return false; - S32 channel = tokens[0].asInteger(); - std::string mesg = tokens[1].asString(); - send_chat_from_viewer(mesg, CHAT_TYPE_NORMAL, channel); - return true; + bool retval = false; + // Need at least 2 tokens to have a valid message. + if (tokens.size() < 2) + { + retval = false; + } + else + { + S32 channel = tokens[0].asInteger(); + { + retval = true; + // Send unescaped message, see EXT-6353. + std::string unescaped_mesg (LLURI::unescape(tokens[1].asString())); + send_chat_from_viewer(unescaped_mesg, CHAT_TYPE_NORMAL, channel); + } + } + return retval; } }; // Creating the object registers with the dispatcher. -LLChatHandler gChatHandler; +LLChatCommandHandler gChatHandler; diff --git a/indra/newview/llchatbar.h b/indra/newview/llchatbar.h index 71440d8bb..656da5132 100644 --- a/indra/newview/llchatbar.h +++ b/indra/newview/llchatbar.h @@ -33,10 +33,9 @@ #ifndef LL_LLCHATBAR_H #define LL_LLCHATBAR_H -#include "llpanel.h" #include "llframetimer.h" #include "llchat.h" -#include "lllayoutstack.h" +#include "llpanel.h" class LLLineEditor; class LLMessageSystem; @@ -46,17 +45,19 @@ class LLFrameTimer; class LLChatBarGestureObserver; class LLComboBox; -class LLChatBar : public LLPanel + +class LLChatBar final +: public LLPanel { public: // constructor for inline chat-bars (e.g. hosted in chat history window) LLChatBar(); - ~LLChatBar(); - virtual BOOL postBuild(); - virtual BOOL handleKeyHere(KEY key, MASK mask); + BOOL postBuild() override; + BOOL handleKeyHere(KEY key, MASK mask) override; + void onFocusLost() override; - void refresh(); + void refresh() override; void refreshGestures(); // Move cursor into chat input field. @@ -65,8 +66,8 @@ public: // Ignore arrow keys for chat bar void setIgnoreArrowKeys(BOOL b); - BOOL inputEditorHasFocus(); - std::string getCurrentChat(); + BOOL inputEditorHasFocus() const; + std::string getCurrentChat() const; // since chat bar logic is reused for chat history // gesture combo box might not be a direct child @@ -94,10 +95,11 @@ public: static void stopChat(); protected: + ~LLChatBar(); + void sendChat(EChatType type); void updateChat(); -protected: LLLineEditor* mInputEditor; LLFrameTimer mGestureLabelTimer; diff --git a/indra/newview/llcommandlineparser.cpp b/indra/newview/llcommandlineparser.cpp index 02d2e22de..17a869e87 100644 --- a/indra/newview/llcommandlineparser.cpp +++ b/indra/newview/llcommandlineparser.cpp @@ -293,19 +293,19 @@ bool LLCommandLineParser::parseAndStoreResults(po::command_line_parser& clp) po::basic_parsed_options opts = clp.run(); po::store(opts, gVariableMap); } - catch(po::error& e) + catch (const po::error& e) { LL_WARNS() << "Caught Error:" << e.what() << LL_ENDL; mErrorMsg = e.what(); return false; } - catch(LLCLPError& e) + catch (const LLCLPError& e) { LL_WARNS() << "Caught Error:" << e.what() << LL_ENDL; mErrorMsg = e.what(); return false; } - catch(LLCLPLastOption&) + catch (const LLCLPLastOption&) { // This exception means a token was read after an option // that must be the last option was reached (see url and slurl options) @@ -354,18 +354,58 @@ bool LLCommandLineParser::parseCommandLine(int argc, char **argv) return parseAndStoreResults(clp); } +// TODO: +// - Break out this funky parsing logic into separate method +// - Unit-test it with tests like LLStringUtil::getTokens() (the command-line +// overload that supports quoted tokens) +// - Unless this logic offers significant semantic benefits, replace it with +// LLStringUtil::getTokens(). This would fix a known bug: you cannot --set a +// string-valued variable to the empty string, because empty strings are +// eliminated below. + bool LLCommandLineParser::parseCommandLineString(const std::string& str) { + std::string cmd_line_string(""); + if (!str.empty()) + { + bool add_last_c = true; + S32 last_c_pos = str.size() - 1; //don't get out of bounds on pos+1, last char will be processed separately + for (S32 pos = 0; pos < last_c_pos; ++pos) + { + cmd_line_string.append(&str[pos], 1); + if (str[pos] == '\\') + { + cmd_line_string.append("\\", 1); + if (str[pos + 1] == '\\') + { + ++pos; + add_last_c = (pos != last_c_pos); + } + } + } + if (add_last_c) + { + cmd_line_string.append(&str[last_c_pos], 1); + if (str[last_c_pos] == '\\') + { + cmd_line_string.append("\\", 1); + } + } + } + // Split the string content into tokens - boost::escaped_list_separator sep("\\", "\r\n ", "\"'"); - boost::tokenizer< boost::escaped_list_separator > tok(str, sep); + const char* escape_chars = "\\"; + const char* separator_chars = "\r\n "; + const char* quote_chars = "\"'"; + boost::escaped_list_separator sep(escape_chars, separator_chars, quote_chars); + boost::tokenizer< boost::escaped_list_separator > tok(cmd_line_string, sep); std::vector tokens; // std::copy(tok.begin(), tok.end(), std::back_inserter(tokens)); for(boost::tokenizer< boost::escaped_list_separator >::iterator i = tok.begin(); i != tok.end(); ++i) { - if(0 != i->size()) + if(!i->empty()) { tokens.push_back(*i); } @@ -386,20 +426,28 @@ bool LLCommandLineParser::parseCommandLineFile(const std::basic_istream < char > void LLCommandLineParser::notify() { - po::notify(gVariableMap); + try + { + po::notify(gVariableMap); + } + catch (const LLCLPError& e) + { + LL_WARNS() << "Caught Error: " << e.what() << LL_ENDL; + mErrorMsg = e.what(); + } } void LLCommandLineParser::printOptions() const { - for(po::variables_map::iterator i = gVariableMap.begin(); i != gVariableMap.end(); ++i) + for (auto& i : gVariableMap) { - std::string name = i->first; - token_vector_t values = i->second.as(); + std::string name = i.first; + token_vector_t values = i.second.as(); std::ostringstream oss; oss << name << ": "; - for(token_vector_t::iterator t_itr = values.begin(); t_itr != values.end(); ++t_itr) + for (auto& value : values) { - oss << t_itr->c_str() << " "; + oss << value.c_str() << " "; } LL_INFOS() << oss.str() << LL_ENDL; } diff --git a/indra/newview/llcompilequeue.cpp b/indra/newview/llcompilequeue.cpp index fce835651..0e4a0168f 100644 --- a/indra/newview/llcompilequeue.cpp +++ b/indra/newview/llcompilequeue.cpp @@ -65,6 +65,7 @@ #include "lltrans.h" #include "llselectmgr.h" +#include "llexperiencecache.h" // *TODO: This should be separated into the script queue, and the floater views of that queue. // There should only be one floater class that can view any queue type @@ -76,12 +77,12 @@ struct LLScriptQueueData { LLUUID mQueueID; - std::string mScriptName; + LLPointer mItemp; LLUUID mTaskId; - LLUUID mItemId; - LLScriptQueueData(const LLUUID& q_id, const std::string& name, const LLUUID& task_id, const LLUUID& item_id) : - mQueueID(q_id), mScriptName(name), mTaskId(task_id), mItemId(item_id) {} - + LLUUID mExperienceId; + LLHost mHost; + LLScriptQueueData(const LLUUID& q_id, const LLUUID& task_id, LLInventoryItem* item, const LLHost& host) : + mQueueID(q_id), mTaskId(task_id), mItemp(item), mHost(host) {} }; ///---------------------------------------------------------------------------- @@ -220,7 +221,7 @@ BOOL LLFloaterScriptQueue::nextObject() LL_INFOS() << "LLFloaterScriptQueue::nextObject() - " << count << " objects left to process." << LL_ENDL; mCurrentObjectID.setNull(); - if(count > 0) + if (count > 0) { successful_start = popNext(); } @@ -228,7 +229,7 @@ BOOL LLFloaterScriptQueue::nextObject() << (successful_start ? "successful" : "unsuccessful") << LL_ENDL; } while((mObjectIDs.size() > 0) && !successful_start); - if(isDone() && !mDone) + if (isDone() && !mDone) { mDone = true; getChild("queue output")->addSimpleElement(getString("Done"), ADD_BOTTOM); @@ -245,14 +246,14 @@ BOOL LLFloaterScriptQueue::popNext() // the inventory. BOOL rv = FALSE; S32 count = mObjectIDs.size(); - if(mCurrentObjectID.isNull() && (count > 0)) + if (mCurrentObjectID.isNull() && (count > 0)) { mCurrentObjectID = mObjectIDs.at(0); LL_INFOS() << "LLFloaterScriptQueue::popNext() - mCurrentID: " << mCurrentObjectID << LL_ENDL; mObjectIDs.erase(mObjectIDs.begin()); LLViewerObject* obj = gObjectList.findObject(mCurrentObjectID); - if(obj) + if (obj) { LL_INFOS() << "LLFloaterScriptQueue::popNext() requesting inv for " << mCurrentObjectID << LL_ENDL; @@ -270,35 +271,21 @@ BOOL LLFloaterScriptQueue::startQueue() return nextObject(); } -#if 0 // Singu TODO: Experiences -class CompileQueueExperienceResponder : public LLHTTPClient::ResponderWithResult +class CompileQueueExperienceResponder final : public LLHTTPClient::ResponderWithResult { + const LLUUID mParent; public: - CompileQueueExperienceResponder(const LLUUID& parent):mParent(parent) - { - } + CompileQueueExperienceResponder(const LLUUID& parent): mParent(parent) {} - LLUUID mParent; - - /*virtual*/ void httpSuccess() - { - sendResult(getContent()); - } - /*virtual*/ void httpFailure() - { - sendResult(LLSD()); - } + void httpSuccess() override { sendResult(getContent()); } + void httpFailure() override { sendResult(LLSD()); } void sendResult(const LLSD& content) { - LLFloaterCompileQueue* queue = (LLFloaterCompileQueue*) LLFloaterScriptQueue::findInstance(mParent); - if(!queue) - return; - - queue->experienceIdsReceived(content["experience_ids"]); + if (auto queue = static_cast(LLFloaterCompileQueue::findInstance(mParent))) + queue->experienceIdsReceived(content["experience_ids"]); } - /*virtual*/ char const* getName() const { return "RequiredRubbish"; } + char const* getName() const override { return "CompileQueueExperienceResponder"; } }; -#endif @@ -318,7 +305,7 @@ public: virtual LLAssetUploadQueue* get() const { LLFloaterCompileQueue* queue = (LLFloaterCompileQueue*) LLFloaterScriptQueue::findInstance(mQueueId); - if(NULL == queue) + if (NULL == queue) { return NULL; } @@ -328,7 +315,7 @@ public: virtual void log(std::string message) const { LLFloaterCompileQueue* queue = (LLFloaterCompileQueue*) LLFloaterScriptQueue::findInstance(mQueueId); - if(NULL == queue) + if (NULL == queue) { return; } @@ -363,6 +350,21 @@ LLFloaterCompileQueue::~LLFloaterCompileQueue() { } +void LLFloaterCompileQueue::experienceIdsReceived(const LLSD& content) +{ + for(LLSD::array_const_iterator it = content.beginArray(); it != content.endArray(); ++it) + { + mExperienceIds.insert(it->asUUID()); + } + nextObject(); +} + +BOOL LLFloaterCompileQueue::hasExperience(const LLUUID& id) const +{ + return mExperienceIds.find(id) != mExperienceIds.end(); +} + + void LLFloaterCompileQueue::handleInventory(LLViewerObject *viewer_object, LLInventoryObject::object_list_t* inv) { @@ -376,7 +378,7 @@ void LLFloaterCompileQueue::handleInventory(LLViewerObject *viewer_object, LLInventoryObject::object_list_t::const_iterator end = inv->end(); for ( ; it != end; ++it) { - if((*it)->getType() == LLAssetType::AT_LSL_TEXT) + if ((*it)->getType() == LLAssetType::AT_LSL_TEXT) { LLInventoryItem* item = (LLInventoryItem*)((LLInventoryObject*)(*it)); // Check permissions before allowing the user to retrieve data. @@ -397,31 +399,68 @@ void LLFloaterCompileQueue::handleInventory(LLViewerObject *viewer_object, } else { - // request all of the assets. - uuid_item_map::iterator iter; - for(iter = asset_item_map.begin(); iter != asset_item_map.end(); iter++) + LLViewerRegion* region = viewer_object->getRegion(); + std::string url = std::string(); + if (region) { - LLInventoryItem *itemp = iter->second; - LLScriptQueueData* datap = new LLScriptQueueData(getID(), - itemp->getName(), - viewer_object->getID(), - itemp->getUUID()); + url = region->getCapability("GetMetadata"); + } - //LL_INFOS() << "ITEM NAME 2: " << names.get(i) << LL_ENDL; - gAssetStorage->getInvItemAsset(viewer_object->getRegion()->getHost(), - gAgent.getID(), - gAgent.getSessionID(), - itemp->getPermissions().getOwner(), - viewer_object->getID(), - itemp->getUUID(), - itemp->getAssetUUID(), - itemp->getType(), - LLFloaterCompileQueue::scriptArrived, - (void*)datap); + const auto& host = region->getHost(); + const auto& obj_id = viewer_object->getID(); + // request all of the assets. + for(const auto& pair : asset_item_map) + { + LLInventoryItem *itemp = pair.second; + LLScriptQueueData* datap = new LLScriptQueueData(getID(), + obj_id, + itemp, + host); + + LLExperienceCache::instance().fetchAssociatedExperience(itemp->getParentUUID(), itemp->getUUID(), + boost::bind(LLFloaterCompileQueue::requestAsset, datap, _1)); } } } +void LLFloaterCompileQueue::requestAsset(LLScriptQueueData* datap, const LLSD& experience) +{ + LLFloaterCompileQueue* queue = static_cast(findInstance(datap->mQueueID)); + if (!queue) + { + delete datap; + return; + } + + if (experience.has(LLExperienceCache::EXPERIENCE_ID)) + { + datap->mExperienceId = experience[LLExperienceCache::EXPERIENCE_ID].asUUID(); + if (!queue->hasExperience(datap->mExperienceId)) + { + std::string buffer = LLTrans::getString("CompileNoExperiencePerm", LLSD::emptyMap() + .with("SCRIPT", datap->mItemp->getName()) + .with("EXPERIENCE", experience[LLExperienceCache::NAME].asString())); + + queue->getChild("queue output")->addSimpleElement(buffer, ADD_BOTTOM); + queue->removeItemByItemID(datap->mItemp->getUUID()); + delete datap; + return; + } + } + + //LL_INFOS() << "ITEM NAME 2: " << names.get(i) << LL_ENDL; + gAssetStorage->getInvItemAsset(datap->mHost, + gAgent.getID(), + gAgent.getSessionID(), + datap->mItemp->getPermissions().getOwner(), + datap->mTaskId, + datap->mItemp->getUUID(), + datap->mItemp->getAssetUUID(), + datap->mItemp->getType(), + LLFloaterCompileQueue::scriptArrived, + (void*)datap); +} + // This is the callback for when each script arrives // static @@ -438,9 +477,9 @@ void LLFloaterCompileQueue::scriptArrived(LLVFS *vfs, const LLUUID& asset_id, LLFloaterCompileQueue* queue = static_cast (LLFloaterScriptQueue::findInstance(data->mQueueID)); std::string buffer; - if(queue && (0 == status)) + if (queue && (0 == status)) { - //LL_INFOS() << "ITEM NAME 3: " << data->mScriptName << LL_ENDL; + //LL_INFOS() << "ITEM NAME 3: " << data->mItemp->getName() << LL_ENDL; // Dump this into a file on the local disk so we can compile it. std::string filename; @@ -454,7 +493,7 @@ void LLFloaterCompileQueue::scriptArrived(LLVFS *vfs, const LLUUID& asset_id, if (object) { std::string url = object->getRegion()->getCapability("UpdateScriptTask"); - if(!url.empty()) + if (!url.empty()) { // Read script source in to buffer. U32 script_size = file.getSize(); @@ -462,17 +501,17 @@ void LLFloaterCompileQueue::scriptArrived(LLVFS *vfs, const LLUUID& asset_id, file.read(script_data, script_size); queue->mUploadQueue->queue(filename, data->mTaskId, - data->mItemId, is_running, queue->mMono, queue->getID(), - script_data, script_size, data->mScriptName); + data->mItemp->getUUID(), is_running, queue->mMono, queue->getID(), + script_data, script_size, data->mItemp->getName(), data->mExperienceId); } else { std::string text = LLTrans::getString("CompileQueueProblemUploading"); LLChat chat(text); LLFloaterChat::addChat(chat); - buffer = text + LLTrans::getString(":") + ' ' + data->mScriptName; + buffer = text + LLTrans::getString(":") + ' ' + data->mItemp->getName(); LL_WARNS() << "Problem uploading script asset." << LL_ENDL; - if(queue) queue->removeItemByItemID(data->mItemId); + if(queue) queue->removeItemByItemID(data->mItemp->getUUID()); } } } @@ -480,29 +519,29 @@ void LLFloaterCompileQueue::scriptArrived(LLVFS *vfs, const LLUUID& asset_id, { LLViewerStats::getInstance()->incStat( LLViewerStats::ST_DOWNLOAD_FAILED ); - if( LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status ) + if ( LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status ) { LLChat chat(LLTrans::getString("CompileQueueScriptNotFound")); LLFloaterChat::addChat(chat); - buffer = LLTrans::getString("CompileQueueProblemDownloading") + LLTrans::getString(":") + ' ' + data->mScriptName; + buffer = LLTrans::getString("CompileQueueProblemDownloading") + LLTrans::getString(":") + ' ' + data->mItemp->getName(); } else if (LL_ERR_INSUFFICIENT_PERMISSIONS == status) { LLChat chat(LLTrans::getString("CompileQueueInsufficientPermDownload")); LLFloaterChat::addChat(chat); - buffer = LLTrans::getString("CompileQueueInsufficientPermFor") + LLTrans::getString(":") + ' ' + data->mScriptName; + buffer = LLTrans::getString("CompileQueueInsufficientPermFor") + LLTrans::getString(":") + ' ' + data->mItemp->getName(); } else { - buffer = LLTrans::getString("CompileQueueUnknownFailure") + ' ' + data->mScriptName; + buffer = LLTrans::getString("CompileQueueUnknownFailure") + ' ' + data->mItemp->getName(); } LL_WARNS() << "Problem downloading script asset." << LL_ENDL; - if(queue) queue->removeItemByItemID(data->mItemId); + if(queue) queue->removeItemByItemID(data->mItemp->getUUID()); } - if(queue && (buffer.size() > 0)) + if (queue && (buffer.size() > 0)) { queue->getChild("queue output")->addSimpleElement(buffer, ADD_BOTTOM); } @@ -528,7 +567,7 @@ void LLFloaterCompileQueue::saveItemByItemID(const LLUUID& asset_id) { LL_INFOS() << "LLFloaterCompileQueue::saveItemByAssetID()" << LL_ENDL; LLViewerObject* viewer_object = gObjectList.findObject(mCurrentObjectID); - if(viewer_object) + if (viewer_object) { S32 count = mCurrentScripts.size(); for(S32 i = 0; i < count; ++i) @@ -582,7 +621,7 @@ void LLFloaterResetQueue::handleInventory(LLViewerObject* viewer_obj, LLInventoryObject::object_list_t::const_iterator end = inv->end(); for ( ; it != end; ++it) { - if((*it)->getType() == LLAssetType::AT_LSL_TEXT) + if ((*it)->getType() == LLAssetType::AT_LSL_TEXT) { LLViewerObject* object = gObjectList.findObject(viewer_obj->getID()); @@ -641,7 +680,7 @@ void LLFloaterRunQueue::handleInventory(LLViewerObject* viewer_obj, LLInventoryObject::object_list_t::const_iterator end = inv->end(); for ( ; it != end; ++it) { - if((*it)->getType() == LLAssetType::AT_LSL_TEXT) + if ((*it)->getType() == LLAssetType::AT_LSL_TEXT) { LLViewerObject* object = gObjectList.findObject(viewer_obj->getID()); @@ -716,17 +755,16 @@ void LLFloaterCompileQueue::removeItemByItemID(const LLUUID& asset_id) BOOL LLFloaterCompileQueue::startQueue() { - /* Singu TODO: Experiences LLViewerRegion* region = gAgent.getRegion(); if (region) { - std::string lookup_url=region->getCapability("GetCreatorExperiences"); - if(!lookup_url.empty()) + std::string lookup_url = region->getCapability("GetCreatorExperiences"); + if (!lookup_url.empty()) { - LLHTTPClient::get(lookup_url, new CompileQueueExperienceResponder(getKey().asUUID())); + LLHTTPClient::get(lookup_url, new CompileQueueExperienceResponder(mID)); return TRUE; } - }*/ + } return nextObject(); } @@ -741,7 +779,7 @@ void LLFloaterNotRunQueue::handleInventory(LLViewerObject* viewer_obj, LLInventoryObject::object_list_t::const_iterator end = inv->end(); for ( ; it != end; ++it) { - if((*it)->getType() == LLAssetType::AT_LSL_TEXT) + if ((*it)->getType() == LLAssetType::AT_LSL_TEXT) { LLViewerObject* object = gObjectList.findObject(viewer_obj->getID()); diff --git a/indra/newview/llcompilequeue.h b/indra/newview/llcompilequeue.h index 25212de11..fba5d295a 100644 --- a/indra/newview/llcompilequeue.h +++ b/indra/newview/llcompilequeue.h @@ -103,7 +103,7 @@ protected: // Get this instance's ID. const LLUUID& getID() const { return mID; } - + protected: // UI LLScrollListCtrl* mMessages; @@ -149,8 +149,8 @@ public: LLAssetUploadQueue* getUploadQueue() { return mUploadQueue; } - void experienceIdsReceived( const LLSD& content ); - BOOL hasExperience(const LLUUID& id)const; + void experienceIdsReceived(const LLSD& content); + BOOL hasExperience(const LLUUID& id) const; protected: LLFloaterCompileQueue(const std::string& name, const LLRect& rect); @@ -160,6 +160,9 @@ protected: virtual void handleInventory(LLViewerObject* viewer_obj, LLInventoryObject::object_list_t* inv); + static void requestAsset(struct LLScriptQueueData* datap, const LLSD& experience); + + // This is the callback for when each script arrives static void scriptArrived(LLVFS *vfs, const LLUUID& asset_id, LLAssetType::EType type, diff --git a/indra/newview/llcontrolavatar.cpp b/indra/newview/llcontrolavatar.cpp index 010a83916..31d027926 100644 --- a/indra/newview/llcontrolavatar.cpp +++ b/indra/newview/llcontrolavatar.cpp @@ -47,8 +47,8 @@ LLControlAvatar::LLControlAvatar(const LLUUID& id, const LLPCode pcode, LLViewer LLVOAvatar(id, pcode, regionp), mPlaying(false), mGlobalScale(1.0f), + mRootVolp(NULL), mMarkedForDeath(false), - mRootVolp(NULL), mScaleConstraintFixup(1.0), mRegionChanged(false) { @@ -60,6 +60,8 @@ LLControlAvatar::LLControlAvatar(const LLUUID& id, const LLPCode pcode, LLViewer // virtual LLControlAvatar::~LLControlAvatar() { + // Should already have been unlinked before destruction + llassert(!mRootVolp); } // virtual @@ -82,18 +84,12 @@ void LLControlAvatar::getNewConstraintFixups(LLVector3& new_pos_fixup, F32& new_ { F32 max_legal_offset = MAX_LEGAL_OFFSET; - if (gSavedSettings.getControl("AnimatedObjectsMaxLegalOffset")) - { - max_legal_offset = gSavedSettings.getF32("AnimatedObjectsMaxLegalOffset"); - } - max_legal_offset = llmax(max_legal_offset,0.f); + static LLCachedControl animated_object_max_legal_offset(gSavedSettings, "AnimatedObjectsMaxLegalOffset"); + max_legal_offset = llmax(animated_object_max_legal_offset(),0.f); F32 max_legal_size = MAX_LEGAL_SIZE; - if (gSavedSettings.getControl("AnimatedObjectsMaxLegalSize")) - { - max_legal_size = gSavedSettings.getF32("AnimatedObjectsMaxLegalSize"); - } - max_legal_size = llmax(max_legal_size, 1.f); + static LLCachedControl animated_object_max_legal_size(gSavedSettings, "AnimatedObjectsMaxLegalSize"); + max_legal_size = llmax(animated_object_max_legal_size(), 1.f); new_pos_fixup = LLVector3(); new_scale_fixup = 1.0f; @@ -113,7 +109,7 @@ void LLControlAvatar::getNewConstraintFixups(LLVector3& new_pos_fixup, F32& new_ unshift_extents[0] = extents[0] - mPositionConstraintFixup; unshift_extents[1] = extents[1] - mPositionConstraintFixup; LLVector3 box_dims = extents[1]-extents[0]; - //F32 box_size = llmax(box_dims[0],box_dims[1],box_dims[2]); + F32 box_size = llmax(box_dims[0],box_dims[1],box_dims[2]); if (!mRootVolp->isAttachment()) { @@ -124,23 +120,23 @@ void LLControlAvatar::getNewConstraintFixups(LLVector3& new_pos_fixup, F32& new_ F32 target_dist = (offset_dist - max_legal_offset); new_pos_fixup = (target_dist/offset_dist)*pos_box_offset; } - if (new_pos_fixup != mPositionConstraintFixup) - { - LL_DEBUGS("ConstraintFix") << getFullname() << " pos fix, offset_dist " << offset_dist << " pos fixup " - << new_pos_fixup << " was " << mPositionConstraintFixup << LL_ENDL; - LL_DEBUGS("ConstraintFix") << "vol_pos " << vol_pos << LL_ENDL; - LL_DEBUGS("ConstraintFix") << "extents " << extents[0] << " " << extents[1] << LL_ENDL; - LL_DEBUGS("ConstraintFix") << "unshift_extents " << unshift_extents[0] << " " << unshift_extents[1] << LL_ENDL; - - } + //if (new_pos_fixup != mPositionConstraintFixup) + //{ + // LL_DEBUGS("ConstraintFix") << getFullname() << " pos fix, offset_dist " << offset_dist << " pos fixup " + // << new_pos_fixup << " was " << mPositionConstraintFixup << LL_ENDL; + // LL_DEBUGS("ConstraintFix") << "vol_pos " << vol_pos << LL_ENDL; + // LL_DEBUGS("ConstraintFix") << "extents " << extents[0] << " " << extents[1] << LL_ENDL; + // LL_DEBUGS("ConstraintFix") << "unshift_extents " << unshift_extents[0] << " " << unshift_extents[1] << LL_ENDL; + // + //} } - /*if (box_size/mScaleConstraintFixup > max_legal_size) + if (box_size/mScaleConstraintFixup > max_legal_size) { new_scale_fixup = mScaleConstraintFixup*max_legal_size/box_size; - LL_DEBUGS("ConstraintFix") << getFullname() << " scale fix, box_size " << box_size << " fixup " - << mScaleConstraintFixup << " max legal " << max_legal_size - << " -> new scale " << new_scale_fixup << LL_ENDL; - }*/ + //LL_DEBUGS("ConstraintFix") << getFullname() << " scale fix, box_size " << box_size << " fixup " + // << mScaleConstraintFixup << " max legal " << max_legal_size + // << " -> new scale " << new_scale_fixup << LL_ENDL; + } } } @@ -163,6 +159,8 @@ void LLControlAvatar::matchVolumeTransform() mPositionConstraintFixup = new_pos_fixup; mScaleConstraintFixup = new_scale_fixup; + static LLCachedControl global_scale(gSavedSettings, "AnimatedObjectsGlobalScale", 1.f); + if (mRootVolp->isAttachment()) { LLVOAvatar *attached_av = mRootVolp->getAvatarAncestor(); @@ -174,13 +172,12 @@ void LLControlAvatar::matchVolumeTransform() LLVector3 joint_pos = attach->getWorldPosition(); LLQuaternion joint_rot = attach->getWorldRotation(); LLVector3 obj_pos = mRootVolp->mDrawable->getPosition(); - LLQuaternion obj_rot = mRootVolp->mDrawable->getRotation(); + const LLQuaternion& obj_rot = mRootVolp->mDrawable->getRotation(); obj_pos.rotVec(joint_rot); mRoot->setWorldPosition(obj_pos + joint_pos); mRoot->setWorldRotation(obj_rot * joint_rot); setRotation(mRoot->getRotation()); - F32 global_scale = gSavedSettings.getF32("AnimatedObjectsGlobalScale"); setGlobalScale(global_scale * mScaleConstraintFixup); } else @@ -200,17 +197,7 @@ void LLControlAvatar::matchVolumeTransform() // complexity info and such line up better. Should defer // this until avatars also get fixed. - LLQuaternion obj_rot; - if (mRootVolp->mDrawable) - { - obj_rot = mRootVolp->mDrawable->getRotation(); - } - else - { - obj_rot = mRootVolp->getRotation(); - } - - LLMatrix3 bind_mat; + const LLQuaternion& obj_rot = mRootVolp->mDrawable ? mRootVolp->mDrawable->getRotation() : mRootVolp->getRotation(); LLQuaternion bind_rot; #define MATCH_BIND_SHAPE @@ -219,7 +206,7 @@ void LLControlAvatar::matchVolumeTransform() const LLMeshSkinInfo* skin_info = mRootVolp->getSkinInfo(); if (skin_info) { - LL_DEBUGS("BindShape") << getFullname() << " bind shape " << skin_info->mBindShapeMatrix << LL_ENDL; + //LL_DEBUGS("BindShape") << getFullname() << " bind shape " << skin_info->mBindShapeMatrix << LL_ENDL; bind_rot = LLSkinningUtil::getUnscaledQuaternion(skin_info->mBindShapeMatrix); } #endif @@ -228,7 +215,6 @@ void LLControlAvatar::matchVolumeTransform() setPositionAgent(vol_pos); mRoot->setPosition(vol_pos + mPositionConstraintFixup); - F32 global_scale = gSavedSettings.getF32("AnimatedObjectsGlobalScale"); setGlobalScale(global_scale * mScaleConstraintFixup); } } @@ -236,7 +222,7 @@ void LLControlAvatar::matchVolumeTransform() void LLControlAvatar::setGlobalScale(F32 scale) { - if (scale <= 0.0) + if (scale <= 0.0f) { LL_WARNS() << "invalid global scale " << scale << LL_ENDL; return; @@ -255,10 +241,8 @@ void LLControlAvatar::recursiveScaleJoint(LLJoint* joint, F32 factor) { joint->setScale(factor * joint->getScale()); - for (LLJoint::child_list_t::iterator iter = joint->mChildren.begin(); - iter != joint->mChildren.end(); ++iter) + for (auto child : joint->mChildren) { - LLJoint* child = *iter; recursiveScaleJoint(child, factor); } } @@ -278,10 +262,9 @@ void LLControlAvatar::updateVolumeGeom() mRootVolp->mDrawable->setState(LLDrawable::USE_BACKLIGHT); LLViewerObject::const_child_list_t& child_list = mRootVolp->getChildren(); - for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); - iter != child_list.end(); ++iter) + for (const auto& iter : child_list) { - LLViewerObject* childp = *iter; + LLViewerObject* childp = iter; if (childp && childp->mDrawable.notNull()) { childp->mDrawable->setState(LLDrawable::USE_BACKLIGHT); @@ -339,6 +322,21 @@ LLControlAvatar *LLControlAvatar::createControlAvatar(LLVOVolume *obj) void LLControlAvatar::markForDeath() { mMarkedForDeath = true; + mRootVolp = NULL; +} + +void LLControlAvatar::markDead() +{ + // NOTE: this can happen when the control avatar and root volume are on different regions and we're + // being called from the LLViewerRegion destructor due the region being dropped + // (due to being used as a vehicle and the move not yet being processed?) + if (mRootVolp) + { + mRootVolp->unlinkControlAvatar(); + mRootVolp = nullptr; + } + + LLVOAvatar::markDead(); } void LLControlAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) @@ -362,7 +360,8 @@ BOOL LLControlAvatar::updateCharacter(LLAgent &agent) //virtual void LLControlAvatar::updateDebugText() { - /*if (gSavedSettings.getBOOL("DebugAnimatedObjects")) + /*static LLCachedControl debug_animated_objects(gSavedSettings, "DebugAnimatedObjects"); + if (debug_animated_objects) { S32 total_linkset_count = 0; if (mRootVolp) @@ -385,63 +384,64 @@ void LLControlAvatar::updateDebugText() S32 cam_dist_count = 0; F32 lod_radius = mRootVolp->mLODRadius; - for (std::vector::iterator it = volumes.begin(); - it != volumes.end(); ++it) + for (auto volp : volumes) { - LLVOVolume *volp = *it; - S32 verts = 0; - total_tris += volp->getTriangleCount(&verts); - total_verts += verts; - est_tris += volp->getEstTrianglesMax(); - est_streaming_tris += volp->getEstTrianglesStreamingCost(); - streaming_cost += volp->getStreamingCost(); - lod_string += llformat("%d",volp->getLOD()); - if (volp && volp->mDrawable) + if (volp) { - bool is_animated_flag = volp->getExtendedMeshFlags() & LLExtendedMeshParams::ANIMATED_MESH_ENABLED_FLAG; - if (is_animated_flag) + S32 verts = 0; + total_tris += volp->getTriangleCount(&verts); + total_verts += verts; + est_tris += volp->getEstTrianglesMax(); + est_streaming_tris += volp->getEstTrianglesStreamingCost(); + streaming_cost += volp->getStreamingCost(); + lod_string += llformat("%d", volp->getLOD()); + if (volp->mDrawable) { - animated_object_flag_string += "1"; + bool is_animated_flag = volp->getExtendedMeshFlags() & LLExtendedMeshParams::ANIMATED_MESH_ENABLED_FLAG; + if (is_animated_flag) + { + animated_object_flag_string += "1"; + } + else + { + animated_object_flag_string += "0"; + } + if (volp->mDrawable->isActive()) + { + active_string += "A"; + } + else + { + active_string += "S"; + } + if (volp->isRiggedMesh()) + { + // Rigged/animatable mesh + type_string += "R"; + lod_radius = volp->mLODRadius; + } + else if (volp->isMesh()) + { + // Static mesh + type_string += "M"; + } + else + { + // Any other prim + type_string += "P"; + } + if (cam_dist_count < 4) + { + cam_dist_string += LLStringOps::getReadableNumber(volp->mLODDistance) + "/" + + LLStringOps::getReadableNumber(volp->mLODAdjustedDistance) + " "; + cam_dist_count++; + } } else { - animated_object_flag_string += "0"; + active_string += "-"; + type_string += "-"; } - if (volp->mDrawable->isActive()) - { - active_string += "A"; - } - else - { - active_string += "S"; - } - if (volp->isRiggedMesh()) - { - // Rigged/animatable mesh - type_string += "R"; - lod_radius = volp->mLODRadius; - } - else if (volp->isMesh()) - { - // Static mesh - type_string += "M"; - } - else - { - // Any other prim - type_string += "P"; - } - if (cam_dist_count < 4) - { - cam_dist_string += LLStringOps::getReadableNumber(volp->mLODDistance) + "/" + - LLStringOps::getReadableNumber(volp->mLODAdjustedDistance) + " "; - cam_dist_count++; - } - } - else - { - active_string += "-"; - type_string += "-"; } } addDebugText(llformat("CAV obj %d anim %d active %s impost %d upprd %d strcst %f", @@ -491,11 +491,10 @@ void LLControlAvatar::getAnimatedVolumes(std::vector& volumes) volumes.push_back(mRootVolp); LLViewerObject::const_child_list_t& child_list = mRootVolp->getChildren(); - for (LLViewerObject::const_child_list_t::const_iterator iter = child_list.begin(); - iter != child_list.end(); ++iter) + for (const auto& iter : child_list) { - LLViewerObject* childp = *iter; - LLVOVolume *child_volp = dynamic_cast(childp); + LLViewerObject* childp = iter; + LLVOVolume *child_volp = childp ? childp->asVolume() : nullptr; if (child_volp && child_volp->isAnimatedObject()) { volumes.push_back(child_volp); @@ -519,16 +518,17 @@ void LLControlAvatar::updateAnimations() // Rebuild mSignaledAnimations from the associated volumes. std::map anims; - for (std::vector::iterator vol_it = volumes.begin(); vol_it != volumes.end(); ++vol_it) + for (auto vol_it = volumes.begin(); vol_it != volumes.end(); ++vol_it) { LLVOVolume *volp = *vol_it; //LL_INFOS("AnimatedObjects") << "updating anim for vol " << volp->getID() << " root " << mRootVolp->getID() << LL_ENDL; - signaled_animation_map_t& signaled_animations = LLObjectSignaledAnimationMap::instance().getMap()[volp->getID()]; - for (std::map::iterator anim_it = signaled_animations.begin(); - anim_it != signaled_animations.end(); + auto& signaled_anim_map = LLObjectSignaledAnimationMap::instance().getMap(); + signaled_animation_map_t& signaled_animations = signaled_anim_map[volp->getID()]; + for (auto anim_it = signaled_animations.begin(), anim_it_end = signaled_animations.end(); + anim_it != anim_it_end; ++anim_it) { - std::map::iterator found_anim_it = anims.find(anim_it->first); + auto found_anim_it = anims.find(anim_it->first); if (found_anim_it != anims.end()) { // Animation already present, use the larger sequence id @@ -539,7 +539,9 @@ void LLControlAvatar::updateAnimations() // Animation not already present, use this sequence id. anims[anim_it->first] = anim_it->second; } +#if LL_DEBUG LL_DEBUGS("AnimatedObjectsNotify") << "found anim for vol " << volp->getID() << " anim " << anim_it->first << " root " << mRootVolp->getID() << LL_ENDL; +#endif } } if (!mPlaying) @@ -567,24 +569,45 @@ LLViewerObject* LLControlAvatar::lineSegmentIntersectRiggedAttachments(const LLV LLVector4a* normal, LLVector4a* tangent) { + if (!mRootVolp) + { + return NULL; + } + LLViewerObject* hit = NULL; if (lineSegmentBoundingBox(start, end)) { LLVector4a local_end = end; LLVector4a local_intersection; - - if (mRootVolp && - mRootVolp->lineSegmentIntersect(start, local_end, face, pick_transparent, pick_rigged, face_hit, &local_intersection, tex_coord, normal, tangent)) + if (mRootVolp->lineSegmentIntersect(start, local_end, face, pick_transparent, pick_rigged, face_hit, &local_intersection, tex_coord, normal, tangent)) { local_end = local_intersection; if (intersection) { *intersection = local_intersection; } - hit = mRootVolp; } + else + { + std::vector volumes; + getAnimatedVolumes(volumes); + + for (auto volp : volumes) + { + if (mRootVolp != volp && volp->lineSegmentIntersect(start, local_end, face, pick_transparent, pick_rigged, face_hit, &local_intersection, tex_coord, normal, tangent)) + { + local_end = local_intersection; + if (intersection) + { + *intersection = local_intersection; + } + hit = volp; + break; + } + } + } } return hit; @@ -618,7 +641,7 @@ bool LLControlAvatar::shouldRenderRigged() const } // virtual -BOOL LLControlAvatar::isImpostor() +BOOL LLControlAvatar::isImpostor() const { if (mRootVolp && mRootVolp->isAttachment()) { @@ -638,8 +661,11 @@ void LLControlAvatar::onRegionChanged() std::vector::iterator it = LLCharacter::sInstances.begin(); for ( ; it != LLCharacter::sInstances.end(); ++it) { - LLControlAvatar* cav = dynamic_cast(*it); - if (!cav) continue; - cav->mRegionChanged = true; + auto avatar = static_cast(*it); + if (!avatar->isDead() && avatar->isControlAvatar()) + { + LLControlAvatar* cav = static_cast(avatar); + cav->mRegionChanged = true; + } } } diff --git a/indra/newview/llcontrolavatar.h b/indra/newview/llcontrolavatar.h index 056593850..c01c5c0a9 100644 --- a/indra/newview/llcontrolavatar.h +++ b/indra/newview/llcontrolavatar.h @@ -30,16 +30,16 @@ #include "llvoavatar.h" #include "llvovolume.h" -class LLControlAvatar: +class LLControlAvatar final: public LLVOAvatar { LOG_CLASS(LLControlAvatar); public: LLControlAvatar(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp); - virtual void initInstance(); // Called after construction to initialize the class. + void initInstance() override; // Called after construction to initialize the class. virtual ~LLControlAvatar(); - virtual LLControlAvatar* asControlAvatar() { return this; } + LLControlAvatar* asControlAvatar() override { return this; } void getNewConstraintFixups(LLVector3& new_pos_constraint, F32& new_scale_constraint) const; void matchVolumeTransform(); @@ -52,14 +52,15 @@ public: // Delayed kill so we don't make graphics pipeline unhappy calling // markDead() inside other graphics pipeline operations. void markForDeath(); + void markDead() override; - virtual void idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time); - virtual BOOL updateCharacter(LLAgent &agent); + void idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) override; + BOOL updateCharacter(LLAgent &agent) override; void getAnimatedVolumes(std::vector& volumes); void updateAnimations(); - virtual LLViewerObject* lineSegmentIntersectRiggedAttachments( + LLViewerObject* lineSegmentIntersectRiggedAttachments( const LLVector4a& start, const LLVector4a& end, S32 face = -1, // which face to check, -1 = ALL_SIDES BOOL pick_transparent = FALSE, @@ -68,15 +69,15 @@ public: LLVector4a* intersection = NULL, // return the intersection point LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point LLVector4a* normal = NULL, // return the surface normal at the intersection point - LLVector4a* tangent = NULL); // return the surface tangent at the intersection point + LLVector4a* tangent = NULL) override; // return the surface tangent at the intersection point - virtual void updateDebugText(); + void updateDebugText() override; - virtual std::string getFullname() const; + std::string getFullname() const override; - virtual bool shouldRenderRigged() const; + bool shouldRenderRigged() const override; - virtual BOOL isImpostor(); + BOOL isImpostor() const override; bool mPlaying; @@ -101,7 +102,7 @@ typedef std::map signaled_animation_map_t; typedef std::map object_signaled_animation_map_t; // Stores information about previously requested animations, by object id. -class LLObjectSignaledAnimationMap: public LLSingleton +class LLObjectSignaledAnimationMap final : public LLSingleton { public: LLObjectSignaledAnimationMap() {} diff --git a/indra/newview/llexperiencelog.cpp b/indra/newview/llexperiencelog.cpp new file mode 100644 index 000000000..ea2e57535 --- /dev/null +++ b/indra/newview/llexperiencelog.cpp @@ -0,0 +1,289 @@ +/** + * @file llexperiencelog.cpp + * @brief llexperiencelog implementation + * + * $LicenseInfo:firstyear=2014&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2014, 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 "llexperiencelog.h" + +#include "lldispatcher.h" +#include "llsdserialize.h" +#include "llviewergenericmessage.h" +#include "llnotificationsutil.h" +#include "lltrans.h" +#include "llerror.h" +#include "lldate.h" + + +class LLExperienceLogDispatchHandler final : public LLDispatchHandler +{ +public: + bool operator()( + const LLDispatcher* dispatcher, + const std::string& key, + const LLUUID& invoice, + const sparam_t& strings) override + { + LLSD message; + + sparam_t::const_iterator it = strings.begin(); + if(it != strings.end()){ + const std::string& llsdRaw = *it++; + std::istringstream llsdData(llsdRaw); + if (!LLSDSerialize::deserialize(message, llsdData, llsdRaw.length())) + { + LL_WARNS() << "LLExperienceLogDispatchHandler: Attempted to read parameter data into LLSD but failed:" << llsdRaw << LL_ENDL; + } + } + message["public_id"] = invoice; + + // Object Name + if(it != strings.end()) + { + message["ObjectName"] = *it++; + } + + // parcel Name + if(it != strings.end()) + { + message["ParcelName"] = *it++; + } + message["Count"] = 1; + + LLExperienceLog::instance().handleExperienceMessage(message); + return true; + } +}; + +static LLExperienceLogDispatchHandler experience_log_dispatch_handler; + +void LLExperienceLog::handleExperienceMessage(LLSD& message) +{ + time_t now; + time(&now); + char daybuf[16];/* Flawfinder: ignore */ + char time_of_day[16];/* Flawfinder: ignore */ + strftime(daybuf, 16, "%Y-%m-%d", localtime(&now)); + strftime(time_of_day, 16, " %H:%M:%S", localtime(&now)); + message["Time"] = time_of_day; + + std::string day = daybuf; + + if(!mEvents.has(day)) + { + mEvents[day] = LLSD::emptyArray(); + } + LLSD& dayEvents = mEvents[day]; + if(dayEvents.size() > 0) + { + LLSD& last = *(dayEvents.rbeginArray()); + if( last["public_id"].asUUID() == message["public_id"].asUUID() + && last["ObjectName"].asString() == message["ObjectName"].asString() + && last["OwnerID"].asUUID() == message["OwnerID"].asUUID() + && last["ParcelName"].asString() == message["ParcelName"].asString() + && last["Permission"].asInteger() == message["Permission"].asInteger()) + { + last["Count"] = last["Count"].asInteger() + 1; + last["Time"] = time_of_day; + mSignals(last); + return; + } + } + message["Time"] = time_of_day; + mEvents[day].append(message); + mSignals(message); +} + +LLExperienceLog::LLExperienceLog() + : mMaxDays(7) + , mPageSize(25) + , mNotifyNewEvent(false) +{ +} + +void LLExperienceLog::initialize() +{ + loadEvents(); + if(!gGenericDispatcher.isHandlerPresent("ExperienceEvent")) + { + gGenericDispatcher.addHandler("ExperienceEvent", &experience_log_dispatch_handler); + } +} + +std::string LLExperienceLog::getFilename() +{ + return gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "experience_events.xml"); +} + + +std::string LLExperienceLog::getPermissionString( const LLSD& message, const std::string& base ) +{ + std::ostringstream buf; + if(message.has("Permission")) + { + buf << base << message["Permission"].asInteger(); + std::string entry; + if(LLTrans::findString(entry, buf.str())) + { + buf.str(entry); + } + } + + if(buf.str().empty()) + { + buf << base << "Unknown"; + + buf.str(LLTrans::getString(buf.str(), message)); + } + + return buf.str(); +} + +void LLExperienceLog::notify( LLSD& message ) +{ + message["EventType"] = getPermissionString(message, "ExperiencePermission"); + if(message.has("IsAttachment") && message["IsAttachment"].asBoolean()) + { + LLNotificationsUtil::add("ExperienceEventAttachment", message); + } + else + { + LLNotificationsUtil::add("ExperienceEvent", message); + } + message.erase("EventType"); +} + +void LLExperienceLog::saveEvents() +{ + eraseExpired(); + std::string filename = getFilename(); + LLSD settings = LLSD::emptyMap().with("Events", mEvents); + + settings["MaxDays"] = (int)mMaxDays; + settings["Notify"] = mNotifyNewEvent; + settings["PageSize"] = (int)mPageSize; + + llofstream stream(filename.c_str()); + LLSDSerialize::toPrettyXML(settings, stream); +} + + +void LLExperienceLog::loadEvents() +{ + LLSD settings = LLSD::emptyMap(); + + std::string filename = getFilename(); + llifstream stream(filename.c_str()); + LLSDSerialize::fromXMLDocument(settings, stream); + + if(settings.has("MaxDays")) + { + setMaxDays((U32)settings["MaxDays"].asInteger()); + } + if(settings.has("Notify")) + { + setNotifyNewEvent(settings["Notify"].asBoolean()); + } + if(settings.has("PageSize")) + { + setPageSize((U32)settings["PageSize"].asInteger()); + } + mEvents.clear(); + if(mMaxDays > 0 && settings.has("Events")) + { + mEvents = settings["Events"]; + } + + eraseExpired(); +} + +LLExperienceLog::~LLExperienceLog() +{ + saveEvents(); +} + +void LLExperienceLog::eraseExpired() +{ + std::vector expired; + for (const auto& event_pair : mEvents.map()) + { + const std::string& date = event_pair.first; + if (isExpired(date)) + { + expired.push_back(date); + } + } + + for (const auto& date : expired) + { + mEvents.erase(date); + } +} + +bool LLExperienceLog::isExpired(const std::string& date) const +{ + if (date.empty()) + return true; + + S32 month, day, year = 0; + S32 matched = sscanf(date.c_str(), "%d-%d-%d", &year, &month, &day); + if (matched != 3) return false; + LLDate event_date; + event_date.fromYMDHMS(year, month, day); + + return event_date.secondsSinceEpoch() <= (LLDate::now().secondsSinceEpoch() - F64(getMaxDays() * 86400U)); +} + +const LLSD& LLExperienceLog::getEvents() const +{ + return mEvents; +} + +void LLExperienceLog::clear() +{ + mEvents.clear(); +} + +void LLExperienceLog::setMaxDays( U32 val ) +{ + mMaxDays = val; +} + +LLExperienceLog::callback_connection_t LLExperienceLog::addUpdateSignal( const callback_slot_t& cb ) +{ + return mSignals.connect(cb); +} + +void LLExperienceLog::setNotifyNewEvent( bool val ) +{ + mNotifyNewEvent = val; + if(!val && mNotifyConnection.connected()) + { + mNotifyConnection.disconnect(); + } + else if( val && !mNotifyConnection.connected()) + { + mNotifyConnection = addUpdateSignal(std::function(LLExperienceLog::notify)); + } +} diff --git a/indra/newview/llexperiencelog.h b/indra/newview/llexperiencelog.h new file mode 100644 index 000000000..27012898c --- /dev/null +++ b/indra/newview/llexperiencelog.h @@ -0,0 +1,86 @@ +/** + * @file llexperiencelog.h + * @brief llexperiencelog and related class definitions + * + * $LicenseInfo:firstyear=2014&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2014, 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_LLEXPERIENCELOG_H +#define LL_LLEXPERIENCELOG_H + +#include "llsingleton.h" + +class LLExperienceLog final : public LLSingleton +{ + friend class LLSingleton; + LLExperienceLog(); +public: + typedef boost::signals2::signal + callback_signal_t; + typedef callback_signal_t::slot_type callback_slot_t; + typedef boost::signals2::connection callback_connection_t; + callback_connection_t addUpdateSignal(const callback_slot_t& cb); + + void initialize(); + + U32 getMaxDays() const { return mMaxDays; } + void setMaxDays(U32 val); + + bool getNotifyNewEvent() const { return mNotifyNewEvent; } + void setNotifyNewEvent(bool val); + + U32 getPageSize() const { return mPageSize; } + void setPageSize(U32 val) { mPageSize = val; } + + const LLSD& getEvents()const; + void clear(); + + virtual ~LLExperienceLog(); + + static void notify(LLSD& message); + static std::string getFilename(); + static std::string getPermissionString(const LLSD& message, const std::string& base); + bool isExpired(const std::string& date) const; +protected: + void handleExperienceMessage(LLSD& message); + + + void loadEvents(); + void saveEvents(); + void eraseExpired(); + + LLSD mEvents; + callback_signal_t mSignals; + callback_connection_t mNotifyConnection; + U32 mMaxDays; + U32 mPageSize; + bool mNotifyNewEvent; + + friend class LLExperienceLogDispatchHandler; +}; + + + + +#endif // LL_LLEXPERIENCELOG_H diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp index 3ed58db98..254d750cb 100644 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -1130,7 +1130,7 @@ BOOL LLFavoritesBarCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask) show_navbar_context_menu(this,x,y); handled = true; }*/ - + return handled; } void copy_slurl_to_clipboard_cb(std::string& slurl) diff --git a/indra/newview/llfloaterauction.cpp b/indra/newview/llfloaterauction.cpp index 4a44b6a3a..cefa86f5c 100644 --- a/indra/newview/llfloaterauction.cpp +++ b/indra/newview/llfloaterauction.cpp @@ -3,38 +3,31 @@ * @author James Cook, Ian Wilkes * @brief Implementation of the auction floater. * - * $LicenseInfo:firstyear=2004&license=viewergpl$ - * - * Copyright (c) 2004-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * 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 + * Copyright (C) 2010, Linden Research, Inc. * - * 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 + * 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. * - * 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. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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 "llfloaterauction.h" -#include "lldir.h" #include "llgl.h" #include "llimagej2c.h" #include "llimagetga.h" @@ -46,17 +39,21 @@ #include "llagent.h" #include "llcombobox.h" +#include "llmimetypes.h" #include "llnotifications.h" -#include "llnotificationsutil.h" +#include "llnotificationsutil.h" #include "llviewertexturelist.h" #include "llviewerparcelmgr.h" #include "llviewerregion.h" -#include "lluictrlfactory.h" #include "llviewerwindow.h" #include "llviewerdisplay.h" #include "llviewercontrol.h" #include "llui.h" +#include "lluictrlfactory.h" #include "llrender.h" +#include "llsdutil.h" +#include "llsdutil_math.h" +#include "lltrans.h" ///---------------------------------------------------------------------------- /// Local function declarations, constants, enums, and typedefs @@ -74,8 +71,8 @@ void auction_tga_upload_done(const LLUUID& asset_id, LLFloaterAuction* LLFloaterAuction::sInstance = NULL; // Default constructor -LLFloaterAuction::LLFloaterAuction() : - LLFloater(std::string("floater_auction")), +LLFloaterAuction::LLFloaterAuction() + : LLFloater(std::string("floater_auction")), mParcelID(-1) { LLUICtrlFactory::getInstance()->buildFloater(this, "floater_auction.xml"); @@ -86,13 +83,13 @@ LLFloaterAuction::LLFloaterAuction() : onCommitControlSetting(gSavedSettings), (void*)"AuctionShowFence"); childSetAction("snapshot_btn", onClickSnapshot, this); - childSetAction("ok_btn", onClickOK, this); + childSetAction("ok_btn", onClickStartAuction, this); } // Destroys the object LLFloaterAuction::~LLFloaterAuction() { - sInstance = NULL; + sInstance = nullptr; } // static @@ -104,12 +101,23 @@ void LLFloaterAuction::show() sInstance->center(); sInstance->setFocus(TRUE); } - sInstance->initialize(); sInstance->open(); /*Flawfinder: ignore*/ } +BOOL LLFloaterAuction::postBuild() +{ + return TRUE; +} + +void LLFloaterAuction::onOpen() +{ + initialize(); +} + void LLFloaterAuction::initialize() { + mParcelUpdateCapUrl.clear(); + mParcelp = LLViewerParcelMgr::getInstance()->getParcelSelection(); LLViewerRegion* region = LLViewerParcelMgr::getInstance()->getSelectionRegion(); LLParcel* parcelp = mParcelp->getParcel(); @@ -117,28 +125,30 @@ void LLFloaterAuction::initialize() { mParcelHost = region->getHost(); mParcelID = parcelp->getLocalID(); + mParcelUpdateCapUrl = region->getCapability("ParcelPropertiesUpdate"); - childSetText("parcel_text", parcelp->getName()); - childEnable("snapshot_btn"); - childEnable("ok_btn"); + getChild("parcel_text")->setValue(parcelp->getName()); + getChildView("snapshot_btn")->setEnabled(TRUE); + getChildView("ok_btn")->setEnabled(true); } else { mParcelHost.invalidate(); if(parcelp && parcelp->getForSale()) { - childSetText("parcel_text", getString("already for sale")); + getChild("parcel_text")->setValue(getString("already for sale")); } else { - childSetText("parcel_text", LLStringUtil::null); + getChild("parcel_text")->setValue(LLStringUtil::null); } mParcelID = -1; - childSetEnabled("snapshot_btn", false); - childSetEnabled("ok_btn", false); + getChildView("snapshot_btn")->setEnabled(false); + getChildView("ok_btn")->setEnabled(false); } + mImageID.setNull(); - mImage = NULL; + mImage = nullptr; } void LLFloaterAuction::draw() @@ -147,9 +157,10 @@ void LLFloaterAuction::draw() if(!isMinimized() && mImage.notNull()) { - LLRect rect; - if (childGetRect("snapshot_icon", rect)) + LLView* snapshot_icon = findChild("snapshot_icon"); + if (snapshot_icon) { + LLRect rect = snapshot_icon->getRect(); { gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); gl_rect_2d(rect, LLColor4(0.f, 0.f, 0.f, 1.f)); @@ -176,7 +187,7 @@ void LLFloaterAuction::onClickSnapshot(void* data) LLPointer raw = new LLImageRaw; - gForceRenderLandFence = self->childGetValue("fence_check").asBoolean(); + gForceRenderLandFence = self->getChild("fence_check")->getValue().asBoolean(); BOOL success = gViewerWindow->rawSnapshot(raw, gViewerWindow->getWindowWidth(), gViewerWindow->getWindowHeight(), @@ -218,13 +229,13 @@ void LLFloaterAuction::onClickSnapshot(void* data) } // static -void LLFloaterAuction::onClickOK(void* data) +void LLFloaterAuction::onClickStartAuction(void* data) { LLFloaterAuction* self = (LLFloaterAuction*)(data); if(self->mImageID.notNull()) { - LLSD parcel_name = self->childGetValue("parcel_text"); + LLSD parcel_name = self->getChild("parcel_text")->getValue(); // create the asset std::string* name = new std::string(parcel_name.asString()); @@ -257,11 +268,243 @@ void LLFloaterAuction::onClickOK(void* data) msg->sendReliable(self->mParcelHost); // clean up floater, and get out - self->mImageID.setNull(); - self->mImage = NULL; - self->mParcelID = -1; - self->mParcelHost.invalidate(); - self->close(); + self->cleanupAndClose(); +} + + +void LLFloaterAuction::cleanupAndClose() +{ + mImageID.setNull(); + mImage = nullptr; + mParcelID = -1; + mParcelHost.invalidate(); + close(); +} + + + +// static glue +void LLFloaterAuction::onClickResetParcel(void* data) +{ + LLFloaterAuction* self = (LLFloaterAuction*)(data); + if (self) + { + self->doResetParcel(); + } +} + + +// Reset all the values for the parcel in preparation for a sale +void LLFloaterAuction::doResetParcel() +{ + LLParcel* parcelp = mParcelp->getParcel(); + LLViewerRegion* region = LLViewerParcelMgr::getInstance()->getSelectionRegion(); + + if (parcelp + && region + && !mParcelUpdateCapUrl.empty()) + { + LLSD body; + std::string empty; + + // request new properties update from simulator + U32 message_flags = 0x01; + body["flags"] = ll_sd_from_U32(message_flags); + + // Set all the default parcel properties for auction + body["local_id"] = parcelp->getLocalID(); + + U32 parcel_flags = PF_ALLOW_LANDMARK | + PF_ALLOW_FLY | + PF_CREATE_GROUP_OBJECTS | + PF_ALLOW_ALL_OBJECT_ENTRY | + PF_ALLOW_GROUP_OBJECT_ENTRY | + PF_ALLOW_GROUP_SCRIPTS | + PF_RESTRICT_PUSHOBJECT | + PF_SOUND_LOCAL | + PF_ALLOW_VOICE_CHAT | + PF_USE_ESTATE_VOICE_CHAN; + + body["parcel_flags"] = ll_sd_from_U32(parcel_flags); + + // Build a parcel name like "Ahern (128,128) PG 4032m" + std::ostringstream parcel_name; + LLVector3 center_point( parcelp->getCenterpoint() ); + center_point.snap(0); // Get rid of fractions + parcel_name << region->getName() + << " (" + << (S32) center_point.mV[VX] + << "," + << (S32) center_point.mV[VY] + << ") " + << region->getSimAccessString() + << " " + << parcelp->getArea() + << "m"; + + std::string new_name(parcel_name.str()); + body["name"] = new_name; + getChild("parcel_text")->setValue(new_name); // Set name in dialog as well, since it won't get updated otherwise + + body["sale_price"] = (S32) 0; + body["description"] = empty; + body["music_url"] = empty; + body["media_url"] = empty; + body["media_desc"] = empty; + body["media_type"] = LLMIMETypes::getDefaultMimeType(); + body["media_width"] = (S32) 0; + body["media_height"] = (S32) 0; + body["auto_scale"] = (S32) 0; + body["media_loop"] = (S32) 0; + body["obscure_media"] = (S32) 0; // OBSOLETE - no longer used + body["obscure_music"] = (S32) 0; // OBSOLETE - no longer used + body["media_id"] = LLUUID::null; + body["group_id"] = MAINTENANCE_GROUP_ID; // Use maintenance group + body["pass_price"] = (S32) 10; // Defaults to $10 + body["pass_hours"] = 0.0f; + body["category"] = (U8) LLParcel::C_NONE; + body["auth_buyer_id"] = LLUUID::null; + body["snapshot_id"] = LLUUID::null; + body["user_location"] = ll_sd_from_vector3( LLVector3::zero ); + body["user_look_at"] = ll_sd_from_vector3( LLVector3::zero ); + body["landing_type"] = (U8) LLParcel::L_DIRECT; + + LL_INFOS() << "Sending parcel update to reset for auction via capability to: " + << mParcelUpdateCapUrl << LL_ENDL; + LLHTTPClient::post(mParcelUpdateCapUrl, body, new LLHTTPClient::ResponderIgnore()); + + // Send a message to clear the object return time + LLMessageSystem *msg = gMessageSystem; + msg->newMessageFast(_PREHASH_ParcelSetOtherCleanTime); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_ParcelData); + msg->addS32Fast(_PREHASH_LocalID, parcelp->getLocalID()); + msg->addS32Fast(_PREHASH_OtherCleanTime, 5); // 5 minute object auto-return + + msg->sendReliable(region->getHost()); + + // Clear the access lists + clearParcelAccessList(parcelp, region, AL_ACCESS); + clearParcelAccessList(parcelp, region, AL_BAN); + clearParcelAccessList(parcelp, region, AL_ALLOW_EXPERIENCE); + clearParcelAccessList(parcelp, region, AL_BLOCK_EXPERIENCE); + } +} + + + +void LLFloaterAuction::clearParcelAccessList(LLParcel* parcel, LLViewerRegion* region, U32 list) +{ + if (!region || !parcel) return; + + LLUUID transactionUUID; + transactionUUID.generate(); + + LLMessageSystem* msg = gMessageSystem; + + msg->newMessageFast(_PREHASH_ParcelAccessListUpdate); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() ); + msg->nextBlockFast(_PREHASH_Data); + msg->addU32Fast(_PREHASH_Flags, list); + msg->addS32(_PREHASH_LocalID, parcel->getLocalID() ); + msg->addUUIDFast(_PREHASH_TransactionID, transactionUUID); + msg->addS32Fast(_PREHASH_SequenceID, 1); // sequence_id + msg->addS32Fast(_PREHASH_Sections, 0); // num_sections + + // pack an empty block since there will be no data + msg->nextBlockFast(_PREHASH_List); + msg->addUUIDFast(_PREHASH_ID, LLUUID::null ); + msg->addS32Fast(_PREHASH_Time, 0 ); + msg->addU32Fast(_PREHASH_Flags, 0 ); + + msg->sendReliable( region->getHost() ); +} + + + +// static - 'Sell to Anyone' clicked, throw up a confirmation dialog +void LLFloaterAuction::onClickSellToAnyone(void* data) +{ + LLFloaterAuction* self = (LLFloaterAuction*)(data); + if (self) + { + LLParcel* parcelp = self->mParcelp->getParcel(); + + // Do a confirmation + S32 sale_price = parcelp->getArea(); // Selling for L$1 per meter + S32 area = parcelp->getArea(); + + LLSD args; + args["LAND_SIZE"] = llformat("%d", area); + args["SALE_PRICE"] = llformat("%d", sale_price); + args["NAME"] = LLTrans::getString("Anyone"); + + LLNotification::Params params("ConfirmLandSaleChange"); // Re-use existing dialog + params.substitutions(args) + .functor/*.function*/(boost::bind(&LLFloaterAuction::onSellToAnyoneConfirmed, self, _1, _2)); + + params.name("ConfirmLandSaleToAnyoneChange"); + + // ask away + LLNotifications::instance().add(params); + } +} + + +// Sell confirmation clicked +bool LLFloaterAuction::onSellToAnyoneConfirmed(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option == 0) + { + doSellToAnyone(); + } + + return false; +} + + + +// Reset all the values for the parcel in preparation for a sale +void LLFloaterAuction::doSellToAnyone() +{ + LLParcel* parcelp = mParcelp->getParcel(); + LLViewerRegion* region = LLViewerParcelMgr::getInstance()->getSelectionRegion(); + + if (parcelp + && region + && !mParcelUpdateCapUrl.empty()) + { + LLSD body; + + // request new properties update from simulator + U32 message_flags = 0x01; + body["flags"] = ll_sd_from_U32(message_flags); + + // Set all the default parcel properties for auction + body["local_id"] = parcelp->getLocalID(); + + // Set 'for sale' flag + U32 parcel_flags = parcelp->getParcelFlags() | PF_FOR_SALE; + // Ensure objects not included + parcel_flags &= ~PF_FOR_SALE_OBJECTS; + body["parcel_flags"] = ll_sd_from_U32(parcel_flags); + + body["sale_price"] = parcelp->getArea(); // Sell for L$1 per square meter + body["auth_buyer_id"] = LLUUID::null; // To anyone + + LL_INFOS() << "Sending parcel update to sell to anyone for L$1 via capability to: " + << mParcelUpdateCapUrl << LL_ENDL; + + LLHTTPClient::post(mParcelUpdateCapUrl, body, new LLHTTPClient::ResponderIgnore()); + + // clean up floater, and get out + cleanupAndClose(); + } } diff --git a/indra/newview/llfloaterauction.h b/indra/newview/llfloaterauction.h index a9f1ea874..f431a84fc 100644 --- a/indra/newview/llfloaterauction.h +++ b/indra/newview/llfloaterauction.h @@ -3,31 +3,25 @@ * @author James Cook, Ian Wilkes * @brief llfloaterauction class header file * - * $LicenseInfo:firstyear=2004&license=viewergpl$ - * - * Copyright (c) 2004-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * 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 + * 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. * - * 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 + * 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. * - * 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. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -36,7 +30,7 @@ #include "llfloater.h" #include "lluuid.h" -#include "llmemory.h" +#include "llsafehandle.h" #include "llviewertexture.h" //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -45,34 +39,50 @@ // Class which holds the functionality to start auctions. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class LLParcelSelection; +class LLParcel; +class LLViewerRegion; -class LLFloaterAuction : public LLFloater +class LLFloaterAuction final : public LLFloater { public: // LLFloater interface - /*virtual*/ void onClose(bool app_quitting) { setVisible(FALSE); } - /*virtual*/ void draw(); + /*virtual*/ void onOpen() override; + /*virtual*/ void onClose(bool app_quitting) override { setVisible(FALSE); } + /*virtual*/ void draw() override; // LLFloaterAuction interface static void show(); - private: + LLFloaterAuction(); ~LLFloaterAuction(); + void initialize(); static void onClickSnapshot(void* data); - static void onClickOK(void* data); + static void onClickResetParcel(void* data); + static void onClickSellToAnyone(void* data); // Sell to anyone clicked + bool onSellToAnyoneConfirmed(const LLSD& notification, const LLSD& response); // Sell confirmation clicked + static void onClickStartAuction(void* data); static LLFloaterAuction* sInstance; + /*virtual*/ BOOL postBuild() override; + + void doResetParcel(); + void doSellToAnyone(); + void clearParcelAccessList(LLParcel* parcel, LLViewerRegion* region, U32 list); + void cleanupAndClose(); private: + LLTransactionID mTransactionID; LLAssetID mImageID; LLPointer mImage; LLSafeHandle mParcelp; S32 mParcelID; LLHost mParcelHost; + + std::string mParcelUpdateCapUrl; // "ParcelPropertiesUpdate" capability }; diff --git a/indra/newview/llfloateravatarlist.cpp b/indra/newview/llfloateravatarlist.cpp index 0f90007f0..427997c02 100644 --- a/indra/newview/llfloateravatarlist.cpp +++ b/indra/newview/llfloateravatarlist.cpp @@ -134,8 +134,9 @@ namespace } } //namespace +const LLColor4* mm_getMarkerColor(const LLUUID& id, bool mark_only = true); LLAvatarListEntry::LLAvatarListEntry(const LLUUID& id, const std::string& name, const LLVector3d& position) : - mID(id), mName(name), mPosition(position), mMarked(false), mFocused(false), + mID(id), mName(name), mPosition(position), mMarked(mm_getMarkerColor(id)), mFocused(false), mStats(), mActivityType(ACTIVITY_NEW), mActivityTimer(), mIsInList(false), mAge(-1), mTime(time(NULL)) @@ -322,6 +323,17 @@ bool is_nearby(const LLUUID& id) return std::find(avatars.begin(), avatars.end(), id) != avatars.end(); } +const LLVector3d& get_av_pos(const LLUUID& id) +{ + if (const auto inst = LLFloaterAvatarList::getIfExists()) + if (const auto av = inst->getAvatarEntry(id)) + return av->getPosition(); + + LLWorld::pos_map_t avatars; + LLWorld::instance().getAvatars(&avatars); + return avatars[id]; +} + void track_av(const LLUUID& id) { if (auto inst = LLFloaterAvatarList::getIfExists()) @@ -336,83 +348,60 @@ void track_av(const LLUUID& id) LLTracker::trackLocation(avatars[id], LLStringUtil::null, LLStringUtil::null); } -void teleport_to(const LLUUID& id) -{ - if (auto entry = LLFloaterAvatarList::instanceExists() ? LLFloaterAvatarList::instance().getAvatarEntry(id) : nullptr) - gAgent.teleportViaLocation(entry->getPosition()); - else - { - LLWorld::pos_map_t avatars; - LLWorld::instance().getAvatars(&avatars); - gAgent.teleportViaLocation(avatars[id]); - } -} - static void cmd_profile(const LLAvatarListEntry* entry); -static void cmd_toggle_mark(LLAvatarListEntry* entry); +static void cmd_toggle_mark(LLAvatarListEntry* entry) +{ + bool mark = !entry->isMarked(); + void mm_setcolor(LLUUID key, LLColor4 col); + void mm_clearMark(const LLUUID & id); + mark ? mm_setcolor(entry->getID(), LLColor4::red) : mm_clearMark(entry->getID()); + entry->setMarked(mark); +} static void cmd_ar(const LLAvatarListEntry* entry); static void cmd_teleport(const LLAvatarListEntry* entry); namespace { typedef LLMemberListener view_listener_t; - class RadarTrack : public view_listener_t + class RadarTrack final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLFloaterAvatarList::instance().onClickTrack(); return true; } }; - class RadarMark : public view_listener_t + class RadarFocus final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) - { - LLFloaterAvatarList::instance().doCommand(cmd_toggle_mark); - return true; - } - }; - - class RadarFocus : public view_listener_t - { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLFloaterAvatarList::setFocusAvatar(LFIDBearer::getActiveSelectedID()); return true; } }; - class RadarFocusPrev : public view_listener_t + class RadarFocusPrev final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLFloaterAvatarList::instance().focusOnPrev(userdata.asInteger()); return true; } }; - class RadarFocusNext : public view_listener_t + class RadarFocusNext final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLFloaterAvatarList::instance().focusOnNext(userdata.asInteger()); return true; } }; - class RadarTeleportTo : public view_listener_t + class RadarAnnounceKeys final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) - { - teleport_to(LFIDBearer::getActiveSelectedID()); - return true; - } - }; - - class RadarAnnounceKeys : public view_listener_t - { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLFloaterAvatarList::instance().sendKeys(); return true; @@ -425,11 +414,9 @@ void addMenu(view_listener_t* menu, const std::string& name); void add_radar_listeners() { addMenu(new RadarTrack, "Radar.Track"); - addMenu(new RadarMark, "Radar.Mark"); addMenu(new RadarFocus, "Radar.Focus"); addMenu(new RadarFocusPrev, "Radar.FocusPrev"); addMenu(new RadarFocusNext, "Radar.FocusNext"); - addMenu(new RadarTeleportTo, "Radar.TeleportTo"); addMenu(new RadarAnnounceKeys, "Radar.AnnounceKeys"); } @@ -790,7 +777,7 @@ void LLFloaterAvatarList::refreshAvatarList() if (entry->isMarked()) { mark.value = "X"; - mark.color = LLColor4::blue; + mark.color = *mm_getMarkerColor(av_id); mark.font_style = "BOLD"; } element.columns.add(mark); @@ -1246,7 +1233,7 @@ void LLFloaterAvatarList::removeFocusFromAll() // static void LLFloaterAvatarList::setFocusAvatar(const LLUUID& id) { - if (!gAgentCamera.lookAtObject(id, false) && !lookAtAvatar(id)) return; + if (/*!gAgentCamera.lookAtObject(id, false) &&*/ !lookAtAvatar(id)) return; if (auto inst = getIfExists()) inst->setFocusAvatarInternal(id); } @@ -1460,7 +1447,6 @@ void send_estate_message(const std::string request, const std::vectorgetName()); } -static void cmd_toggle_mark(LLAvatarListEntry* entry) { entry->toggleMark(); } static void cmd_ar(const LLAvatarListEntry* entry) { LLFloaterReporter::showFromObject(entry->getID()); } static void cmd_profile(const LLAvatarListEntry* entry) { LLAvatarActions::showProfile(entry->getID()); } static void cmd_teleport(const LLAvatarListEntry* entry) { gAgent.teleportViaLocation(entry->getPosition()); } diff --git a/indra/newview/llfloateravatarlist.h b/indra/newview/llfloateravatarlist.h index 480e52f52..5c8321987 100644 --- a/indra/newview/llfloateravatarlist.h +++ b/indra/newview/llfloateravatarlist.h @@ -124,7 +124,7 @@ enum ACTIVITY_TYPE bool isInList() const { return mIsInList; } - void toggleMark() { mMarked = !mMarked; } + void setMarked(bool marked) { mMarked = marked; } struct uuidMatch { diff --git a/indra/newview/llfloaterchat.cpp b/indra/newview/llfloaterchat.cpp index e36a41975..a2c7a2d12 100644 --- a/indra/newview/llfloaterchat.cpp +++ b/indra/newview/llfloaterchat.cpp @@ -225,12 +225,13 @@ void add_timestamped_line(LLViewerTextEditor* edit, LLChat chat, const LLColor4& style->setColor(color); style->mItalic = is_irc; style->mBold = chat.mChatType == CHAT_TYPE_SHOUT; - edit->appendText(line, false, prepend_newline, style, false); + edit->appendText(line, false, prepend_newline, style, chat.mSourceType == CHAT_SOURCE_SYSTEM); } void LLFloaterChat::addChatHistory(const std::string& str, bool log_to_file) { LLChat chat(str); + chat.mSourceType = CHAT_SOURCE_SYSTEM; addChatHistory(chat, log_to_file); } @@ -276,7 +277,7 @@ void LLFloaterChat::addChatHistory(LLChat& chat, bool log_to_file) LLColor4 color = get_text_color(chat); - if (!log_to_file) color = LLColor4::grey; //Recap from log file. + if (!log_to_file) color = gSavedSettings.getColor("LogChatColor"); //Recap from log file. if (chat.mChatType == CHAT_TYPE_DEBUG_MSG) { @@ -344,6 +345,7 @@ void LLFloaterChat::onClickToggleShowMute(bool show_mute, LLTextEditor* history_ void LLFloaterChat::addChat(const std::string& str, BOOL from_im, BOOL local_agent) { LLChat chat(str); + chat.mSourceType = CHAT_SOURCE_SYSTEM; addChat(chat, from_im, local_agent); } diff --git a/indra/newview/llfloaterexperiencepicker.cpp b/indra/newview/llfloaterexperiencepicker.cpp new file mode 100644 index 000000000..7613001b3 --- /dev/null +++ b/indra/newview/llfloaterexperiencepicker.cpp @@ -0,0 +1,167 @@ +/** +* @file llfloaterexperiencepicker.cpp +* @brief Implementation of llfloaterexperiencepicker +* @author dolphin@lindenlab.com +* +* $LicenseInfo:firstyear=2014&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2014, 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 "llfloaterexperiencepicker.h" + + +#include "lllineeditor.h" +//#include "llfloaterreg.h" +#include "lluictrlfactory.h" +#include "llscrolllistctrl.h" +#include "llviewerregion.h" +#include "llagent.h" +#include "llexperiencecache.h" +#include "llslurl.h" +#include "llavatarnamecache.h" +#include "llfloaterexperienceprofile.h" +#include "llcombobox.h" +#include "llviewercontrol.h" +#include "lldraghandle.h" +#include "llpanelexperiencepicker.h" + +// +LLFloaterExperiencePicker* show_xp_picker(const LLSD& key) +{ + LLFloaterExperiencePicker* floater = + LLFloaterExperiencePicker::getInstance(key); + if (!floater) + { + floater = new LLFloaterExperiencePicker(key); + } + floater->open(); + return floater; +} +// + +LLFloaterExperiencePicker* LLFloaterExperiencePicker::show( select_callback_t callback, const LLUUID& key, BOOL allow_multiple, BOOL close_on_select, filter_list filters, LLView * frustumOrigin ) +{ + LLFloaterExperiencePicker* floater = show_xp_picker(key); + + if (floater->mSearchPanel) + { + floater->mSearchPanel->mSelectionCallback = callback; + floater->mSearchPanel->mCloseOnSelect = close_on_select; + floater->mSearchPanel->setAllowMultiple(allow_multiple); + floater->mSearchPanel->setDefaultFilters(); + floater->mSearchPanel->addFilters(filters.begin(), filters.end()); + floater->mSearchPanel->filterContent(); + } + + if(frustumOrigin) + { + floater->mFrustumOrigin = frustumOrigin->getHandle(); + } + + return floater; +} + +void LLFloaterExperiencePicker::drawFrustum() +{ + if(mFrustumOrigin.get()) + { + LLView * frustumOrigin = mFrustumOrigin.get(); + LLRect origin_rect; + frustumOrigin->localRectToOtherView(frustumOrigin->getLocalRect(), &origin_rect, this); + // draw context cone connecting color picker with color swatch in parent floater + LLRect local_rect = getLocalRect(); + if (hasFocus() && frustumOrigin->isInVisibleChain() && mContextConeOpacity > 0.001f) + { + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + LLGLEnable cull_face; + gGL.begin(LLRender::TRIANGLE_STRIP); + { + gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity); + gGL.vertex2i(local_rect.mLeft, local_rect.mTop); + gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity); + gGL.vertex2i(origin_rect.mLeft, origin_rect.mTop); + gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity); + gGL.vertex2i(local_rect.mRight, local_rect.mTop); + gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity); + gGL.vertex2i(origin_rect.mRight, origin_rect.mTop); + gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity); + gGL.vertex2i(local_rect.mRight, local_rect.mBottom); + gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity); + gGL.vertex2i(origin_rect.mRight, origin_rect.mBottom); + gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity); + gGL.vertex2i(local_rect.mLeft, local_rect.mBottom); + gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity); + gGL.vertex2i(origin_rect.mLeft, origin_rect.mBottom); + gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity); + gGL.vertex2i(local_rect.mLeft, local_rect.mTop); + gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity); + gGL.vertex2i(origin_rect.mLeft, origin_rect.mTop); + } + gGL.end(); + } + + if (gFocusMgr.childHasMouseCapture(getDragHandle())) + { + mContextConeOpacity = lerp(mContextConeOpacity, gSavedSettings.getF32("PickerContextOpacity"), LLCriticalDamp::getInterpolant(mContextConeFadeTime)); + } + else + { + mContextConeOpacity = lerp(mContextConeOpacity, 0.f, LLCriticalDamp::getInterpolant(mContextConeFadeTime)); + } + } +} + +void LLFloaterExperiencePicker::draw() +{ + drawFrustum(); + LLFloater::draw(); +} + +LLFloaterExperiencePicker::LLFloaterExperiencePicker( const LLSD& key ) + :LLFloater() + ,LLInstanceTracker(key.asUUID()) + ,mSearchPanel(nullptr) + ,mContextConeOpacity(0.f) + ,mContextConeInAlpha(0.f) + ,mContextConeOutAlpha(0.f) + ,mContextConeFadeTime(0.f) +{ + mContextConeInAlpha = gSavedSettings.getF32("ContextConeInAlpha"); + mContextConeOutAlpha = gSavedSettings.getF32("ContextConeOutAlpha"); + mContextConeFadeTime = gSavedSettings.getF32("ContextConeFadeTime"); + LLUICtrlFactory::getInstance()->buildFloater(this, "floater_experience_search.xml", NULL, false); + //buildFromFile("floater_experience_search.xml"); +} + +LLFloaterExperiencePicker::~LLFloaterExperiencePicker() +{ + gFocusMgr.releaseFocusIfNeeded( this ); +} + +BOOL LLFloaterExperiencePicker::postBuild() +{ + mSearchPanel = new LLPanelExperiencePicker(); + addChild(mSearchPanel); + mSearchPanel->setOrigin(0, 0); + return LLFloater::postBuild(); +} diff --git a/indra/newview/llfloaterexperiencepicker.h b/indra/newview/llfloaterexperiencepicker.h new file mode 100644 index 000000000..4aff63169 --- /dev/null +++ b/indra/newview/llfloaterexperiencepicker.h @@ -0,0 +1,69 @@ +/** +* @file llfloaterexperiencepicker.h +* @brief Header file for llfloaterexperiencepicker +* @author dolphin@lindenlab.com +* +* $LicenseInfo:firstyear=2014&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2014, 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_LLFLOATEREXPERIENCEPICKER_H +#define LL_LLFLOATEREXPERIENCEPICKER_H + +#include "llfloater.h" +#include "llinstancetracker.h" + +class LLScrollListCtrl; +class LLLineEditor; +class LLPanelExperiencePicker; + + +class LLFloaterExperiencePicker : public LLFloater +, public LLInstanceTracker +{ +public: + + typedef std::function select_callback_t; + // filter function for experiences, return true if the experience should be hidden. + typedef std::function filter_function; + typedef std::vector filter_list; + + static LLFloaterExperiencePicker* show( select_callback_t callback, const LLUUID& key, BOOL allow_multiple, BOOL close_on_select, filter_list filters, LLView * frustumOrigin); + + LLFloaterExperiencePicker(const LLSD& key); + virtual ~LLFloaterExperiencePicker(); + + BOOL postBuild() override; + + void draw() override; +private: + + LLPanelExperiencePicker* mSearchPanel; + + void drawFrustum(); + LLHandle mFrustumOrigin; + F32 mContextConeOpacity; + F32 mContextConeInAlpha; + F32 mContextConeOutAlpha; + F32 mContextConeFadeTime; +}; + +#endif // LL_LLFLOATEREXPERIENCEPICKER_H + diff --git a/indra/newview/llfloaterexperienceprofile.cpp b/indra/newview/llfloaterexperienceprofile.cpp new file mode 100644 index 000000000..3195a3bda --- /dev/null +++ b/indra/newview/llfloaterexperienceprofile.cpp @@ -0,0 +1,934 @@ +/** + * @file llfloaterexperienceprofile.cpp + * @brief llfloaterexperienceprofile and related class definitions + * + * $LicenseInfo:firstyear=2013&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2013, 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 "llfloaterexperienceprofile.h" + +#include "llagent.h" +#include "llappviewer.h" +#include "llavatarnamecache.h" +#include "llcheckboxctrl.h" +#include "llcombobox.h" +#include "llcommandhandler.h" +//#include "llexpandabletextbox.h" +#include "llexperiencecache.h" +//#include "llfloaterreg.h" +#include "llgroupactions.h" +#include "lluictrlfactory.h" +#include "lllayoutstack.h" +#include "lllineeditor.h" +#include "llnotificationsutil.h" +#include "llsdserialize.h" +#include "llslurl.h" +#include "lltabcontainer.h" +#include "lltextbox.h" +#include "lltexteditor.h" +#include "lltexturectrl.h" +#include "lltrans.h" +#include "llviewerregion.h" +#include "llevents.h" +#include "llfloatergroups.h" +#include "llnotifications.h" +#include "llfloaterreporter.h" +#include "llurlaction.h" + +#define XML_PANEL_EXPERIENCE_PROFILE "floater_experienceprofile.xml" +#define TF_NAME "experience_title" +#define TF_DESC "experience_description" +#define TF_SLURL "LocationTextText" +#define TF_MRKT "marketplace" +#define TF_MATURITY "ContentRatingText" +#define TF_OWNER "OwnerText" +#define TF_GROUP "GroupText" +#define TF_GRID_WIDE "grid_wide" +#define TF_PRIVILEGED "privileged" +#define EDIT "edit_" + +#define IMG_LOGO "logo" + +#define PNL_TOP "top panel" +#define PNL_IMAGE "image_panel" +#define PNL_DESC "description panel" +#define PNL_LOC "location panel" +#define PNL_MRKT "marketplace panel" +#define PNL_GROUP "group_panel" +#define PNL_PERMS "perm panel" + +#define BTN_ALLOW "allow_btn" +#define BTN_BLOCK "block_btn" +#define BTN_CANCEL "cancel_btn" +#define BTN_CLEAR_LOCATION "clear_btn" +#define BTN_EDIT "edit_btn" +#define BTN_ENABLE "enable_btn" +#define BTN_FORGET "forget_btn" +#define BTN_PRIVATE "private_btn" +#define BTN_REPORT "report_btn" +#define BTN_SAVE "save_btn" +#define BTN_SET_GROUP "Group_btn" +#define BTN_SET_LOCATION "location_btn" + + +class LLExperienceHandler : public LLCommandHandler +{ +public: + LLExperienceHandler() : LLCommandHandler("experience", UNTRUSTED_THROTTLE) { } + + bool handle(const LLSD& params, const LLSD& query_map, + LLMediaCtrl* web) override + { + if (params.size() != 2 || params[1].asString() != "profile") + return false; + + LLExperienceCache::instance().get(params[0].asUUID(), boost::bind(&LLExperienceHandler::experienceCallback, this, _1)); + return true; + } + + void experienceCallback(const LLSD& experienceDetails) + { + if (!experienceDetails.has(LLExperienceCache::MISSING)) + { + LLFloaterExperienceProfile::showInstance(experienceDetails[LLExperienceCache::EXPERIENCE_ID].asUUID()); + } + } +}; + +LLExperienceHandler gExperienceHandler; + +void LLFloaterExperienceProfile::showInstance(const LLSD& data) +{ + bool is_map = data.has("experience_id"); + LLFloaterExperienceProfile* floater = getInstance(is_map ? data["experience_id"].asUUID() : data.asUUID()); + if (!floater) floater = new LLFloaterExperienceProfile(data); + else if (is_map && data.has("edit_experience") && data["edit_experience"].asBoolean()) + floater->changeToEdit(); + floater->open(); +} + +LLFloaterExperienceProfile::LLFloaterExperienceProfile(const LLSD& data) + : LLFloater(), LLInstanceTracker(data.asUUID()) + , mSaveCompleteAction(NOTHING) + , mDirty(false) + , mForceClose(false) +{ + if (data.has("experience_id")) +{ + mExperienceId = data["experience_id"].asUUID(); + mPostEdit = data.has("edit_experience") && data["edit_experience"].asBoolean(); +} + else +{ + mExperienceId = data.asUUID(); + mPostEdit = false; + } + LLUICtrlFactory::getInstance()->buildFloater(this, XML_PANEL_EXPERIENCE_PROFILE, NULL, false); + //buildFromFile(XML_PANEL_EXPERIENCE_PROFILE); +} + + +LLFloaterExperienceProfile::~LLFloaterExperienceProfile() +{ + +} + +BOOL LLFloaterExperienceProfile::postBuild() +{ + + if (mExperienceId.notNull()) + { + LLExperienceCache::instance().fetch(mExperienceId, true); + LLExperienceCache::instance().get(mExperienceId, boost::bind(&LLFloaterExperienceProfile::experienceCallback, + getDerivedHandle(), _1)); + + LLViewerRegion* region = gAgent.getRegion(); + if (region) + { + LLExperienceCache::instance().getExperienceAdmin(mExperienceId, boost::bind( + &LLFloaterExperienceProfile::experienceIsAdmin, getDerivedHandle(), _1)); + } + } + + childSetAction(BTN_EDIT, boost::bind(&LLFloaterExperienceProfile::onClickEdit, this)); + childSetAction(BTN_ALLOW, boost::bind(&LLFloaterExperienceProfile::onClickPermission, this, "Allow")); + childSetAction(BTN_FORGET, boost::bind(&LLFloaterExperienceProfile::onClickForget, this)); + childSetAction(BTN_BLOCK, boost::bind(&LLFloaterExperienceProfile::onClickPermission, this, "Block")); + childSetAction(BTN_CANCEL, boost::bind(&LLFloaterExperienceProfile::onClickCancel, this)); + childSetAction(BTN_SAVE, boost::bind(&LLFloaterExperienceProfile::onClickSave, this)); + childSetAction(BTN_SET_LOCATION, boost::bind(&LLFloaterExperienceProfile::onClickLocation, this)); + childSetAction(BTN_CLEAR_LOCATION, boost::bind(&LLFloaterExperienceProfile::onClickClear, this)); + childSetAction(BTN_SET_GROUP, boost::bind(&LLFloaterExperienceProfile::onPickGroup, this)); + childSetAction(BTN_REPORT, boost::bind(&LLFloaterExperienceProfile::onReportExperience, this)); + + getChild(EDIT TF_DESC)->setKeystrokeCallback(boost::bind(&LLFloaterExperienceProfile::onFieldChanged, this)); + getChild(EDIT TF_MATURITY)->setCommitCallback(boost::bind(&LLFloaterExperienceProfile::onFieldChanged, this)); + getChild(EDIT TF_MRKT)->setKeystrokeCallback(boost::bind(&LLFloaterExperienceProfile::onFieldChanged, this)); + getChild(EDIT TF_NAME)->setKeystrokeCallback(boost::bind(&LLFloaterExperienceProfile::onFieldChanged, this)); + + childSetCommitCallback(EDIT BTN_ENABLE, boost::bind(&LLFloaterExperienceProfile::onFieldChanged, this), nullptr); + childSetCommitCallback(EDIT BTN_PRIVATE, boost::bind(&LLFloaterExperienceProfile::onFieldChanged, this), nullptr); + + childSetCommitCallback(EDIT IMG_LOGO, boost::bind(&LLFloaterExperienceProfile::onFieldChanged, this), nullptr); + + if (auto logo = findChild(IMG_LOGO)) + { + void show_picture(const LLUUID& id, const std::string& name); + LLTextBox* name = getChild(TF_NAME); + std::function cb = [logo, name]() { show_picture(logo->getImageAssetID(), "Experience Picture: " + name->getText()); }; + logo->setMouseUpCallback(boost::bind(cb)); + } + + getChild(EDIT TF_DESC)->setCommitOnFocusLost(TRUE); + + LLEventPumps::instance().obtain("experience_permission").listen(mExperienceId.asString()+"-profile", + boost::bind(&LLFloaterExperienceProfile::experiencePermission, getDerivedHandle(this), _1)); + + if (mPostEdit && mExperienceId.notNull()) + { + mPostEdit = false; + changeToEdit(); + } + + return TRUE; +} + +void LLFloaterExperienceProfile::experienceCallback(LLHandle handle, const LLSD& experience ) +{ + LLFloaterExperienceProfile* pllpep = handle.get(); + if (pllpep) + { + pllpep->refreshExperience(experience); + } +} + + +bool LLFloaterExperienceProfile::experiencePermission( LLHandle handle, const LLSD& permission ) +{ + LLFloaterExperienceProfile* pllpep = handle.get(); + if (pllpep) + { + pllpep->updatePermission(permission); + } + return false; +} + + +void LLFloaterExperienceProfile::onClickEdit() +{ + changeToEdit(); +} + + +void LLFloaterExperienceProfile::onClickCancel() +{ + changeToView(); +} + +void LLFloaterExperienceProfile::onClickSave() +{ + doSave(NOTHING); +} + +void LLFloaterExperienceProfile::onClickPermission(const char* perm) +{ + LLViewerRegion* region = gAgent.getRegion(); + if (!region) + return; + LLExperienceCache::instance().setExperiencePermission(mExperienceId, perm, boost::bind( + &LLFloaterExperienceProfile::experiencePermissionResults, mExperienceId, _1)); +} + + +void LLFloaterExperienceProfile::onClickForget() +{ + LLViewerRegion* region = gAgent.getRegion(); + if (!region) + return; + + LLExperienceCache::instance().forgetExperiencePermission(mExperienceId, boost::bind( + &LLFloaterExperienceProfile::experiencePermissionResults, mExperienceId, _1)); +} + +bool LLFloaterExperienceProfile::setMaturityString( U8 maturity, LLTextBox* child, LLComboBox* combo ) +{ + //LLStyle::Params style; // Singu Note: Nope. + std::string access; + if (maturity <= SIM_ACCESS_PG) + { + //style.image(LLUI::getUIImage(getString("maturity_icon_general"))); // Singu Note: Nope. + access = LLTrans::getString("SIM_ACCESS_PG"); + combo->setCurrentByIndex(2); + } + else if (maturity <= SIM_ACCESS_MATURE) + { + //style.image(LLUI::getUIImage(getString("maturity_icon_moderate"))); // Singu Note: Nope. + access = LLTrans::getString("SIM_ACCESS_MATURE"); + combo->setCurrentByIndex(1); + } + else if (maturity <= SIM_ACCESS_ADULT) + { + //style.image(LLUI::getUIImage(getString("maturity_icon_adult"))); // Singu Note: Nope. + access = LLTrans::getString("SIM_ACCESS_ADULT"); + combo->setCurrentByIndex(0); + } + else + { + return false; + } + + /* Singu Note: Nope. + child->setText(LLStringUtil::null); + + child->appendImageSegment(style); + */ + child->setText(access); + + return true; +} + + +void LLFloaterExperienceProfile::refreshExperience( const LLSD& experience ) +{ + mExperienceDetails = experience; + mPackage = experience; + + + LLLayoutPanel* imagePanel = getChild(PNL_IMAGE); + LLLayoutPanel* descriptionPanel = getChild(PNL_DESC); + LLLayoutPanel* locationPanel = getChild(PNL_LOC); + LLLayoutPanel* marketplacePanel = getChild(PNL_MRKT); + LLLayoutPanel* topPanel = getChild(PNL_TOP); + + + imagePanel->setVisible(FALSE); + descriptionPanel->setVisible(FALSE); + locationPanel->setVisible(FALSE); + marketplacePanel->setVisible(FALSE); + topPanel->setVisible(FALSE); + + + LLTextBox* child = getChild(TF_NAME); + //child->setText(experience[LLExperienceCache::NAME].asString()); + child->setValue(experience[LLExperienceCache::EXPERIENCE_ID].asUUID()); + + LLLineEditor* linechild = getChild(EDIT TF_NAME); + linechild->setText(experience[LLExperienceCache::NAME].asString()); + + std::string value = experience[LLExperienceCache::DESCRIPTION].asString(); + LLTextEditor* exchild = getChild(TF_DESC); + exchild->setText(value); + descriptionPanel->setVisible(value.length()>0); + + LLTextEditor* edit_child = getChild(EDIT TF_DESC); + edit_child->setText(value); + + mLocationSLURL = experience[LLExperienceCache::SLURL].asString(); + edit_child = getChild(TF_SLURL); + bool has_slurl = !mLocationSLURL.empty() && mLocationSLURL != "last"; + locationPanel->setVisible(has_slurl); + if (has_slurl) mLocationSLURL = LLSLURL(mLocationSLURL).getSLURLString(); + edit_child->setText(mLocationSLURL); + + + edit_child = getChild(EDIT TF_SLURL); + if (has_slurl) + { + edit_child->setText(mLocationSLURL); + } + else + { + edit_child->setText(getString("empty_slurl")); + } + + setMaturityString((U8)(experience[LLExperienceCache::MATURITY].asInteger()), getChild(TF_MATURITY), getChild(EDIT TF_MATURITY)); + + LLUUID agent_id = experience[LLExperienceCache::AGENT_ID].asUUID(); + getChild(TF_OWNER)->setValue(agent_id); + + LLUUID id = experience[LLExperienceCache::GROUP_ID].asUUID(); + bool id_null = id.isNull(); + if (!id_null) + { + getChild(TF_GROUP)->setValue(id); + } + getChild(PNL_GROUP)->setVisible(!id_null); + + setEditGroup(id); + + getChild(BTN_SET_GROUP)->setEnabled(agent_id == gAgentID); + + LLCheckBoxCtrl* enable = getChild(EDIT BTN_ENABLE); + S32 properties = mExperienceDetails[LLExperienceCache::PROPERTIES].asInteger(); + enable->set(!(properties & LLExperienceCache::PROPERTY_DISABLED)); + + enable = getChild(EDIT BTN_PRIVATE); + enable->set(properties & LLExperienceCache::PROPERTY_PRIVATE); + + topPanel->setVisible(TRUE); + child=getChild(TF_GRID_WIDE); + child->setVisible(TRUE); + + if(properties & LLExperienceCache::PROPERTY_GRID) + { + child->setText(LLTrans::getString("Grid-Scope")); + } + else + { + child->setText(LLTrans::getString("Land-Scope")); + } + + if (getChild(BTN_EDIT)->getVisible()) + { + topPanel->setVisible(TRUE); + } + + if (properties & LLExperienceCache::PROPERTY_PRIVILEGED) + { + child = getChild(TF_PRIVILEGED); + child->setVisible(TRUE); + } + else + { + LLViewerRegion* region = gAgent.getRegion(); + if (region) + { + LLExperienceCache::instance().getExperiencePermission(mExperienceId, boost::bind( + &LLFloaterExperienceProfile::experiencePermissionResults, mExperienceId, _1)); + } + } + + value=experience[LLExperienceCache::METADATA].asString(); + if (value.empty()) + return; + + LLPointer parser = new LLSDXMLParser(); + + LLSD data; + + std::istringstream is(value); + if (LLSDParser::PARSE_FAILURE != parser->parse(is, data, value.size())) + { + value.clear(); + if (data.has(TF_MRKT)) + { + value=data[TF_MRKT].asString(); + + edit_child = getChild(TF_MRKT); + edit_child->setText(value); + if(!value.empty()) + { + marketplacePanel->setVisible(TRUE); + } + else + { + marketplacePanel->setVisible(FALSE); + } + } + else + { + marketplacePanel->setVisible(FALSE); + } + + linechild = getChild(EDIT TF_MRKT); + linechild->setText(value); + + if (data.has(IMG_LOGO)) + { + LLTextureCtrl* logo = getChild(IMG_LOGO); + + LLUUID id = data[IMG_LOGO].asUUID(); + logo->setImageAssetID(id); + imagePanel->setVisible(TRUE); + + logo = getChild(EDIT IMG_LOGO); + logo->setImageAssetID(data[IMG_LOGO].asUUID()); + + imagePanel->setVisible(id.notNull()); + } + } + else + { + marketplacePanel->setVisible(FALSE); + imagePanel->setVisible(FALSE); + } + + mDirty=false; + mForceClose = false; + getChild(BTN_SAVE)->setEnabled(mDirty); +} + +void LLFloaterExperienceProfile::setPreferences( const LLSD& content ) +{ + S32 properties = mExperienceDetails[LLExperienceCache::PROPERTIES].asInteger(); + if (properties & LLExperienceCache::PROPERTY_PRIVILEGED) + { + return; + } + + const LLSD& experiences = content["experiences"]; + const LLSD& blocked = content["blocked"]; + + + for(const auto& exp : experiences.array()) + { + if (exp.asUUID()==mExperienceId) + { + experienceAllowed(); + return; + } + } + + for(const auto& exp : blocked.array()) + { + if (exp.asUUID()==mExperienceId) + { + experienceBlocked(); + return; + } + } + + experienceForgotten(); +} + +void LLFloaterExperienceProfile::onFieldChanged() +{ + updatePackage(); + + if (!getChild(BTN_EDIT)->getVisible()) + { + return; + } + + mDirty = mPackage.size() != mExperienceDetails.size(); + if (!mDirty) + { + LLSD::map_const_iterator st = mExperienceDetails.beginMap(); + LLSD::map_const_iterator dt = mPackage.beginMap(); + LLSD::map_const_iterator ste = mExperienceDetails.endMap(); + LLSD::map_const_iterator dte = mPackage.endMap(); + for (; st != ste && dt != dte; ++st, ++dt) + if (mDirty = st->first != dt->first || st->second.asString() != dt->second.asString()) + break; + } + + getChild(BTN_SAVE)->setEnabled(mDirty); +} + + +BOOL LLFloaterExperienceProfile::canClose() +{ + if (mForceClose || !mDirty) + { + return TRUE; + } + else + { + // Bring up view-modal dialog: Save changes? Yes, No, Cancel + LLNotificationsUtil::add("SaveChanges", LLSD(), LLSD(), boost::bind(&LLFloaterExperienceProfile::handleSaveChangesDialog, this, _1, _2, CLOSE)); + return FALSE; + } +} + +bool LLFloaterExperienceProfile::handleSaveChangesDialog( const LLSD& notification, const LLSD& response, PostSaveAction action ) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + switch( option ) + { + case 0: // "Yes" + // close after saving + doSave( action ); + break; + + case 1: // "No" + if (action != NOTHING) + { + mForceClose = TRUE; + if (action==CLOSE) + { + close(); + } + else + { + changeToView(); + } + } + break; + + case 2: // "Cancel" + default: + // If we were quitting, we didn't really mean it. + LLAppViewer::instance()->abortQuit(); + break; + } + return false; +} + +void LLFloaterExperienceProfile::doSave( int success_action ) +{ + mSaveCompleteAction=success_action; + + LLViewerRegion* region = gAgent.getRegion(); + if (!region) + return; + + LLExperienceCache::instance().updateExperience(mPackage, boost::bind( + &LLFloaterExperienceProfile::experienceUpdateResult, + getDerivedHandle(), _1)); +} + +void LLFloaterExperienceProfile::onSaveComplete( const LLSD& content ) +{ + LLUUID id = getExperienceId(); + + if (content.has("removed")) + { + const LLSD& removed = content["removed"]; + for(const auto& it : removed.map()) + { + const std::string& field = it.first; + if (field == LLExperienceCache::EXPERIENCE_ID) + { + //this message should be removed by the experience api + continue; + } + const LLSD& data = it.second; + std::string error_tag = data["error_tag"].asString()+ "ExperienceProfileMessage"; + LLSD fields; + if (LLNotificationTemplates::instance().templateExists(error_tag)) + { + fields["field"] = field; + fields["extra_info"] = data["extra_info"]; + LLNotificationsUtil::add(error_tag, fields); + } + else + { + fields["MESSAGE"] = data["en"]; + LLNotificationsUtil::add("GenericAlert", fields); + } + } + } + + if (!content.has("experience_keys")) + { + LL_WARNS() << "LLFloaterExperienceProfile::onSaveComplete called with bad content" << LL_ENDL; + return; + } + + const LLSD& experiences = content["experience_keys"]; + + if (experiences.size() == 0) + { + LL_WARNS() << "LLFloaterExperienceProfile::onSaveComplete called with empty content" << LL_ENDL; + return; + } + + const auto& exp = experiences[0]; + if (!exp.has(LLExperienceCache::EXPERIENCE_ID) || (exp[LLExperienceCache::EXPERIENCE_ID].asUUID() != id)) + { + LL_WARNS() << "LLFloaterExperienceProfile::onSaveComplete called with unexpected experience id" << LL_ENDL; + return; + } + + refreshExperience(exp); + LLExperienceCache::instance().insert(exp); + LLExperienceCache::instance().fetch(id, true); + + if (mSaveCompleteAction == VIEW) + { + LLTabContainer* tabs = getChild("tab_container"); + tabs->selectTabByName("panel_experience_info"); + } + else if (mSaveCompleteAction == CLOSE) + { + close(); + } +} + +void LLFloaterExperienceProfile::changeToView() +{ + if (mForceClose || !mDirty) + { + refreshExperience(mExperienceDetails); + LLTabContainer* tabs = getChild("tab_container"); + + tabs->selectTabByName("panel_experience_info"); + } + else + { + // Bring up view-modal dialog: Save changes? Yes, No, Cancel + LLNotificationsUtil::add("SaveChanges", LLSD(), LLSD(), boost::bind(&LLFloaterExperienceProfile::handleSaveChangesDialog, this, _1, _2, VIEW)); + } +} + +void LLFloaterExperienceProfile::changeToEdit() +{ + LLTabContainer* tabs = getChild("tab_container"); + + tabs->selectTabByName("edit_panel_experience_info"); +} + +void LLFloaterExperienceProfile::onClickLocation() +{ + LLViewerRegion* region = gAgent.getRegion(); + if (region) + { + auto child = getChild(EDIT TF_SLURL); + mLocationSLURL = LLSLURL(region->getName(), gAgent.getPositionGlobal()).getSLURLString(); + child->setText(mLocationSLURL); + onFieldChanged(); + } +} + +void LLFloaterExperienceProfile::onClickClear() +{ + auto child = getChild(EDIT TF_SLURL); + mLocationSLURL.clear(); + child->setText(getString("empty_slurl")); + onFieldChanged(); +} + +void LLFloaterExperienceProfile::updatePermission(const LLSD& permission) +{ + if (permission.has("experience")) + { + if (permission["experience"].asUUID() != mExperienceId) + { + return; + } + + std::string str = permission[mExperienceId.asString()]["permission"].asString(); + if (str == "Allow") + { + experienceAllowed(); + } + else if (str == "Block") + { + experienceBlocked(); + } + else if (str == "Forget") + { + experienceForgotten(); + } + } + else + { + setPreferences(permission); + } +} + +void LLFloaterExperienceProfile::experienceAllowed() +{ + LLButton* button=getChild(BTN_ALLOW); + button->setEnabled(FALSE); + + button=getChild(BTN_FORGET); + button->setEnabled(TRUE); + + button=getChild(BTN_BLOCK); + button->setEnabled(TRUE); +} + +void LLFloaterExperienceProfile::experienceForgotten() +{ + LLButton* button=getChild(BTN_ALLOW); + button->setEnabled(TRUE); + + button=getChild(BTN_FORGET); + button->setEnabled(FALSE); + + button=getChild(BTN_BLOCK); + button->setEnabled(TRUE); +} + +void LLFloaterExperienceProfile::experienceBlocked() +{ + LLButton* button=getChild(BTN_ALLOW); + button->setEnabled(TRUE); + + button=getChild(BTN_FORGET); + button->setEnabled(TRUE); + + button=getChild(BTN_BLOCK); + button->setEnabled(FALSE); +} + +void LLFloaterExperienceProfile::onClose( bool app_quitting ) +{ + LLEventPumps::instance().obtain("experience_permission").stopListening(mExperienceId.asString()+"-profile"); + LLFloater::onClose(app_quitting); +} + +void LLFloaterExperienceProfile::updatePackage() +{ + mPackage[LLExperienceCache::NAME] = getChild(EDIT TF_NAME)->getText(); + mPackage[LLExperienceCache::DESCRIPTION] = getChild(EDIT TF_DESC)->getText(); + if (mLocationSLURL.empty()) + { + mPackage[LLExperienceCache::SLURL] = LLStringUtil::null; + } + else + { + mPackage[LLExperienceCache::SLURL] = mLocationSLURL; + } + + mPackage[LLExperienceCache::MATURITY] = getChild(EDIT TF_MATURITY)->getSelectedValue().asInteger(); + + LLSD metadata; + + metadata[TF_MRKT] = getChild(EDIT TF_MRKT)->getText(); + metadata[IMG_LOGO] = getChild(EDIT IMG_LOGO)->getImageAssetID(); + + LLPointer formatter = new LLSDXMLFormatter(); + + std::ostringstream os; + if (formatter->format(metadata, os)) + { + mPackage[LLExperienceCache::METADATA] = os.str(); + } + + int properties = mPackage[LLExperienceCache::PROPERTIES].asInteger(); + LLCheckBoxCtrl* enable = getChild(EDIT BTN_ENABLE); + if (enable->get()) + { + properties &= ~LLExperienceCache::PROPERTY_DISABLED; + } + else + { + properties |= LLExperienceCache::PROPERTY_DISABLED; + } + + enable = getChild(EDIT BTN_PRIVATE); + if (enable->get()) + { + properties |= LLExperienceCache::PROPERTY_PRIVATE; + } + else + { + properties &= ~LLExperienceCache::PROPERTY_PRIVATE; + } + + mPackage[LLExperienceCache::PROPERTIES] = properties; +} + +void LLFloaterExperienceProfile::onPickGroup() +{ + LLFloater* parent_floater = gFloaterView->getParentFloater(this); + + LLFloaterGroupPicker* widget = LLFloaterGroupPicker::showInstance(gAgent.getID()); + if (widget) + { + widget->setSelectGroupCallback(boost::bind(&LLFloaterExperienceProfile::setEditGroup, this, _1)); + if (parent_floater) + { + LLRect new_rect = gFloaterView->findNeighboringPosition(parent_floater, widget); + widget->setOrigin(new_rect.mLeft, new_rect.mBottom); + parent_floater->addDependentFloater(widget); + } + } +} + +void LLFloaterExperienceProfile::setEditGroup( LLUUID group_id ) +{ + LLTextBox* child = getChild(EDIT TF_GROUP); + child->setValue(group_id); + mPackage[LLExperienceCache::GROUP_ID] = group_id; + onFieldChanged(); +} + +void LLFloaterExperienceProfile::onReportExperience() +{ + LLFloaterReporter::showFromExperience(mExperienceId); +} + +/*static*/ +bool LLFloaterExperienceProfile::hasPermission(const LLSD& content, const std::string &name, const LLUUID &test) +{ + if (!content.has(name)) + return false; + + const LLSD& list = content[name]; + for (const auto& it : list.array()) + { + if (it.asUUID() == test) + { + return true; + } + } + return false; +} + +/*static*/ +void LLFloaterExperienceProfile::experiencePermissionResults(const LLUUID& exprienceId, const LLSD& result) +{ + std::string permission("Forget"); + if (hasPermission(result, "experiences", exprienceId)) + permission = "Allow"; + else if (hasPermission(result, "blocked", exprienceId)) + permission = "Block"; + + LLSD experience; + LLSD message; + experience["permission"] = permission; + message["experience"] = exprienceId; + message[exprienceId.asString()] = experience; + + LLEventPumps::instance().obtain("experience_permission").post(message); +} + +/*static*/ +void LLFloaterExperienceProfile::experienceIsAdmin(LLHandle handle, const LLSD &result) +{ + LLFloaterExperienceProfile* parent = handle.get(); + if (!parent) + return; + + bool enabled = true; + LLViewerRegion* region = gAgent.getRegion(); + if (!region) + { + enabled = false; + } + else + { + std::string url = region->getCapability("UpdateExperience"); + if (url.empty()) + enabled = false; + } + if (enabled && result["status"].asBoolean()) + { + parent->getChild(PNL_TOP)->setVisible(TRUE); + parent->getChild(BTN_EDIT)->setVisible(TRUE); + } +} + +/*static*/ +void LLFloaterExperienceProfile::experienceUpdateResult(LLHandle handle, const LLSD &result) +{ + LLFloaterExperienceProfile* parent = handle.get(); + if (parent) + { + parent->onSaveComplete(result); + } +} diff --git a/indra/newview/llfloaterexperienceprofile.h b/indra/newview/llfloaterexperienceprofile.h new file mode 100644 index 000000000..d9dad7784 --- /dev/null +++ b/indra/newview/llfloaterexperienceprofile.h @@ -0,0 +1,113 @@ +/** + * @file llfloaterexperienceprofile.h + * @brief llfloaterexperienceprofile and related class definitions + * + * $LicenseInfo:firstyear=2013&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2013, 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_LLFLOATEREXPERIENCEPROFILE_H +#define LL_LLFLOATEREXPERIENCEPROFILE_H + +#include "llfloater.h" +#include "lluuid.h" +#include "llsd.h" + +class LLLayoutPanel; +class LLTextBox; +class LLComboBox; + +class LLFloaterExperienceProfile final : public LLFloater +, public LLInstanceTracker +{ + LOG_CLASS(LLFloaterExperienceProfile); +public: + enum PostSaveAction + { + NOTHING, + CLOSE, + VIEW, + }; + + static void experiencePermissionResults(const LLUUID& exprienceId, const LLSD& result); + + static void showInstance(const LLSD& data); + LLFloaterExperienceProfile(const LLSD& data); + virtual ~LLFloaterExperienceProfile(); + + LLUUID getExperienceId() const { return mExperienceId; } + void setPreferences( const LLSD& content ); + + + void refreshExperience(const LLSD& experience); + void onSaveComplete( const LLSD& content ); + BOOL canClose() override; + + void onClose(bool app_quitting) override; +protected: + void onClickEdit(); + void onClickPermission(const char* permission); + void onClickForget(); + void onClickCancel(); + void onClickSave(); + void onClickLocation(); + void onClickClear(); + void onPickGroup(); + void onFieldChanged(); + void onReportExperience(); + + void setEditGroup(LLUUID group_id); + + void changeToView(); + void changeToEdit(); + + void experienceForgotten(); + void experienceBlocked(); + void experienceAllowed(); + + static void experienceCallback(LLHandle handle, const LLSD& experience); + static bool experiencePermission(LLHandle handle, const LLSD& permission); + + BOOL postBuild() override; + bool setMaturityString(U8 maturity, LLTextBox* child, LLComboBox* combo); + bool handleSaveChangesDialog(const LLSD& notification, const LLSD& response, PostSaveAction action); + void doSave( int success_action ); + + void updatePackage(); + + void updatePermission( const LLSD& permission ); + LLUUID mExperienceId; + LLSD mExperienceDetails; + LLSD mPackage; + std::string mLocationSLURL; + int mSaveCompleteAction; + bool mDirty; + bool mForceClose; + bool mPostEdit; // edit experience after opening and updating it +private: + static bool hasPermission(const LLSD& content, const std::string &name, const LLUUID &test); + static void experienceIsAdmin(LLHandle handle, const LLSD &result); + static void experienceUpdateResult(LLHandle handle, const LLSD &result); +}; + +#endif // LL_LLFLOATEREXPERIENCEPROFILE_H diff --git a/indra/newview/llfloaterexperiences.cpp b/indra/newview/llfloaterexperiences.cpp new file mode 100644 index 000000000..395b09470 --- /dev/null +++ b/indra/newview/llfloaterexperiences.cpp @@ -0,0 +1,377 @@ +/** + * @file llfloaterexperiences.cpp + * @brief LLFloaterExperiences class implementation + * + * $LicenseInfo:firstyear=2012&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, 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 "llfloaterexperiences.h" + +#include "llagent.h" +#include "llcororesponder.h" +#include "llevents.h" +#include "llexperiencecache.h" +#include "llfloaterexperienceprofile.h" +#include "llfloaterregioninfo.h" +#include "llnotificationsutil.h" +#include "llpanelexperiencelog.h" +#include "llpanelexperiencepicker.h" +#include "llpanelexperiences.h" +#include "lltabcontainer.h" +#include "lltrans.h" +#include "lluictrlfactory.h" +#include "llviewerregion.h" + + +#define SHOW_RECENT_TAB (0) +LLFloaterExperiences::LLFloaterExperiences(const LLSD& data) + :LLFloater(data) +{ + LLUICtrlFactory::getInstance()->buildFloater(this, "floater_experiences.xml", NULL, false); + //buildFromFile("floater_experiences.xml"); +} + +LLPanelExperiences* LLFloaterExperiences::addTab(const std::string& name, bool select) +{ + LLPanelExperiences* newPanel = LLPanelExperiences::create(name); + getChild("xp_tabs")->addTabPanel( + newPanel, + LLTrans::getString(name), + select); + + return newPanel; +} + +BOOL LLFloaterExperiences::postBuild() +{ + LLPanel* panel = new LLPanelExperiencePicker(); + getChild("xp_tabs")->addTabPanel(panel, panel->getLabel()); + addTab("Allowed_Experiences_Tab", true); + addTab("Blocked_Experiences_Tab", false); + addTab("Admin_Experiences_Tab", false); + addTab("Contrib_Experiences_Tab", false); + LLPanelExperiences* owned = addTab("Owned_Experiences_Tab", false); + owned->setButtonAction("acquire", boost::bind(&LLFloaterExperiences::sendPurchaseRequest, this)); + owned->enableButton(false); +#if SHOW_RECENT_TAB + addTab("Recent_Experiences_Tab", false); +#endif //SHOW_RECENT_TAB + panel = new LLPanelExperienceLog(); + getChild("xp_tabs")->addTabPanel(panel, panel->getLabel()); + resizeToTabs(); + + return TRUE; +} + + +void LLFloaterExperiences::clearFromRecent(const LLSD& ids) +{ +#if SHOW_RECENT_TAB + LLTabContainer* tabs = getChild("xp_tabs"); + + LLPanelExperiences* tab = (LLPanelExperiences*)tabs->getPanelByName("Recent_Experiences_Tab"); + if(!tab) + return; + + tab->removeExperiences(ids); +#endif // SHOW_RECENT_TAB +} + +void LLFloaterExperiences::setupRecentTabs() +{ +#if SHOW_RECENT_TAB + LLTabContainer* tabs = getChild("xp_tabs"); + + LLPanelExperiences* tab = (LLPanelExperiences*)tabs->getPanelByName("Recent_Experiences_Tab"); + if(!tab) + return; + + LLSD recent; + + const LLExperienceCache::cache_t& experiences = LLExperienceCache::getCached(); + + LLExperienceCache::cache_t::const_iterator it = experiences.begin(); + while( it != experiences.end() ) + { + if(!it->second.has(LLExperienceCache::MISSING)) + { + recent.append(it->first); + } + ++it; + } + + tab->setExperienceList(recent); +#endif // SHOW_RECENT_TAB +} + + +void LLFloaterExperiences::resizeToTabs() +{ + const S32 TAB_WIDTH_PADDING = 16; + + LLTabContainer* tabs = getChild("xp_tabs"); + LLRect rect = getRect(); + if(rect.getWidth() < tabs->getTotalTabWidth() + TAB_WIDTH_PADDING) + { + rect.mRight = rect.mLeft + tabs->getTotalTabWidth() + TAB_WIDTH_PADDING; + } + reshape(rect.getWidth(), rect.getHeight(), FALSE); +} + +void LLFloaterExperiences::refreshContents() +{ + setupRecentTabs(); + + LLViewerRegion* region = gAgent.getRegion(); + + if (region) + { + NameMap_t tabMap; + LLHandle handle = getDerivedHandle(); + + tabMap["experiences"]="Allowed_Experiences_Tab"; + tabMap["blocked"]="Blocked_Experiences_Tab"; + tabMap["experience_ids"]="Owned_Experiences_Tab"; + + retrieveExperienceList(region->getCapability("GetExperiences"), handle, tabMap); + + updateInfo("GetAdminExperiences","Admin_Experiences_Tab"); + updateInfo("GetCreatorExperiences","Contrib_Experiences_Tab"); + + retrieveExperienceList(region->getCapability("AgentExperiences"), handle, tabMap, + "ExperienceAcquireFailed", boost::bind(&LLFloaterExperiences::checkPurchaseInfo, this, _1, _2)); + } +} + +void LLFloaterExperiences::onOpen() +{ + LLEventPumps::instance().obtain("experience_permission").stopListening("LLFloaterExperiences"); + LLEventPumps::instance().obtain("experience_permission").listen("LLFloaterExperiences", + boost::bind(&LLFloaterExperiences::updatePermissions, this, _1)); + + LLViewerRegion* region = gAgent.getRegion(); + if(region) + { + if(region->capabilitiesReceived()) + { + refreshContents(); + return; + } + region->setCapabilitiesReceivedCallback(boost::bind(&LLFloaterExperiences::refreshContents, this)); + return; + } +} + +bool LLFloaterExperiences::updatePermissions( const LLSD& permission ) +{ + LLTabContainer* tabs = getChild("xp_tabs"); + LLUUID experience; + std::string permission_string; + if(permission.has("experience")) + { + experience = permission["experience"].asUUID(); + permission_string = permission[experience.asString()]["permission"].asString(); + + } + LLPanelExperiences* tab = (LLPanelExperiences*)tabs->getPanelByName("Allowed_Experiences_Tab"); + if(tab) + { + if(permission.has("experiences")) + { + tab->setExperienceList(permission["experiences"]); + } + else if(experience.notNull()) + { + if(permission_string != "Allow") + { + tab->removeExperience(experience); + } + else + { + tab->addExperience(experience); + } + } + } + + tab = (LLPanelExperiences*)tabs->getPanelByName("Blocked_Experiences_Tab"); + if(tab) + { + if(permission.has("blocked")) + { + tab->setExperienceList(permission["blocked"]); + } + else if(experience.notNull()) + { + if(permission_string != "Block") + { + tab->removeExperience(experience); + } + else + { + tab->addExperience(experience); + } + } + } + return false; +} + +void LLFloaterExperiences::onClose( bool app_quitting ) +{ + LLEventPumps::instance().obtain("experience_permission").stopListening("LLFloaterExperiences"); + LLFloater::onClose(app_quitting); +} + +void LLFloaterExperiences::checkPurchaseInfo(LLPanelExperiences* panel, const LLSD& content) const +{ + panel->enableButton(content.has("purchase")); + + LLFloaterExperiences::findInstance()->updateInfo("GetAdminExperiences","Admin_Experiences_Tab"); + LLFloaterExperiences::findInstance()->updateInfo("GetCreatorExperiences","Contrib_Experiences_Tab"); +} + +void LLFloaterExperiences::checkAndOpen(LLPanelExperiences* panel, const LLSD& content) const +{ + checkPurchaseInfo(panel, content); + + // determine new item + const LLSD& response_ids = content["experience_ids"]; + + if (mPrepurchaseIds.size() + 1 == response_ids.size()) + { + // we have a new element + for (const auto& it : response_ids.array()) + { + LLUUID experience_id = it.asUUID(); + if (std::find(mPrepurchaseIds.begin(), mPrepurchaseIds.end(), experience_id) == mPrepurchaseIds.end()) + { + // new element found, open it + LLSD args; + args["experience_id"] = experience_id; + args["edit_experience"] = true; + LLFloaterExperienceProfile::showInstance(args); + break; + } + } + } +} + +void LLFloaterExperiences::updateInfo(std::string experienceCap, std::string tab) +{ + LLViewerRegion* region = gAgent.getRegion(); + if (region) + { + NameMap_t tabMap; + LLHandle handle = getDerivedHandle(); + + tabMap["experience_ids"] = tab; + + retrieveExperienceList(region->getCapability(experienceCap), handle, tabMap); + } +} + +void LLFloaterExperiences::sendPurchaseRequest() +{ + LLViewerRegion* region = gAgent.getRegion(); + + if (region) + { + NameMap_t tabMap; + const std::string tab_owned_name = "Owned_Experiences_Tab"; + LLHandle handle = getDerivedHandle(); + + tabMap["experience_ids"] = tab_owned_name; + + // extract ids for experiences that we already have + LLTabContainer* tabs = getChild("xp_tabs"); + LLPanelExperiences* tab_owned = (LLPanelExperiences*)tabs->getPanelByName(tab_owned_name); + mPrepurchaseIds.clear(); + if (tab_owned) + { + tab_owned->getExperienceIdsList(mPrepurchaseIds); + } + + requestNewExperience(region->getCapability("AgentExperiences"), handle, tabMap, "ExperienceAcquireFailed", + boost::bind(&LLFloaterExperiences::checkAndOpen, this, _1, _2)); + } +} + + +void LLFloaterExperiences::retrieveExperienceList(const std::string &url, + const LLHandle &hparent, const NameMap_t &tabMapping, + const std::string &errorNotify, Callback_t cback, bool post) +{ + if (url.empty()) + { + LL_WARNS() << "retrieveExperienceListCoro called with empty capability!" << LL_ENDL; + return; + } + + auto responder = new LLCoroResponder( + boost::bind(LLFloaterExperiences::retrieveExperienceListCoro, _1, + hparent, tabMapping, errorNotify, cback)); + + if (post) + LLHTTPClient::post(url, LLSD(), responder); + else + LLHTTPClient::get(url, responder); +} + +void LLFloaterExperiences::retrieveExperienceListCoro(const LLCoroResponder& responder, + LLHandle hparent, NameMap_t tabMapping, + std::string errorNotify, Callback_t cback) +{ + LLSD result = responder.getContent(); + + if (!responder.isGoodStatus(responder.getStatus())) + { + LLSD subs; + subs["ERROR_MESSAGE"] = responder.getReason(); + LLNotificationsUtil::add(errorNotify, subs); + + return; + } + + if (hparent.isDead()) + return; + + LLFloaterExperiences* parent = hparent.get(); + LLTabContainer* tabs = parent->getChild("xp_tabs"); + + for (auto& it : tabMapping) + { + if (result.has(it.first)) + { + LLPanelExperiences* tab = (LLPanelExperiences*)tabs->getPanelByName(it.second); + if (tab) + { + const LLSD& ids = result[it.first]; + tab->setExperienceList(ids); + if (cback != nullptr) + { + cback(tab, result); + } + } + } + } + +} diff --git a/indra/newview/llfloaterexperiences.h b/indra/newview/llfloaterexperiences.h new file mode 100644 index 000000000..ebe1a00fe --- /dev/null +++ b/indra/newview/llfloaterexperiences.h @@ -0,0 +1,78 @@ +/** + * @file llfloaterexperiences.h + * @brief LLFloaterExperiences class definition + * + * $LicenseInfo:firstyear=2012&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, 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_LLFLOATEREXPERIENCES_H +#define LL_LLFLOATEREXPERIENCES_H + +#include "llfloater.h" + +class LLPanelExperiences; + +class LLFloaterExperiences final : + public LLFloater +, public LLFloaterSingleton +{ + friend class LLUISingleton >; +public: + LLFloaterExperiences(const LLSD& data); + void onClose(bool app_quitting) override; + + void onOpen(/*const LLSD& key*/) override; + +protected: + typedef std::map NameMap_t; + typedef std::function Callback_t; + + void clearFromRecent(const LLSD& ids); + void resizeToTabs(); + /*virtual*/ BOOL postBuild() override; + void refreshContents(); + void setupRecentTabs(); + LLPanelExperiences* addTab(const std::string& name, bool select); + + bool updatePermissions(const LLSD& permission); + void sendPurchaseRequest(); + void checkPurchaseInfo(LLPanelExperiences* panel, const LLSD& content)const; + void checkAndOpen(LLPanelExperiences* panel, const LLSD& content) const; + void updateInfo(std::string experiences, std::string tab); + + void retrieveExperienceList(const std::string &url, const LLHandle &hparent, const NameMap_t &tabMapping, + const std::string &errorNotify = std::string("ErrorMessage"), Callback_t cback = Callback_t(), bool post = false); + + void requestNewExperience(const std::string &url, const LLHandle &hparent, const NameMap_t &tabMapping, + const std::string &errorNotify, Callback_t cback) + { + retrieveExperienceList(url, hparent, tabMapping, errorNotify, cback, true); + } + +private: + static void retrieveExperienceListCoro(const struct LLCoroResponder& responder, LLHandle hparent, + NameMap_t tabMapping, std::string errorNotify, Callback_t cback); + uuid_vec_t mPrepurchaseIds; +}; + +#endif //LL_LLFLOATEREXPERIENCES_H + diff --git a/indra/newview/llfloatergroups.cpp b/indra/newview/llfloatergroups.cpp index 5367bcc6d..0e3374ecf 100644 --- a/indra/newview/llfloatergroups.cpp +++ b/indra/newview/llfloatergroups.cpp @@ -375,7 +375,6 @@ LLSD create_group_element(const LLGroupData *group_datap, const LLUUID &active_g void init_group_list(LLScrollListCtrl* ctrl, const LLUUID& highlight_id, U64 powers_mask) { - S32 count = gAgent.mGroups.size(); LLUUID id; LLCtrlListInterface *group_list = ctrl->getListInterface(); if (!group_list) return; @@ -386,11 +385,16 @@ void init_group_list(LLScrollListCtrl* ctrl, const LLUUID& highlight_id, U64 pow group_list->operateOnAll(LLCtrlListInterface::OP_DELETE); - for(S32 i = 0; i < count; ++i) + for(const auto& group : gAgent.mGroups) { - LLSD element = create_group_element(&gAgent.mGroups[i], highlight_id, powers_mask); - if(element.size()) + LLSD element = create_group_element(&group, highlight_id, powers_mask); + if (element.size()) + { group_list->addElement(element, ADD_SORTED); + // Force a name lookup here to get it added to the cache so other UI is prepared + std::string dummy; + gCacheName->getGroupName(group.mID, dummy); + } } // add "none" to list at top diff --git a/indra/newview/llfloaterland.cpp b/indra/newview/llfloaterland.cpp index df031e4d8..0ad893756 100644 --- a/indra/newview/llfloaterland.cpp +++ b/indra/newview/llfloaterland.cpp @@ -46,16 +46,16 @@ #include "llagent.h" #include "llagentaccess.h" -#include "llavataractions.h" #include "llbutton.h" #include "llcheckboxctrl.h" #include "llcombobox.h" -#include "llfloaterauction.h" #include "llfloateravatarpicker.h" +#include "llfloaterauction.h" #include "llfloaterbanduration.h" #include "llfloatergroups.h" #include "llfloaterscriptlimits.h" -#include "llgroupactions.h" +#include "llavataractions.h" +#include "lllayoutstack.h" #include "lllineeditor.h" #include "llnamelistctrl.h" #include "llpanellandaudio.h" @@ -64,6 +64,7 @@ #include "llscrolllistctrl.h" #include "llscrolllistitem.h" #include "llselectmgr.h" +#include "llslurl.h" #include "llspinctrl.h" #include "lltabcontainer.h" #include "lltextbox.h" @@ -81,15 +82,20 @@ #include "roles_constants.h" #include "llworld.h" #include "lltrans.h" +#include "llpanelexperiencelisteditor.h" +#include "llpanelexperiencepicker.h" +#include "llexperiencecache.h" +#include "llgroupactions.h" #include "hippogridmanager.h" - // [RLVa:KB] #include "rlvhandler.h" // [/RLVa:KB] +const F64 COVENANT_REFRESH_TIME_SEC = 60.0f; + static std::string OWNER_ONLINE = "0"; static std::string OWNER_OFFLINE = "1"; static std::string OWNER_GROUP = "2"; @@ -98,17 +104,37 @@ static std::string OWNER_INSIM = "4"; // constants used in callbacks below - syntactic sugar. static const BOOL BUY_GROUP_LAND = TRUE; static const BOOL BUY_PERSONAL_LAND = FALSE; -LLPointer LLPanelLandGeneral::sSelectionForBuyPass = NULL; // Statics LLParcelSelectionObserver* LLFloaterLand::sObserver = NULL; S32 LLFloaterLand::sLastTab = 0; // Local classes -class LLParcelSelectionObserver : public LLParcelObserver +class LLParcelSelectionObserver final : public LLParcelObserver { public: - virtual void changed() { LLFloaterLand::refreshAll(); } + void changed() override { LLFloaterLand::refreshAll(); } +}; + +class LLPanelLandExperiences final + : public LLPanel +{ +public: + LLPanelLandExperiences(LLSafeHandle& parcelp); + BOOL postBuild() override; + void refresh() override; + + void experienceAdded(const LLUUID& id, U32 xp_type, U32 access_type); + void experienceRemoved(const LLUUID& id, U32 access_type); +protected: + void setupList(LLPanelExperienceListEditor* child, const char* control_name, U32 xp_type, U32 access_type ); + void refreshPanel(LLPanelExperienceListEditor* panel, U32 xp_type); + + LLSafeHandle& mParcel; + + + LLPanelExperienceListEditor* mAllowed; + LLPanelExperienceListEditor* mBlocked; }; //--------------------------------------------------------------------------- @@ -203,7 +229,7 @@ void LLFloaterLand::refreshAll() void LLFloaterLand::onOpen() { - // moved from triggering show instance in llviwermenu.cpp + // moved from triggering show instance in llviewermenu.cpp if (LLViewerParcelMgr::getInstance()->selectionEmpty()) { @@ -221,21 +247,9 @@ void LLFloaterLand::onOpen() refresh(); } -// virtual -void LLFloaterLand::onClose(bool app_quitting) -{ - // Might have been showing owned objects - LLSelectMgr::getInstance()->unhighlightAll(); - - // Save which panel we had open - sLastTab = mTabLand->getCurrentPanelIndex(); - - destroy(); -} - LLFloaterLand::LLFloaterLand(const LLSD& seed) - : LLFloater(std::string("floaterland"), std::string("FloaterLandRect5"), std::string("About Land")) +: LLFloater(std::string("floaterland"), std::string("FloaterLandRect5"), std::string("About Land")) , mTabLand(nullptr) , mPanelGeneral(nullptr) , mPanelObjects(nullptr) @@ -243,6 +257,7 @@ LLFloaterLand::LLFloaterLand(const LLSD& seed) , mPanelMedia(nullptr) , mPanelAccess(nullptr) , mPanelCovenant(nullptr) + , mPanelExperiences(nullptr) { mFactoryMap["land_general_panel"] = LLCallbackMap(createPanelLandGeneral, this); mFactoryMap["land_covenant_panel"] = LLCallbackMap(createPanelLandCovenant, this); @@ -251,6 +266,7 @@ LLFloaterLand::LLFloaterLand(const LLSD& seed) mFactoryMap["land_audio_panel"] = LLCallbackMap(createPanelLandAudio, this); mFactoryMap["land_media_panel"] = LLCallbackMap(createPanelLandMedia, this); mFactoryMap["land_access_panel"] = LLCallbackMap(createPanelLandAccess, this); + //mFactoryMap["land_experiences_panel"] = LLCallbackMap(createPanelLandExperiences, this); // We need to buildPanel this, so we call this in postBuild LLUICtrlFactory::getInstance()->buildFloater(this, "floater_about_land.xml", &getFactoryMap(), false); @@ -266,6 +282,8 @@ BOOL LLFloaterLand::postBuild() if (tab) { + if (!gAgent.getRegion()->getCapability("RegionExperiences").empty()) + createPanelLandExperiences(this); // We need to buildPanel this, so call it here instead of during floater building tab->selectTab(sLastTab); } @@ -295,10 +313,9 @@ void LLFloaterLand::refresh() mPanelMedia->refresh(); mPanelAccess->refresh(); mPanelCovenant->refresh(); + if (mPanelExperiences) mPanelExperiences->refresh(); } - - void* LLFloaterLand::createPanelLandGeneral(void* data) { LLFloaterLand* self = (LLFloaterLand*)data; @@ -331,14 +348,6 @@ void* LLFloaterLand::createPanelLandOptions(void* data) return self->mPanelOptions; } -// static -void* LLFloaterLand::createPanelLandAudio(void* data) -{ - LLFloaterLand* self = (LLFloaterLand*)data; - self->mPanelAudio = new LLPanelLandAudio(self->mParcel); - return self->mPanelAudio; -} - // static void* LLFloaterLand::createPanelLandMedia(void* data) { @@ -355,6 +364,26 @@ void* LLFloaterLand::createPanelLandAccess(void* data) return self->mPanelAccess; } +// static +void* LLFloaterLand::createPanelLandAudio(void* data) +{ + LLFloaterLand* self = (LLFloaterLand*)data; + self->mPanelAudio = new LLPanelLandAudio(self->mParcel); + return self->mPanelAudio; +} + +// static +void* LLFloaterLand::createPanelLandExperiences(void* data) +{ + LLFloaterLand* self = static_cast(data); + self->mPanelExperiences = new LLPanelLandExperiences(self->mParcel); + self->mTabLand->addTabPanel(self->mPanelExperiences, self->mPanelExperiences->getLabel()); // We must build this panel separately from the floater xml, so add it to the tab container manually. + return self->mPanelExperiences; +} + + +LLPointer LLPanelLandGeneral::sSelectionForBuyPass = NULL; + //--------------------------------------------------------------------------- // LLPanelLandGeneral //--------------------------------------------------------------------------- @@ -398,12 +427,12 @@ LLPanelLandGeneral::LLPanelLandGeneral(LLParcelSelectionHandle& parcel) BOOL LLPanelLandGeneral::postBuild() { mEditName = getChild("Name"); - mEditName->setCommitCallback(onCommitAny, this); + mEditName->setCommitCallback(boost::bind(&LLPanelLandGeneral::onCommitAny, this)); getChild("Name")->setPrevalidate(LLLineEditor::prevalidatePrintableNotPipe); mEditDesc = getChild("Description"); mEditDesc->setCommitOnFocusLost(TRUE); - mEditDesc->setCommitCallback(onCommitAny, this); + mEditDesc->setCommitCallback(boost::bind(&LLPanelLandGeneral::onCommitAny, this)); // No prevalidate function - historically the prevalidate function was broken, // allowing residents to put in characters like U+2661 WHITE HEART SUIT, so // preserve that ability. @@ -421,25 +450,24 @@ BOOL LLPanelLandGeneral::postBuild() mBtnSetGroup->setCommitCallback(boost::bind(&LLPanelLandGeneral::onClickSetGroup, this)); mCheckDeedToGroup = getChild( "check deed"); - childSetCommitCallback("check deed", onCommitAny, this); + mCheckDeedToGroup->setCommitCallback(boost::bind(&LLPanelLandGeneral::onCommitAny, this)); mBtnDeedToGroup = getChild("Deed..."); - mBtnDeedToGroup->setClickedCallback(onClickDeed, this); + mBtnDeedToGroup->setCommitCallback(boost::bind(&LLPanelLandGeneral::onClickDeed, this)); mCheckContributeWithDeed = getChild( "check contrib"); - childSetCommitCallback("check contrib", onCommitAny, this); + mCheckContributeWithDeed->setCommitCallback(boost::bind(&LLPanelLandGeneral::onCommitAny, this)); - mSaleInfoNotForSale = getChild("Not for sale."); mSaleInfoForSale1 = getChild("For Sale: Price L$[PRICE]."); mBtnSellLand = getChild("Sell Land..."); - mBtnSellLand->setClickedCallback(onClickSellLand, this); + mBtnSellLand->setCommitCallback(boost::bind(&LLPanelLandGeneral::onClickSellLand, this)); mSaleInfoForSale2 = getChild("For sale to"); @@ -449,7 +477,7 @@ BOOL LLPanelLandGeneral::postBuild() mBtnStopSellLand = getChild("Cancel Land Sale"); - mBtnStopSellLand->setClickedCallback(onClickStopSellLand, this); + mBtnStopSellLand->setCommitCallback(boost::bind(&LLPanelLandGeneral::onClickStopSellLand, this)); mTextClaimDate = getChild("DateClaimText"); @@ -465,6 +493,23 @@ BOOL LLPanelLandGeneral::postBuild() mBtnBuyLand->setClickedCallback(onClickBuyLand, (void*)&BUY_PERSONAL_LAND); + mBtnBuyGroupLand = getChild("Buy For Group..."); + mBtnBuyGroupLand->setClickedCallback(onClickBuyLand, (void*)&BUY_GROUP_LAND); + + + mBtnBuyPass = getChild("Buy Pass..."); + mBtnBuyPass->setClickedCallback(onClickBuyPass, this); + + mBtnReleaseLand = getChild("Abandon Land..."); + mBtnReleaseLand->setCommitCallback(boost::bind(&LLPanelLandGeneral::onClickRelease, this)); + + mBtnReclaimLand = getChild("Reclaim Land..."); + mBtnReclaimLand->setCommitCallback(boost::bind(&LLPanelLandGeneral::onClickReclaim, this)); + + mBtnStartAuction = getChild("Linden Sale..."); + mBtnStartAuction->setCommitCallback(boost::bind(&LLPanelLandGeneral::onClickStartAuction, this)); + + mBtnScriptLimits = getChild("Scripts..."); if(gDisconnected) { @@ -474,40 +519,22 @@ BOOL LLPanelLandGeneral::postBuild() // note: on region change this will not be re checked, should not matter on Agni as // 99% of the time all regions will return the same caps. In case of an erroneous setting // to enabled the floater will just throw an error when trying to get it's cap - std::string url = gAgent.getRegion()->getCapability("LandResources"); + std::string url = gAgent.getRegionCapability("LandResources"); if (!url.empty()) { - mBtnScriptLimits = getChild("Scripts..."); if(mBtnScriptLimits) { - mBtnScriptLimits->setClickedCallback(onClickScriptLimits, this); + mBtnScriptLimits->setCommitCallback(boost::bind(&LLPanelLandGeneral::onClickScriptLimits, this)); } } else { - mBtnScriptLimits = getChild("Scripts..."); if(mBtnScriptLimits) { mBtnScriptLimits->setVisible(false); } } - mBtnBuyGroupLand = getChild("Buy For Group..."); - mBtnBuyGroupLand->setClickedCallback(onClickBuyLand, (void*)&BUY_GROUP_LAND); - - - mBtnBuyPass = getChild("Buy Pass..."); - mBtnBuyPass->setClickedCallback(onClickBuyPass, this); - - mBtnReleaseLand = getChild("Abandon Land..."); - mBtnReleaseLand->setClickedCallback(onClickRelease, NULL); - - mBtnReclaimLand = getChild("Reclaim Land..."); - mBtnReclaimLand->setClickedCallback(onClickReclaim, NULL); - - mBtnStartAuction = getChild("Linden Sale..."); - mBtnStartAuction->setClickedCallback(onClickStartAuction, this); - return TRUE; } @@ -520,9 +547,56 @@ LLPanelLandGeneral::~LLPanelLandGeneral() // public void LLPanelLandGeneral::refresh() { - mBtnStartAuction->setVisible(gAgent.isGodlike()); + mEditName->setEnabled(FALSE); + mEditName->setText(LLStringUtil::null); - LLParcel *parcel = mParcel->getParcel(); + mEditDesc->setEnabled(FALSE); + mEditDesc->setText(getString("no_selection_text")); + + mTextSalePending->setText(LLStringUtil::null); + mTextSalePending->setEnabled(FALSE); + + mBtnDeedToGroup->setEnabled(FALSE); + mBtnSetGroup->setEnabled(FALSE); + mBtnStartAuction->setEnabled(FALSE); + + mCheckDeedToGroup ->set(FALSE); + mCheckDeedToGroup ->setEnabled(FALSE); + mCheckContributeWithDeed->set(FALSE); + mCheckContributeWithDeed->setEnabled(FALSE); + + mTextOwner->setValue(LLUUID::null); + mContentRating->setText(LLStringUtil::null); + mLandType->setText(LLStringUtil::null); + + mTextClaimDate->setText(LLStringUtil::null); + mTextGroup->setValue(LLUUID::null); + mTextPrice->setText(LLStringUtil::null); + + mSaleInfoForSale1->setVisible(FALSE); + mSaleInfoForSale2->setVisible(FALSE); + mSaleInfoForSaleObjects->setVisible(FALSE); + mSaleInfoForSaleNoObjects->setVisible(FALSE); + mSaleInfoNotForSale->setVisible(FALSE); + mBtnSellLand->setVisible(FALSE); + mBtnStopSellLand->setVisible(FALSE); + + mTextPriceLabel->setText(LLStringUtil::null); + mTextDwell->setText(LLStringUtil::null); + + mBtnBuyLand->setEnabled(FALSE); + mBtnScriptLimits->setEnabled(FALSE); + mBtnBuyGroupLand->setEnabled(FALSE); + mBtnReleaseLand->setEnabled(FALSE); + mBtnReclaimLand->setEnabled(FALSE); + mBtnBuyPass->setEnabled(FALSE); + + if(gDisconnected) + { + return; + } + + mBtnStartAuction->setVisible(gAgent.isGodlike()); bool region_owner = false; LLViewerRegion* regionp = LLViewerParcelMgr::getInstance()->getSelectionRegion(); if(regionp && (regionp->getOwner() == gAgent.getID())) @@ -536,59 +610,8 @@ void LLPanelLandGeneral::refresh() mBtnReleaseLand->setVisible(TRUE); mBtnReclaimLand->setVisible(FALSE); } - if (!parcel) - { - // nothing selected, disable panel - mEditName->setEnabled(FALSE); - mEditName->setText(LLStringUtil::null); - - mEditDesc->setEnabled(FALSE); - mEditDesc->setText(getString("no_selection_text")); - - mTextSalePending->setText(LLStringUtil::null); - mTextSalePending->setEnabled(FALSE); - - mBtnDeedToGroup->setEnabled(FALSE); - mBtnSetGroup->setEnabled(FALSE); - mBtnStartAuction->setEnabled(FALSE); - - mCheckDeedToGroup ->set(FALSE); - mCheckDeedToGroup ->setEnabled(FALSE); - mCheckContributeWithDeed->set(FALSE); - mCheckContributeWithDeed->setEnabled(FALSE); - - mTextOwner->setValue(LLUUID::null); - mContentRating->setText(LLStringUtil::null); - mLandType->setText(LLStringUtil::null); - - mTextClaimDate->setText(LLStringUtil::null); - mTextGroup->setValue(LLUUID::null); - mTextPrice->setText(LLStringUtil::null); - - mSaleInfoForSale1->setVisible(FALSE); - mSaleInfoForSale2->setVisible(FALSE); - mSaleInfoForSaleObjects->setVisible(FALSE); - mSaleInfoForSaleNoObjects->setVisible(FALSE); - mSaleInfoNotForSale->setVisible(FALSE); - mBtnSellLand->setVisible(FALSE); - mBtnStopSellLand->setVisible(FALSE); - - mTextPriceLabel->setText(LLStringUtil::null); - mTextDwell->setText(LLStringUtil::null); - - mBtnBuyLand->setEnabled(FALSE); - mBtnScriptLimits->setEnabled(FALSE); - mBtnBuyGroupLand->setEnabled(FALSE); - mBtnReleaseLand->setEnabled(FALSE); - mBtnReclaimLand->setEnabled(FALSE); - mBtnBuyPass->setEnabled(FALSE); - - if(gDisconnected) - { - return; - } - } - else + LLParcel *parcel = mParcel->getParcel(); + if (parcel) { // something selected, hooray! BOOL is_leased = (LLParcel::OS_LEASED == parcel->getOwnershipStatus()); @@ -622,7 +645,7 @@ void LLPanelLandGeneral::refresh() bool group_owned = parcel->getIsGroupOwned(); // Is it owned? - mTextOwner->setValue(is_public ? LLSD(LLUUID::null) : LLSD().with("id", owner_id).with("group", group_owned)); + mTextOwner->setValue(is_public ? LLSD(LLUUID::null) : LLSD().with("id", owner_id).with("type", group_owned ? LFIDBearer::GROUP : LFIDBearer::AVATAR)); mTextGroup->setValue(is_public ? LLUUID::null : group_id); if (is_public) { @@ -792,6 +815,7 @@ void LLPanelLandGeneral::refresh() mBtnBuyLand->setEnabled( LLViewerParcelMgr::getInstance()->canAgentBuyParcel(parcel, false)); mBtnScriptLimits->setEnabled(true); +// LLViewerParcelMgr::getInstance()->canAgentBuyParcel(parcel, false)); mBtnBuyGroupLand->setEnabled( LLViewerParcelMgr::getInstance()->canAgentBuyParcel(parcel, true)); @@ -828,7 +852,7 @@ void LLPanelLandGeneral::refreshNames() } bool group_owned = parcel->getIsGroupOwned(); - mTextOwner->setValue(LLSD().with("id", parcel->getOwnerID()).with("group", group_owned)); + mTextOwner->setValue(LLSD().with("id", parcel->getOwnerID()).with("type", group_owned ? LFIDBearer::GROUP : LFIDBearer::AVATAR)); if (group_owned) { mTextOwner->setText(getString("group_owned_text")); @@ -898,19 +922,16 @@ void LLPanelLandGeneral::onClickBuyLand(void* data) LLViewerParcelMgr::getInstance()->startBuyLand(*for_group); } -// static -void LLPanelLandGeneral::onClickScriptLimits(void* data) +void LLPanelLandGeneral::onClickScriptLimits() { - LLPanelLandGeneral* panelp = (LLPanelLandGeneral*)data; - LLParcel* parcel = panelp->mParcel->getParcel(); + LLParcel* parcel = mParcel->getParcel(); if(parcel != NULL) { LLFloaterScriptLimits::showInstance(); } } -// static -void LLPanelLandGeneral::onClickDeed(void*) +void LLPanelLandGeneral::onClickDeed() { //LLParcel* parcel = mParcel->getParcel(); //if (parcel) @@ -919,14 +940,12 @@ void LLPanelLandGeneral::onClickDeed(void*) //} } -// static -void LLPanelLandGeneral::onClickRelease(void*) +void LLPanelLandGeneral::onClickRelease() { LLViewerParcelMgr::getInstance()->startReleaseLand(); } -// static -void LLPanelLandGeneral::onClickReclaim(void*) +void LLPanelLandGeneral::onClickReclaim() { LL_DEBUGS() << "LLPanelLandGeneral::onClickReclaim()" << LL_ENDL; LLViewerParcelMgr::getInstance()->reclaimParcel(); @@ -968,11 +987,9 @@ void LLPanelLandGeneral::onClickBuyPass(void* data) LLNotificationsUtil::add("LandBuyPass", args, LLSD(), cbBuyPass); } -// static -void LLPanelLandGeneral::onClickStartAuction(void* data) +void LLPanelLandGeneral::onClickStartAuction() { - LLPanelLandGeneral* panelp = (LLPanelLandGeneral*)data; - LLParcel* parcelp = panelp->mParcel->getParcel(); + LLParcel* parcelp = mParcel->getParcel(); if(parcelp) { if(parcelp->getForSale()) @@ -1000,20 +1017,17 @@ bool LLPanelLandGeneral::cbBuyPass(const LLSD& notification, const LLSD& respons return false; } -// static -void LLPanelLandGeneral::onCommitAny(LLUICtrl *ctrl, void *userdata) +void LLPanelLandGeneral::onCommitAny() { - LLPanelLandGeneral *panelp = (LLPanelLandGeneral *)userdata; - - LLParcel* parcel = panelp->mParcel->getParcel(); + LLParcel* parcel = mParcel->getParcel(); if (!parcel) { return; } // Extract data from UI - std::string name = panelp->mEditName->getText(); - std::string desc = panelp->mEditDesc->getText(); + std::string name = mEditName->getText(); + std::string desc = mEditDesc->getText(); // Valid data from UI @@ -1021,8 +1035,8 @@ void LLPanelLandGeneral::onCommitAny(LLUICtrl *ctrl, void *userdata) parcel->setName(name); parcel->setDesc(desc); - BOOL allow_deed_to_group= panelp->mCheckDeedToGroup->get(); - BOOL contribute_with_deed = panelp->mCheckContributeWithDeed->get(); + BOOL allow_deed_to_group= mCheckDeedToGroup->get(); + BOOL contribute_with_deed = mCheckContributeWithDeed->get(); parcel->setParcelFlag(PF_ALLOW_DEED_TO_GROUP, allow_deed_to_group); parcel->setContributeWithDeed(contribute_with_deed); @@ -1031,20 +1045,18 @@ void LLPanelLandGeneral::onCommitAny(LLUICtrl *ctrl, void *userdata) LLViewerParcelMgr::getInstance()->sendParcelPropertiesUpdate( parcel ); // Might have changed properties, so let's redraw! - panelp->refresh(); + refresh(); } -// static -void LLPanelLandGeneral::onClickSellLand(void* data) +void LLPanelLandGeneral::onClickSellLand() { LLViewerParcelMgr::getInstance()->startSellLand(); + refresh(); } -// static -void LLPanelLandGeneral::onClickStopSellLand(void* data) +void LLPanelLandGeneral::onClickStopSellLand() { - LLPanelLandGeneral* panelp = (LLPanelLandGeneral*)data; - LLParcel* parcel = panelp->mParcel->getParcel(); + LLParcel* parcel = mParcel->getParcel(); parcel->setParcelFlag(PF_FOR_SALE, FALSE); parcel->setSalePrice(0); @@ -1058,7 +1070,7 @@ void LLPanelLandGeneral::onClickStopSellLand(void* data) //--------------------------------------------------------------------------- LLPanelLandObjects::LLPanelLandObjects(LLParcelSelectionHandle& parcel) : LLPanel(std::string("land_objects_panel")), - mParcel(parcel), + mParcelObjectBonus(NULL), mSWTotalObjects(NULL), mObjectContribution(NULL), @@ -1080,7 +1092,8 @@ LLPanelLandObjects::LLPanelLandObjects(LLParcelSelectionHandle& parcel) mOwnerList(NULL), mFirstReply(TRUE), mSelectedCount(0), - mSelectedIsGroup(FALSE) + mSelectedIsGroup(FALSE), + mParcel(parcel) { } @@ -1088,7 +1101,6 @@ LLPanelLandObjects::LLPanelLandObjects(LLParcelSelectionHandle& parcel) BOOL LLPanelLandObjects::postBuild() { - mFirstReply = TRUE; mParcelObjectBonus = getChild("parcel_object_bonus"); mSWTotalObjects = getChild("objects_available"); @@ -1097,37 +1109,37 @@ BOOL LLPanelLandObjects::postBuild() mOwnerObjects = getChild("owner_objects_text"); mBtnShowOwnerObjects = getChild("ShowOwner"); - mBtnShowOwnerObjects->setClickedCallback(onClickShowOwnerObjects, this); + mBtnShowOwnerObjects->setCommitCallback(boost::bind(&LLPanelLandObjects::onClickShowOwnerObjects, this)); mBtnReturnOwnerObjects = getChild("ReturnOwner..."); - mBtnReturnOwnerObjects->setClickedCallback(onClickReturnOwnerObjects, this); + mBtnReturnOwnerObjects->setCommitCallback(boost::bind(&LLPanelLandObjects::onClickReturnOwnerObjects, this)); mGroupObjects = getChild("group_objects_text"); mBtnShowGroupObjects = getChild("ShowGroup"); - mBtnShowGroupObjects->setClickedCallback(onClickShowGroupObjects, this); + mBtnShowGroupObjects->setCommitCallback(boost::bind(&LLPanelLandObjects::onClickShowGroupObjects, this)); mBtnReturnGroupObjects = getChild("ReturnGroup..."); - mBtnReturnGroupObjects->setClickedCallback(onClickReturnGroupObjects, this); + mBtnReturnGroupObjects->setCommitCallback(boost::bind(&LLPanelLandObjects::onClickReturnGroupObjects, this)); mOtherObjects = getChild("other_objects_text"); mBtnShowOtherObjects = getChild("ShowOther"); - mBtnShowOtherObjects->setClickedCallback(onClickShowOtherObjects, this); + mBtnShowOtherObjects->setCommitCallback(boost::bind(&LLPanelLandObjects::onClickShowOtherObjects, this)); mBtnReturnOtherObjects = getChild("ReturnOther..."); - mBtnReturnOtherObjects->setClickedCallback(onClickReturnOtherObjects, this); + mBtnReturnOtherObjects->setCommitCallback(boost::bind(&LLPanelLandObjects::onClickReturnOtherObjects, this)); mSelectedObjects = getChild("selected_objects_text"); mCleanOtherObjectsTime = getChild("clean other time"); mCleanOtherObjectsTime->setFocusLostCallback(boost::bind(&LLPanelLandObjects::onLostFocus, _1, this)); - mCleanOtherObjectsTime->setCommitCallback(onCommitClean, this); + mCleanOtherObjectsTime->setCommitCallback(boost::bind(&LLPanelLandObjects::onCommitClean, this)); mCleanOtherObjectsTime->setPrevalidate(LLLineEditor::prevalidateNonNegativeS32); mBtnRefresh = getChild("Refresh List"); - mBtnRefresh->setClickedCallback(onClickRefresh, this); + mBtnRefresh->setCommitCallback(boost::bind(&LLPanelLandObjects::onClickRefresh, this)); mBtnReturnOwnerList = getChild("Return objects..."); - mBtnReturnOwnerList->setClickedCallback(onClickReturnOwnerList, this); + mBtnReturnOwnerList->setCommitCallback(boost::bind(&LLPanelLandObjects::onClickReturnOwnerList, this)); mIconAvatarOnline = LLUI::getUIImage("icon_avatar_online.tga"); mIconAvatarInSim = LLUI::getUIImage("ff_visible_map.tga"); @@ -1141,13 +1153,13 @@ BOOL LLPanelLandObjects::postBuild() return TRUE; } - - - // virtual LLPanelLandObjects::~LLPanelLandObjects() { } + +const LLStringExplicit zero_str("0"); + // public void LLPanelLandObjects::refresh() { @@ -1169,15 +1181,15 @@ void LLPanelLandObjects::refresh() if (!parcel || gDisconnected) { - mSWTotalObjects->setTextArg("[COUNT]", llformat("%d", 0)); - mSWTotalObjects->setTextArg("[TOTAL]", llformat("%d", 0)); - mSWTotalObjects->setTextArg("[AVAILABLE]", llformat("%d", 0)); - mObjectContribution->setTextArg("[COUNT]", llformat("%d", 0)); - mTotalObjects->setTextArg("[COUNT]", llformat("%d", 0)); - mOwnerObjects->setTextArg("[COUNT]", llformat("%d", 0)); - mGroupObjects->setTextArg("[COUNT]", llformat("%d", 0)); - mOtherObjects->setTextArg("[COUNT]", llformat("%d", 0)); - mSelectedObjects->setTextArg("[COUNT]", llformat("%d", 0)); + mSWTotalObjects->setTextArg("[COUNT]", zero_str); + mSWTotalObjects->setTextArg("[TOTAL]", zero_str); + mSWTotalObjects->setTextArg("[AVAILABLE]", zero_str); + mObjectContribution->setTextArg("[COUNT]", zero_str); + mTotalObjects->setTextArg("[COUNT]", zero_str); + mOwnerObjects->setTextArg("[COUNT]", zero_str); + mGroupObjects->setTextArg("[COUNT]", zero_str); + mOtherObjects->setTextArg("[COUNT]", zero_str); + mSelectedObjects->setTextArg("[COUNT]", zero_str); } else { @@ -1279,6 +1291,7 @@ void send_other_clean_time_message(S32 parcel_local_id, S32 other_clean_time) msg->sendReliable(region->getHost()); } + void send_return_objects_message(S32 parcel_local_id, S32 return_type, uuid_list_t* owner_ids = NULL) { @@ -1337,9 +1350,7 @@ bool LLPanelLandObjects::callbackReturnOwnerObjects(const LLSD& notification, co } else { - std::string full_name; - gCacheName->getFullName(owner_id, full_name); - args["NAME"] = full_name; + args["NAME"] = LLSLURL("agent", owner_id, "completename").getSLURLString(); LLNotificationsUtil::add("OtherObjectsReturned", args); } send_return_objects_message(parcel->getLocalID(), RT_OWNER); @@ -1426,57 +1437,49 @@ bool LLPanelLandObjects::callbackReturnOwnerList(const LLSD& notification, const return false; } - -// static -void LLPanelLandObjects::onClickReturnOwnerList(void* userdata) +void LLPanelLandObjects::onClickReturnOwnerList() { - LLPanelLandObjects *self = (LLPanelLandObjects *)userdata; - - LLParcel* parcelp = self->mParcel->getParcel(); + LLParcel* parcelp = mParcel->getParcel(); if (!parcelp) return; // Make sure we have something selected. - if (self->mSelectedOwners.empty()) + if (mSelectedOwners.empty()) { return; } //uuid_list_t::iterator selected_itr = self->mSelectedOwners.begin(); //if (selected_itr == self->mSelectedOwners.end()) return; - send_parcel_select_objects(parcelp->getLocalID(), RT_LIST, &(self->mSelectedOwners)); + send_parcel_select_objects(parcelp->getLocalID(), RT_LIST, &mSelectedOwners); LLSD args; - args["NAME"] = self->mSelectedName; - args["N"] = llformat("%d",self->mSelectedCount); - if (self->mSelectedIsGroup) + args["NAME"] = mSelectedName; + args["N"] = std::to_string(mSelectedCount); + if (mSelectedIsGroup) { - LLNotificationsUtil::add("ReturnObjectsDeededToGroup", args, LLSD(), boost::bind(&LLPanelLandObjects::callbackReturnOwnerList, self, _1, _2)); + LLNotificationsUtil::add("ReturnObjectsDeededToGroup", args, LLSD(), boost::bind(&LLPanelLandObjects::callbackReturnOwnerList, this, _1, _2)); } else { - LLNotificationsUtil::add("ReturnObjectsOwnedByUser", args, LLSD(), boost::bind(&LLPanelLandObjects::callbackReturnOwnerList, self, _1, _2)); + LLNotificationsUtil::add("ReturnObjectsOwnedByUser", args, LLSD(), boost::bind(&LLPanelLandObjects::callbackReturnOwnerList, this, _1, _2)); } } - -// static -void LLPanelLandObjects::onClickRefresh(void* userdata) +void LLPanelLandObjects::onClickRefresh() { - LLPanelLandObjects *self = (LLPanelLandObjects*)userdata; - LLMessageSystem *msg = gMessageSystem; - LLParcel* parcel = self->mParcel->getParcel(); + LLParcel* parcel = mParcel->getParcel(); if (!parcel) return; LLViewerRegion* region = LLViewerParcelMgr::getInstance()->getSelectionRegion(); if (!region) return; // ready the list for results - self->mOwnerList->deleteAllItems(); - self->mOwnerList->setCommentText(LLTrans::getString("Searching")); - self->mOwnerList->setEnabled(FALSE); - self->mFirstReply = TRUE; + mOwnerList->deleteAllItems(); + mOwnerList->setCommentText(LLTrans::getString("Searching")); + mOwnerList->setEnabled(FALSE); + mFirstReply = TRUE; // send the message msg->newMessageFast(_PREHASH_ParcelObjectOwnersRequest); @@ -1492,7 +1495,7 @@ void LLPanelLandObjects::onClickRefresh(void* userdata) // static void LLPanelLandObjects::processParcelObjectOwnersReply(LLMessageSystem *msg, void **) { - LLPanelLandObjects* self = LLFloaterLand::getCurrentPanelLandObjects(); + LLPanelLandObjects* self = LLFloaterLand::getInstance()->mPanelObjects; if (!self) { @@ -1501,7 +1504,7 @@ void LLPanelLandObjects::processParcelObjectOwnersReply(LLMessageSystem *msg, vo return; } - const std::string FONT = "SANSSERIF"; + constexpr auto&& FONT = "SANSSERIF"; // Extract all of the owners. S32 rows = msg->getNumberOfBlocksFast(_PREHASH_Data); @@ -1521,10 +1524,6 @@ void LLPanelLandObjects::processParcelObjectOwnersReply(LLMessageSystem *msg, vo self->mFirstReply = FALSE; } - LLVector3d mypos = gAgent.getPositionGlobal(); - uuid_vec_t avatar_ids; - LLWorld::instance().getAvatars(&avatar_ids, NULL, mypos, F32_MAX); - for(S32 i = 0; i < rows; ++i) { msg->getUUIDFast(_PREHASH_Data, _PREHASH_OwnerID, owner_id, i); @@ -1545,6 +1544,9 @@ void LLPanelLandObjects::processParcelObjectOwnersReply(LLMessageSystem *msg, vo item_params.value = owner_id; item_params.target = is_group_owned ? LLNameListItem::GROUP : LLNameListItem::INDIVIDUAL; + uuid_vec_t avatar_ids; + LLWorld::instance().getAvatars(&avatar_ids, nullptr, gAgent.getPositionGlobal(), F32_MAX); + if (is_group_owned) { item_params.columns.add().type("icon").value(self->mIconGroup->getName()).column("type"); @@ -1591,9 +1593,10 @@ void LLPanelLandObjects::processParcelObjectOwnersReply(LLMessageSystem *msg, vo } } +// static void LLPanelLandObjects::onCommitList() { - if (FALSE == mOwnerList->getCanSelect()) + if (mOwnerList->getCanSelect() == FALSE) { return; } @@ -1612,7 +1615,7 @@ void LLPanelLandObjects::onCommitList() cell = item->getColumn(2); mSelectedName = cell->getValue().asString(); cell = item->getColumn(3); - mSelectedCount = atoi(cell->getValue().asString().c_str()); + mSelectedCount = std::stoi(cell->getValue().asString()); // Set the selection, and enable the return button. mSelectedOwners.clear(); @@ -1620,7 +1623,7 @@ void LLPanelLandObjects::onCommitList() mBtnReturnOwnerList->setEnabled(TRUE); // Highlight this user's objects - clickShowCore(this, RT_LIST, &(mSelectedOwners)); + clickShowCore(this, RT_LIST, &mSelectedOwners); } } @@ -1633,31 +1636,26 @@ void LLPanelLandObjects::clickShowCore(LLPanelLandObjects* self, S32 return_type send_parcel_select_objects(parcel->getLocalID(), return_type, list); } -// static -void LLPanelLandObjects::onClickShowOwnerObjects(void* userdata) +void LLPanelLandObjects::onClickShowOwnerObjects() { - clickShowCore((LLPanelLandObjects*)userdata, RT_OWNER); + clickShowCore(this, RT_OWNER); } -// static -void LLPanelLandObjects::onClickShowGroupObjects(void* userdata) +void LLPanelLandObjects::onClickShowGroupObjects() { - clickShowCore((LLPanelLandObjects*)userdata, (RT_GROUP)); + clickShowCore(this, (RT_GROUP)); } -// static -void LLPanelLandObjects::onClickShowOtherObjects(void* userdata) +void LLPanelLandObjects::onClickShowOtherObjects() { - clickShowCore((LLPanelLandObjects*)userdata, RT_OTHER); + clickShowCore(this, RT_OTHER); } -// static -void LLPanelLandObjects::onClickReturnOwnerObjects(void* userdata) +void LLPanelLandObjects::onClickReturnOwnerObjects() { S32 owned = 0; - LLPanelLandObjects* panelp = (LLPanelLandObjects*)userdata; - LLParcel* parcel = panelp->mParcel->getParcel(); + LLParcel* parcel = mParcel->getParcel(); if (!parcel) return; owned = parcel->getOwnerPrimCount(); @@ -1667,26 +1665,22 @@ void LLPanelLandObjects::onClickReturnOwnerObjects(void* userdata) LLUUID owner_id = parcel->getOwnerID(); LLSD args; - args["N"] = llformat("%d",owned); + args["N"] = std::to_string(owned); if (owner_id == gAgent.getID()) { - LLNotificationsUtil::add("ReturnObjectsOwnedBySelf", args, LLSD(), boost::bind(&LLPanelLandObjects::callbackReturnOwnerObjects, panelp, _1, _2)); + LLNotificationsUtil::add("ReturnObjectsOwnedBySelf", args, LLSD(), boost::bind(&LLPanelLandObjects::callbackReturnOwnerObjects, this, _1, _2)); } else { - std::string name; - gCacheName->getFullName(owner_id, name); - args["NAME"] = name; - LLNotificationsUtil::add("ReturnObjectsOwnedByUser", args, LLSD(), boost::bind(&LLPanelLandObjects::callbackReturnOwnerObjects, panelp, _1, _2)); + args["NAME"] = LLSLURL("agent", owner_id, "completename").getSLURLString(); + LLNotificationsUtil::add("ReturnObjectsOwnedByUser", args, LLSD(), boost::bind(&LLPanelLandObjects::callbackReturnOwnerObjects, this, _1, _2)); } } -// static -void LLPanelLandObjects::onClickReturnGroupObjects(void* userdata) +void LLPanelLandObjects::onClickReturnGroupObjects() { - LLPanelLandObjects* panelp = (LLPanelLandObjects*)userdata; - LLParcel* parcel = panelp->mParcel->getParcel(); + LLParcel* parcel = mParcel->getParcel(); if (!parcel) return; send_parcel_select_objects(parcel->getLocalID(), RT_GROUP); @@ -1699,16 +1693,14 @@ void LLPanelLandObjects::onClickReturnGroupObjects(void* userdata) args["N"] = llformat("%d", parcel->getGroupPrimCount()); // create and show confirmation textbox - LLNotificationsUtil::add("ReturnObjectsDeededToGroup", args, LLSD(), boost::bind(&LLPanelLandObjects::callbackReturnGroupObjects, panelp, _1, _2)); + LLNotificationsUtil::add("ReturnObjectsDeededToGroup", args, LLSD(), boost::bind(&LLPanelLandObjects::callbackReturnGroupObjects, this, _1, _2)); } -// static -void LLPanelLandObjects::onClickReturnOtherObjects(void* userdata) +void LLPanelLandObjects::onClickReturnOtherObjects() { S32 other = 0; - LLPanelLandObjects* panelp = (LLPanelLandObjects*)userdata; - LLParcel* parcel = panelp->mParcel->getParcel(); + LLParcel* parcel = mParcel->getParcel(); if (!parcel) return; other = parcel->getOtherPrimCount(); @@ -1724,7 +1716,7 @@ void LLPanelLandObjects::onClickReturnOtherObjects(void* userdata) gCacheName->getGroupName(parcel->getGroupID(), group_name); args["NAME"] = group_name; - LLNotificationsUtil::add("ReturnObjectsNotOwnedByGroup", args, LLSD(), boost::bind(&LLPanelLandObjects::callbackReturnOtherObjects, panelp, _1, _2)); + LLNotificationsUtil::add("ReturnObjectsNotOwnedByGroup", args, LLSD(), boost::bind(&LLPanelLandObjects::callbackReturnOtherObjects, this, _1, _2)); } else { @@ -1732,14 +1724,12 @@ void LLPanelLandObjects::onClickReturnOtherObjects(void* userdata) if (owner_id == gAgent.getID()) { - LLNotificationsUtil::add("ReturnObjectsNotOwnedBySelf", args, LLSD(), boost::bind(&LLPanelLandObjects::callbackReturnOtherObjects, panelp, _1, _2)); + LLNotificationsUtil::add("ReturnObjectsNotOwnedBySelf", args, LLSD(), boost::bind(&LLPanelLandObjects::callbackReturnOtherObjects, this, _1, _2)); } else { - std::string name; - gCacheName->getFullName(owner_id, name); - args["NAME"] = name; - LLNotificationsUtil::add("ReturnObjectsNotOwnedByUser", args, LLSD(), boost::bind(&LLPanelLandObjects::callbackReturnOtherObjects, panelp, _1, _2)); + args["NAME"] = LLSLURL("agent", owner_id, "completename").getSLURLString(); + LLNotificationsUtil::add("ReturnObjectsNotOwnedByUser", args, LLSD(), boost::bind(&LLPanelLandObjects::callbackReturnOtherObjects, this, _1, _2)); } } } @@ -1747,24 +1737,23 @@ void LLPanelLandObjects::onClickReturnOtherObjects(void* userdata) // static void LLPanelLandObjects::onLostFocus(LLFocusableElement* caller, void* user_data) { - onCommitClean((LLUICtrl*)caller, user_data); + LLPanelLandObjects *lop = static_cast(user_data); + if (lop) lop->onCommitClean(); } -// static -void LLPanelLandObjects::onCommitClean(LLUICtrl *caller, void* user_data) +void LLPanelLandObjects::onCommitClean() { - LLPanelLandObjects *lop = (LLPanelLandObjects *)user_data; - LLParcel* parcel = lop->mParcel->getParcel(); + LLParcel* parcel = mParcel->getParcel(); if (parcel) { - S32 return_time = atoi(lop->mCleanOtherObjectsTime->getText().c_str()); + S32 return_time = std::stoi(mCleanOtherObjectsTime->getText()); // Only send return time if it has changed - if (return_time != lop->mOtherTime) + if (return_time != mOtherTime) { - lop->mOtherTime = return_time; + mOtherTime = return_time; - parcel->setCleanOtherTime(lop->mOtherTime); - send_other_clean_time_message(parcel->getLocalID(), lop->mOtherTime); + parcel->setCleanOtherTime(mOtherTime); + send_other_clean_time_message(parcel->getLocalID(), mOtherTime); } } } @@ -1797,8 +1786,8 @@ LLPanelLandOptions::LLPanelLandOptions(LLParcelSelectionHandle& parcel) mGamingCtrl(NULL), mPushRestrictionCtrl(NULL), mSeeAvatarsCtrl(NULL), - mParcel(parcel), - mPublishHelpButton(NULL) + mPublishHelpButton(NULL), + mParcel(parcel) { } @@ -1806,48 +1795,48 @@ LLPanelLandOptions::LLPanelLandOptions(LLParcelSelectionHandle& parcel) BOOL LLPanelLandOptions::postBuild() { mCheckEditObjects = getChild( "edit objects check"); - childSetCommitCallback("edit objects check", onCommitAny, this); + mCheckEditObjects->setCommitCallback(boost::bind(&LLPanelLandOptions::onCommitAny, this)); mCheckEditGroupObjects = getChild( "edit group objects check"); - childSetCommitCallback("edit group objects check", onCommitAny, this); + mCheckEditGroupObjects->setCommitCallback(boost::bind(&LLPanelLandOptions::onCommitAny, this)); mCheckAllObjectEntry = getChild( "all object entry check"); - childSetCommitCallback("all object entry check", onCommitAny, this); + mCheckAllObjectEntry->setCommitCallback(boost::bind(&LLPanelLandOptions::onCommitAny, this)); mCheckGroupObjectEntry = getChild( "group object entry check"); - childSetCommitCallback("group object entry check", onCommitAny, this); + mCheckGroupObjectEntry->setCommitCallback(boost::bind(&LLPanelLandOptions::onCommitAny, this)); mCheckEditLand = getChild( "edit land check"); - childSetCommitCallback("edit land check", onCommitAny, this); + mCheckEditLand->setCommitCallback(boost::bind(&LLPanelLandOptions::onCommitAny, this)); mCheckLandmark = getChild( "check landmark"); - childSetCommitCallback("check landmark", onCommitAny, this); + mCheckLandmark->setCommitCallback(boost::bind(&LLPanelLandOptions::onCommitAny, this)); mCheckLandmark->setVisible(!gHippoGridManager->getConnectedGrid()->isSecondLife()); mCheckGroupScripts = getChild( "check group scripts"); - childSetCommitCallback("check group scripts", onCommitAny, this); + mCheckGroupScripts->setCommitCallback(boost::bind(&LLPanelLandOptions::onCommitAny, this)); mCheckFly = getChild( "check fly"); - childSetCommitCallback("check fly", onCommitAny, this); + mCheckFly->setCommitCallback(boost::bind(&LLPanelLandOptions::onCommitAny, this)); mCheckOtherScripts = getChild( "check other scripts"); - childSetCommitCallback("check other scripts", onCommitAny, this); + mCheckOtherScripts->setCommitCallback(boost::bind(&LLPanelLandOptions::onCommitAny, this)); mCheckSafe = getChild( "check safe"); - childSetCommitCallback("check safe", onCommitAny, this); + mCheckSafe->setCommitCallback(boost::bind(&LLPanelLandOptions::onCommitAny, this)); mPushRestrictionCtrl = getChild( "PushRestrictCheck"); - childSetCommitCallback("PushRestrictCheck", onCommitAny, this); + mPushRestrictionCtrl->setCommitCallback(boost::bind(&LLPanelLandOptions::onCommitAny, this)); mSeeAvatarsCtrl = getChild( "SeeAvatarsCheck"); - childSetCommitCallback("SeeAvatarsCheck", onCommitAny, this); + mSeeAvatarsCtrl->setCommitCallback(boost::bind(&LLPanelLandOptions::onCommitAny, this)); mCheckShowDirectory = getChild( "ShowDirectoryCheck"); - childSetCommitCallback("ShowDirectoryCheck", onCommitAny, this); + mCheckShowDirectory->setCommitCallback(boost::bind(&LLPanelLandOptions::onCommitAny, this)); if (gAgent.getAgentAccess().isInTransition()) @@ -1856,26 +1845,28 @@ BOOL LLPanelLandOptions::postBuild() // Post-transition, it goes away. We can remove this conditional // after the transition and just use the "else" clause. mCategoryCombo = getChild( "land category with adult"); - childSetCommitCallback("land category with adult", onCommitAny, this); } else { // this is the code that should be preserved post-transition // you could also change the XML to set visibility and enabled true. mCategoryCombo = getChild( "land category"); - childSetCommitCallback("land category", onCommitAny, this); } + mCategoryCombo->setCommitCallback(boost::bind(&LLPanelLandOptions::onCommitAny, this)); mCategoryCombo->setVisible(true); mCategoryCombo->setEnabled(true); mMatureCtrl = getChild( "MatureCheck"); - childSetCommitCallback("MatureCheck", onCommitAny, this); + mMatureCtrl->setCommitCallback(boost::bind(&LLPanelLandOptions::onCommitAny, this)); - mGamingCtrl = getChild( "GamingCheck"); - childSetCommitCallback("GamingCheck", onCommitAny, this); - mGamingCtrl->setVisible((gAgent.getRegion()->getGamingFlags() & REGION_GAMING_PRESENT) && !(gAgent.getRegion()->getGamingFlags() & REGION_GAMING_HIDE_PARCEL)); - mGamingCtrl->setEnabled(false); + if (mGamingCtrl = getChild( "GamingCheck")) + { + auto region = gAgent.getRegion(); + mGamingCtrl->setCommitCallback(boost::bind(&LLPanelLandOptions::onCommitAny, this)); + mGamingCtrl->setVisible(region && (region->getGamingFlags() & REGION_GAMING_PRESENT) && !(region->getGamingFlags() & REGION_GAMING_HIDE_PARCEL)); + mGamingCtrl->setEnabled(false); + } mPublishHelpButton = getChild("?"); mPublishHelpButton->setClickedCallback(onClickPublishHelp, this); @@ -1893,7 +1884,7 @@ BOOL LLPanelLandOptions::postBuild() mSnapshotCtrl = getChild("snapshot_ctrl"); if (mSnapshotCtrl) { - mSnapshotCtrl->setCommitCallback( onCommitAny, this ); + mSnapshotCtrl->setCommitCallback(boost::bind(&LLPanelLandOptions::onCommitAny, this)); mSnapshotCtrl->setAllowNoTexture ( TRUE ); mSnapshotCtrl->setImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER); mSnapshotCtrl->setNonImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER); @@ -1907,15 +1898,15 @@ BOOL LLPanelLandOptions::postBuild() mLocationText = getChild("landing_point"); mSetBtn = getChild("Set"); - mSetBtn->setClickedCallback(onClickSet, this); + mSetBtn->setCommitCallback(boost::bind(&LLPanelLandOptions::onClickSet, this)); mClearBtn = getChild("Clear"); - mClearBtn->setClickedCallback(onClickClear, this); + mClearBtn->setCommitCallback(boost::bind(&LLPanelLandOptions::onClickClear, this)); mLandingTypeCombo = getChild( "landing type"); - childSetCommitCallback("landing type", onCommitAny, this); + mLandingTypeCombo->setCommitCallback(boost::bind(&LLPanelLandOptions::onCommitAny, this)); getChild("snapshot_ctrl")->setFallbackImageName("default_land_picture.j2c"); @@ -2050,6 +2041,10 @@ void LLPanelLandOptions::refresh() mSnapshotCtrl->setImageAssetID(parcel->getSnapshotID()); mSnapshotCtrl->setEnabled( can_change_identity ); + // find out where we're looking and convert that to an angle in degrees on a regular compass (not the internal representation) + LLVector3 user_look_at = parcel->getUserLookAt(); + U32 user_look_at_angle = ( (U32)( ( atan2(user_look_at[1], -user_look_at[0]) + F_PI * 2 ) * RAD_TO_DEG + 0.5) - 90) % 360; + LLVector3 pos = parcel->getUserLocation(); if (pos.isExactlyZero()) { @@ -2057,10 +2052,11 @@ void LLPanelLandOptions::refresh() } else { - mLocationText->setTextArg("[LANDING]",llformat("%d, %d, %d", + mLocationText->setTextArg("[LANDING]",llformat("%d, %d, %d (%d\xC2\xB0)", ll_round(pos.mV[VX]), ll_round(pos.mV[VY]), - ll_round(pos.mV[VZ]))); + ll_round(pos.mV[VZ]), + user_look_at_angle)); } mSetBtn->setEnabled( can_change_landing_point ); @@ -2128,7 +2124,6 @@ void LLPanelLandOptions::refreshSearch() mCheckShowDirectory->set(FALSE); mCheckShowDirectory->setEnabled(FALSE); - // *TODO:Translate const std::string& none_string = LLParcel::getCategoryUIString(LLParcel::C_NONE); mCategoryCombo->setSimple(none_string); mCategoryCombo->setEnabled(FALSE); @@ -2158,7 +2153,6 @@ void LLPanelLandOptions::refreshSearch() mCheckShowDirectory->setLabelArg("[DIRECTORYFEE]", gHippoGridManager->getConnectedGrid()->getDirectoryFee()); // Set by string in case the order in UI doesn't match the order by index. - // *TODO:Translate LLParcel::ECategory cat = parcel->getCategory(); const std::string& category_string = LLParcel::getCategoryUIString(cat); mCategoryCombo->setSimple(category_string); @@ -2218,38 +2212,35 @@ void LLPanelLandOptions::refreshSearch() } -// static -void LLPanelLandOptions::onCommitAny(LLUICtrl *ctrl, void *userdata) +void LLPanelLandOptions::onCommitAny() { - LLPanelLandOptions *self = (LLPanelLandOptions *)userdata; - - LLParcel* parcel = self->mParcel->getParcel(); + LLParcel* parcel = mParcel->getParcel(); if (!parcel) { return; } // Extract data from UI - BOOL create_objects = self->mCheckEditObjects->get(); - BOOL create_group_objects = self->mCheckEditGroupObjects->get() || self->mCheckEditObjects->get(); - BOOL all_object_entry = self->mCheckAllObjectEntry->get(); - BOOL group_object_entry = self->mCheckGroupObjectEntry->get() || self->mCheckAllObjectEntry->get(); - BOOL allow_terraform = self->mCheckEditLand->get(); - BOOL allow_damage = !self->mCheckSafe->get(); - BOOL allow_fly = self->mCheckFly->get(); - BOOL allow_landmark = self->mCheckLandmark->get(); - BOOL allow_other_scripts = self->mCheckOtherScripts->get(); - BOOL allow_group_scripts = self->mCheckGroupScripts->get() || allow_other_scripts; + BOOL create_objects = mCheckEditObjects->get(); + BOOL create_group_objects = mCheckEditGroupObjects->get() || mCheckEditObjects->get(); + BOOL all_object_entry = mCheckAllObjectEntry->get(); + BOOL group_object_entry = mCheckGroupObjectEntry->get() || mCheckAllObjectEntry->get(); + BOOL allow_terraform = mCheckEditLand->get(); + BOOL allow_damage = !mCheckSafe->get(); + BOOL allow_fly = mCheckFly->get(); + BOOL allow_landmark = mCheckLandmark->get(); + BOOL allow_other_scripts = mCheckOtherScripts->get(); + BOOL allow_group_scripts = mCheckGroupScripts->get() || allow_other_scripts; BOOL allow_publish = FALSE; - BOOL mature_publish = self->mMatureCtrl->get(); - BOOL push_restriction = self->mPushRestrictionCtrl->get(); - BOOL see_avs = self->mSeeAvatarsCtrl->get(); - bool gaming = self->mGamingCtrl->get(); - BOOL show_directory = self->mCheckShowDirectory->get(); + BOOL mature_publish = mMatureCtrl->get(); + BOOL push_restriction = mPushRestrictionCtrl->get(); + BOOL see_avs = mSeeAvatarsCtrl->get(); + bool gaming = mGamingCtrl->get(); + BOOL show_directory = mCheckShowDirectory->get(); // we have to get the index from a lookup, not from the position in the dropdown! - S32 category_index = LLParcel::getCategoryFromString(self->mCategoryCombo->getSelectedValue()); - S32 landing_type_index = self->mLandingTypeCombo->getCurrentIndex(); - LLUUID snapshot_id = self->mSnapshotCtrl->getImageAssetID(); + S32 category_index = LLParcel::getCategoryFromString(mCategoryCombo->getSelectedValue()); + S32 landing_type_index = mLandingTypeCombo->getCurrentIndex(); + LLUUID snapshot_id = mSnapshotCtrl->getImageAssetID(); LLViewerRegion* region; region = LLViewerParcelMgr::getInstance()->getSelectionRegion(); @@ -2258,8 +2249,8 @@ void LLPanelLandOptions::onCommitAny(LLUICtrl *ctrl, void *userdata) if ( (!allow_other_scripts && parcel->getParcelFlag(PF_ALLOW_OTHER_SCRIPTS)) || (!allow_group_scripts && parcel->getParcelFlag(PF_ALLOW_GROUP_SCRIPTS)) ) { // Don't allow turning off "Run Scripts" if damage is allowed in the region - self->mCheckOtherScripts->set(parcel->getParcelFlag(PF_ALLOW_OTHER_SCRIPTS)); // Restore UI to actual settings - self->mCheckGroupScripts->set(parcel->getParcelFlag(PF_ALLOW_GROUP_SCRIPTS)); + mCheckOtherScripts->set(parcel->getParcelFlag(PF_ALLOW_OTHER_SCRIPTS)); // Restore UI to actual settings + mCheckGroupScripts->set(parcel->getParcelFlag(PF_ALLOW_GROUP_SCRIPTS)); LLNotificationsUtil::add("UnableToDisableOutsideScripts"); return; } @@ -2290,16 +2281,12 @@ void LLPanelLandOptions::onCommitAny(LLUICtrl *ctrl, void *userdata) LLViewerParcelMgr::getInstance()->sendParcelPropertiesUpdate( parcel ); // Might have changed properties, so let's redraw! - self->refresh(); + refresh(); } - -// static -void LLPanelLandOptions::onClickSet(void* userdata) +void LLPanelLandOptions::onClickSet() { - LLPanelLandOptions* self = (LLPanelLandOptions*)userdata; - - LLParcel* selected_parcel = self->mParcel->getParcel(); + LLParcel* selected_parcel = mParcel->getParcel(); if (!selected_parcel) return; LLParcel* agent_parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); @@ -2317,14 +2304,12 @@ void LLPanelLandOptions::onClickSet(void* userdata) LLViewerParcelMgr::getInstance()->sendParcelPropertiesUpdate(selected_parcel); - self->refresh(); + refresh(); } -void LLPanelLandOptions::onClickClear(void* userdata) +void LLPanelLandOptions::onClickClear() { - LLPanelLandOptions* self = (LLPanelLandOptions*)userdata; - - LLParcel* selected_parcel = self->mParcel->getParcel(); + LLParcel* selected_parcel = mParcel->getParcel(); if (!selected_parcel) return; // yes, this magic number of 0,0,0 means that it is clear @@ -2334,9 +2319,10 @@ void LLPanelLandOptions::onClickClear(void* userdata) LLViewerParcelMgr::getInstance()->sendParcelPropertiesUpdate(selected_parcel); - self->refresh(); + refresh(); } + // static void LLPanelLandOptions::onClickPublishHelp(void*) { @@ -2375,19 +2361,19 @@ LLPanelLandAccess::LLPanelLandAccess(LLParcelSelectionHandle& parcel) BOOL LLPanelLandAccess::postBuild() { - childSetCommitCallback("public_access", onCommitPublicAccess, this); - childSetCommitCallback("limit_payment", onCommitAny, this); - childSetCommitCallback("limit_age_verified", onCommitAny, this); - childSetCommitCallback("GroupCheck", onCommitGroupCheck, this); - childSetCommitCallback("PassCheck", onCommitAny, this); - childSetCommitCallback("pass_combo", onCommitAny, this); - childSetCommitCallback("PriceSpin", onCommitAny, this); - childSetCommitCallback("HoursSpin", onCommitAny, this); + getChild("public_access")->setCommitCallback(boost::bind(&LLPanelLandAccess::onCommitPublicAccess, this, _1)); + getChild("limit_payment")->setCommitCallback(boost::bind(&LLPanelLandAccess::onCommitAny, this)); + getChild("limit_age_verified")->setCommitCallback(boost::bind(&LLPanelLandAccess::onCommitAny, this)); + getChild("GroupCheck")->setCommitCallback(boost::bind(&LLPanelLandAccess::onCommitGroupCheck, this, _1)); + getChild("PassCheck")->setCommitCallback(boost::bind(&LLPanelLandAccess::onCommitAny, this)); + getChild("pass_combo")->setCommitCallback(boost::bind(&LLPanelLandAccess::onCommitAny, this)); + getChild("PriceSpin")->setCommitCallback(boost::bind(&LLPanelLandAccess::onCommitAny, this)); + getChild("HoursSpin")->setCommitCallback(boost::bind(&LLPanelLandAccess::onCommitAny, this)); childSetAction("add_allowed", boost::bind(&LLPanelLandAccess::onClickAddAccess, this)); - childSetAction("remove_allowed", onClickRemoveAccess, this); + getChild("remove_allowed")->setCommitCallback(boost::bind(&LLPanelLandAccess::onClickRemoveAccess, this)); childSetAction("add_banned", boost::bind(&LLPanelLandAccess::onClickAddBanned, this)); - childSetAction("remove_banned", onClickRemoveBanned, this); + getChild("remove_banned")->setCommitCallback(boost::bind(&LLPanelLandAccess::onClickRemoveBanned, this)); mListAccess = getChild("AccessList"); if (mListAccess) @@ -2452,10 +2438,9 @@ void LLPanelLandAccess::refresh() mListAccess->setToolTipArg(LLStringExplicit("[LISTED]"), llformat("%d",count)); mListAccess->setToolTipArg(LLStringExplicit("[MAX]"), llformat("%d",PARCEL_MAX_ACCESS_LIST)); - for (access_map_const_iterator cit = parcel->mAccessList.begin(); - cit != parcel->mAccessList.end(); ++cit) + for (const auto& pair : parcel->mAccessList) { - const LLAccessEntry& entry = (*cit).second; + const LLAccessEntry& entry = pair.second; LLSD item; item["id"] = entry.mID; LLSD& columns = item["columns"]; @@ -2490,10 +2475,9 @@ void LLPanelLandAccess::refresh() mListBanned->setToolTipArg(LLStringExplicit("[LISTED]"), llformat("%d",count)); mListBanned->setToolTipArg(LLStringExplicit("[MAX]"), llformat("%d",PARCEL_MAX_ACCESS_LIST)); - for (access_map_const_iterator cit = parcel->mBanList.begin(); - cit != parcel->mBanList.end(); ++cit) + for (const auto& pair : parcel->mBanList) { - const LLAccessEntry& entry = (*cit).second; + const LLAccessEntry& entry = pair.second; LLSD item; item["id"] = entry.mID; LLSD& columns = item["columns"]; @@ -2563,10 +2547,10 @@ void LLPanelLandAccess::refresh() getChild("PassCheck")->setValue(FALSE); getChild("PriceSpin")->setValue((F32)PARCEL_PASS_PRICE_DEFAULT); getChild("HoursSpin")->setValue(PARCEL_PASS_HOURS_DEFAULT ); - mListAccess->setToolTipArg(LLStringExplicit("[LISTED]"), llformat("%d",0)); - mListAccess->setToolTipArg(LLStringExplicit("[MAX]"), llformat("%d",0)); - mListBanned->setToolTipArg(LLStringExplicit("[LISTED]"), llformat("%d",0)); - mListBanned->setToolTipArg(LLStringExplicit("[MAX]"), llformat("%d",0)); + mListAccess->setToolTipArg(LLStringExplicit("[LISTED]"), zero_str); + mListAccess->setToolTipArg(LLStringExplicit("[MAX]"), zero_str); + mListBanned->setToolTipArg(LLStringExplicit("[LISTED]"), zero_str); + mListBanned->setToolTipArg(LLStringExplicit("[MAX]"), zero_str); } } @@ -2684,70 +2668,60 @@ void LLPanelLandAccess::draw() LLPanel::draw(); } -// static -void LLPanelLandAccess::onCommitPublicAccess(LLUICtrl *ctrl, void *userdata) +void LLPanelLandAccess::onCommitPublicAccess(LLUICtrl *ctrl) { - LLPanelLandAccess *self = (LLPanelLandAccess *)userdata; - LLParcel* parcel = self->mParcel->getParcel(); + LLParcel* parcel = mParcel->getParcel(); if (!parcel) { return; } // If we disabled public access, enable group access by default (if applicable) - BOOL public_access = self->getChild("public_access")->getValue().asBoolean(); - if (!public_access) + if (!getChild("public_access")->getValue().asBoolean()) { std::string group_name; if (gCacheName->getGroupName(parcel->getGroupID(), group_name)) { - self->getChild("GroupCheck")->setValue(true); + getChild("GroupCheck")->setValue(true); } } - onCommitAny(ctrl, userdata); + onCommitAny(); } -void LLPanelLandAccess::onCommitGroupCheck(LLUICtrl *ctrl, void *userdata) +void LLPanelLandAccess::onCommitGroupCheck(LLUICtrl *ctrl) { - LLPanelLandAccess *self = (LLPanelLandAccess *)userdata; - LLParcel* parcel = self->mParcel->getParcel(); + LLParcel* parcel = mParcel->getParcel(); if (!parcel) { return; } - BOOL use_pass_list = !self->getChild("public_access")->getValue().asBoolean(); - BOOL use_access_group = self->getChild("GroupCheck")->getValue().asBoolean(); - LLCtrlSelectionInterface* passcombo = self->childGetSelectionInterface("pass_combo"); - if (passcombo) + BOOL use_pass_list = !getChild("public_access")->getValue().asBoolean(); + BOOL use_access_group = getChild("GroupCheck")->getValue().asBoolean(); + LLCtrlSelectionInterface* passcombo = childGetSelectionInterface("pass_combo"); + if (passcombo && use_access_group && use_pass_list) { - if (use_access_group && use_pass_list) + if (passcombo->getSelectedValue().asString() == "group") { - if (passcombo->getSelectedValue().asString() == "group") - { - passcombo->selectByValue("anyone"); - } + passcombo->selectByValue("anyone"); } } - onCommitAny(ctrl, userdata); + onCommitAny(); } -// static -void LLPanelLandAccess::onCommitAny(LLUICtrl *ctrl, void *userdata) +void LLPanelLandAccess::onCommitAny() { - LLPanelLandAccess *self = (LLPanelLandAccess *)userdata; - - LLParcel* parcel = self->mParcel->getParcel(); + LLParcel* parcel = mParcel->getParcel(); if (!parcel) { return; } // Extract data from UI - BOOL public_access = self->getChild("public_access")->getValue().asBoolean(); - BOOL use_access_group = self->getChild("GroupCheck")->getValue().asBoolean(); + BOOL public_access = getChild("public_access")->getValue().asBoolean(); + BOOL use_access_group = getChild("GroupCheck")->getValue().asBoolean(); if (use_access_group) { std::string group_name; @@ -2765,14 +2739,14 @@ void LLPanelLandAccess::onCommitAny(LLUICtrl *ctrl, void *userdata) { use_access_list = FALSE; use_access_group = FALSE; - limit_payment = self->getChild("limit_payment")->getValue().asBoolean(); - limit_age_verified = self->getChild("limit_age_verified")->getValue().asBoolean(); + limit_payment = getChild("limit_payment")->getValue().asBoolean(); + limit_age_verified = getChild("limit_age_verified")->getValue().asBoolean(); } else { use_access_list = TRUE; - use_pass_list = self->getChild("PassCheck")->getValue().asBoolean(); - LLCtrlSelectionInterface* passcombo = self->childGetSelectionInterface("pass_combo"); + use_pass_list = getChild("PassCheck")->getValue().asBoolean(); + LLCtrlSelectionInterface* passcombo = childGetSelectionInterface("pass_combo"); if (passcombo) { if (use_access_group && use_pass_list) @@ -2785,8 +2759,8 @@ void LLPanelLandAccess::onCommitAny(LLUICtrl *ctrl, void *userdata) } } - S32 pass_price = llfloor((F32)self->getChild("PriceSpin")->getValue().asReal()); - F32 pass_hours = (F32)self->getChild("HoursSpin")->getValue().asReal(); + S32 pass_price = llfloor((F32)getChild("PriceSpin")->getValue().asReal()); + F32 pass_hours = (F32)getChild("HoursSpin")->getValue().asReal(); // Push data into current parcel parcel->setParcelFlag(PF_USE_ACCESS_GROUP, use_access_group); @@ -2803,7 +2777,7 @@ void LLPanelLandAccess::onCommitAny(LLUICtrl *ctrl, void *userdata) LLViewerParcelMgr::getInstance()->sendParcelPropertiesUpdate( parcel ); // Might have changed properties, so let's redraw! - self->refresh(); + refresh(); } void LLPanelLandAccess::onClickAddAccess() @@ -2845,15 +2819,14 @@ void LLPanelLandAccess::callbackAvatarCBAccess(const uuid_vec_t& ids) } // static -void LLPanelLandAccess::onClickRemoveAccess(void* data) +void LLPanelLandAccess::onClickRemoveAccess() { - LLPanelLandAccess* panelp = (LLPanelLandAccess*)data; - if (panelp && panelp->mListAccess) + if (mListAccess) { - LLParcel* parcel = panelp->mParcel->getParcel(); + LLParcel* parcel = mParcel->getParcel(); if (parcel) { - std::vector names = panelp->mListAccess->getAllSelected(); + std::vector names = mListAccess->getAllSelected(); for (std::vector::iterator iter = names.begin(); iter != names.end(); ) { @@ -2862,11 +2835,12 @@ void LLPanelLandAccess::onClickRemoveAccess(void* data) parcel->removeFromAccessList(agent_id); } LLViewerParcelMgr::getInstance()->sendParcelAccessListUpdate(AL_ACCESS); - panelp->refresh(); + refresh(); } } } +// static void LLPanelLandAccess::onClickAddBanned() { LLFloater* root_floater = gFloaterView->getParentFloater(this); @@ -2878,6 +2852,7 @@ void LLPanelLandAccess::onClickAddBanned() } } +// static void LLPanelLandAccess::callbackAvatarCBBanned(const uuid_vec_t& ids) { LLFloater* root_floater = gFloaterView->getParentFloater(this); @@ -2916,16 +2891,14 @@ void LLPanelLandAccess::callbackAvatarCBBanned2(const uuid_vec_t& ids, S32 durat } } -// static -void LLPanelLandAccess::onClickRemoveBanned(void* data) +void LLPanelLandAccess::onClickRemoveBanned() { - LLPanelLandAccess* panelp = (LLPanelLandAccess*)data; - if (panelp && panelp->mListBanned) + if (mListBanned) { - LLParcel* parcel = panelp->mParcel->getParcel(); + LLParcel* parcel = mParcel->getParcel(); if (parcel) { - std::vector names = panelp->mListBanned->getAllSelected(); + std::vector names = mListBanned->getAllSelected(); for (std::vector::iterator iter = names.begin(); iter != names.end(); ) { @@ -2934,7 +2907,7 @@ void LLPanelLandAccess::onClickRemoveBanned(void* data) parcel->removeFromBanList(agent_id); } LLViewerParcelMgr::getInstance()->sendParcelAccessListUpdate(AL_BAN); - panelp->refresh(); + refresh(); } } } @@ -2944,7 +2917,8 @@ void LLPanelLandAccess::onClickRemoveBanned(void* data) //--------------------------------------------------------------------------- LLPanelLandCovenant::LLPanelLandCovenant(LLParcelSelectionHandle& parcel) : LLPanel(std::string("land_covenant_panel")), - mParcel(parcel) + mParcel(parcel), + mNextUpdateTime(0) { } @@ -3005,13 +2979,22 @@ void LLPanelLandCovenant::refresh() } } - // send EstateCovenantInfo message - LLMessageSystem *msg = gMessageSystem; - msg->newMessage("EstateCovenantRequest"); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID,gAgent.getSessionID()); - msg->sendReliable(region->getHost()); + if (mLastRegionID != region->getRegionID() + || mNextUpdateTime < LLTimer::getElapsedSeconds()) + { + // Request Covenant Info + // Note: LLPanelLandCovenant doesn't change Covenant's content and any + // changes made by Estate floater should be requested by Estate floater + LLMessageSystem *msg = gMessageSystem; + msg->newMessage("EstateCovenantRequest"); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID,gAgent.getSessionID()); + msg->sendReliable(region->getHost()); + + mLastRegionID = region->getRegionID(); + mNextUpdateTime = LLTimer::getElapsedSeconds() + COVENANT_REFRESH_TIME_SEC; + } } // static @@ -3058,6 +3041,110 @@ void LLPanelLandCovenant::updateEstateOwnerID(const LLUUID& id) } } +LLPanelLandExperiences::LLPanelLandExperiences( LLSafeHandle& parcelp ) + : mParcel(parcelp), + mAllowed(nullptr), + mBlocked(nullptr) +{ + mFactoryMap["panel_allowed"] = LLCallbackMap(create_xp_list_editor, reinterpret_cast(&mAllowed)); + mFactoryMap["panel_blocked"] = LLCallbackMap(create_xp_list_editor, reinterpret_cast(&mBlocked)); + LLUICtrlFactory::getInstance()->buildPanel(this, "panel_region_experiences.xml", &mFactoryMap); +} + + +BOOL LLPanelLandExperiences::postBuild() +{ + setupList(mAllowed, "panel_allowed", EXPERIENCE_KEY_TYPE_ALLOWED, AL_ALLOW_EXPERIENCE); + setupList(mBlocked, "panel_blocked", EXPERIENCE_KEY_TYPE_BLOCKED, AL_BLOCK_EXPERIENCE); + + // only non-grid-wide experiences + mAllowed->addFilter(boost::bind(LLPanelExperiencePicker::FilterWithProperty, _1, LLExperienceCache::PROPERTY_GRID)); + + // no privileged ones + mBlocked->addFilter(boost::bind(LLPanelExperiencePicker::FilterWithoutProperties, _1, LLExperienceCache::PROPERTY_PRIVILEGED|LLExperienceCache::PROPERTY_GRID)); + + getChild("trusted_layout_panel")->setVisible(FALSE); + getChild("experiences_help_text")->setVisible(FALSE); + getChild("allowed_text_help")->setText(getString("allowed_parcel_text")); + getChild("blocked_text_help")->setText(getString("blocked_parcel_text")); + + return LLPanel::postBuild(); +} + +void LLPanelLandExperiences::setupList(LLPanelExperienceListEditor* child, const char* control_name, U32 xp_type, U32 access_type ) +{ + //LLPanelExperienceListEditor* child = findChild(control_name); + if (child) + { + child->getChild("text_name")->setText(child->getString(control_name)); + child->setMaxExperienceIDs(PARCEL_MAX_EXPERIENCE_LIST); + child->setAddedCallback(boost::bind(&LLPanelLandExperiences::experienceAdded, this, _1, xp_type, access_type)); + child->setRemovedCallback(boost::bind(&LLPanelLandExperiences::experienceRemoved, this, _1, access_type)); + } + + //return child; +} + +void LLPanelLandExperiences::experienceAdded( const LLUUID& id, U32 xp_type, U32 access_type ) +{ + LLParcel* parcel = mParcel->getParcel(); + if (parcel) + { + parcel->setExperienceKeyType(id, xp_type); + LLViewerParcelMgr::getInstance()->sendParcelAccessListUpdate(access_type); + refresh(); + } +} + +void LLPanelLandExperiences::experienceRemoved( const LLUUID& id, U32 access_type ) +{ + LLParcel* parcel = mParcel->getParcel(); + if (parcel) + { + parcel->setExperienceKeyType(id, EXPERIENCE_KEY_TYPE_NONE); + LLViewerParcelMgr::getInstance()->sendParcelAccessListUpdate(access_type); + refresh(); + } +} + +void LLPanelLandExperiences::refreshPanel(LLPanelExperienceListEditor* panel, U32 xp_type) +{ + LLParcel *parcel = mParcel->getParcel(); + + // Display options + if (panel == NULL) + { + return; + } + if (!parcel || gDisconnected) + { + // disable the panel + panel->setEnabled(FALSE); + panel->setExperienceIds(LLSD::emptyArray()); + } + else + { + // enable the panel + panel->setEnabled(TRUE); + LLAccessEntry::map entries = parcel->getExperienceKeysByType(xp_type); + LLAccessEntry::map::iterator it = entries.begin(); + LLSD ids = LLSD::emptyArray(); + for (/**/; it != entries.end(); ++it) + { + ids.append(it->second.mID); + } + panel->setExperienceIds(ids); + panel->setReadonly(!LLViewerParcelMgr::isParcelModifiableByAgent(parcel, GP_LAND_OPTIONS)); + panel->refreshExperienceCounter(); + } +} + +void LLPanelLandExperiences::refresh() +{ + refreshPanel(mAllowed, EXPERIENCE_KEY_TYPE_ALLOWED); + refreshPanel(mBlocked, EXPERIENCE_KEY_TYPE_BLOCKED); +} + // [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0a) void LLFloaterLand::open() { @@ -3095,3 +3182,16 @@ void LLFloaterLand::open() LLFloater::open(); } // [/RLVa:KB] + + +// virtual +void LLFloaterLand::onClose(bool app_quitting) +{ + // Might have been showing owned objects + LLSelectMgr::getInstance()->unhighlightAll(); + + // Save which panel we had open + sLastTab = mTabLand->getCurrentPanelIndex(); + + destroy(); +} diff --git a/indra/newview/llfloaterland.h b/indra/newview/llfloaterland.h index 9bc8011bf..4024d60a2 100644 --- a/indra/newview/llfloaterland.h +++ b/indra/newview/llfloaterland.h @@ -3,43 +3,33 @@ * @author James Cook * @brief "About Land" floater, allowing display and editing of land parcel properties. * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * 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 + * Copyright (C) 2010, Linden Research, Inc. * - * 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 + * 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. * - * 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. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #ifndef LL_LLFLOATERLAND_H #define LL_LLFLOATERLAND_H -#include -#include - #include "llfloater.h" #include "llpointer.h" // LLPointer<> -//#include "llviewertexturelist.h" #include "llsafehandle.h" const F32 CACHE_REFRESH_TIME = 2.5f; @@ -49,6 +39,7 @@ class LLCheckBoxCtrl; class LLRadioGroup; class LLComboBox; class LLLineEditor; +class LLMessageSystem; class LLNameListCtrl; class LLRadioGroup; class LLParcelSelectionObserver; @@ -58,7 +49,6 @@ class LLTextBox; class LLTextEditor; class LLTextureCtrl; class LLUIImage; -class LLViewerTextEditor; class LLParcelSelection; class LLPanelLandGeneral; @@ -71,9 +61,11 @@ class LLPanelLandBan; class LLPanelLandRenters; class LLPanelLandCovenant; class LLParcel; +class LLPanelLandExperiences; -class LLFloaterLand -: public LLFloater, public LLFloaterSingleton +class LLFloaterLand final +: public LLFloater +, public LLFloaterSingleton { friend class LLUISingleton >; public: @@ -85,24 +77,23 @@ public: LLParcel* getCurrentSelectedParcel(); // Destroys itself on close. - virtual void onClose(bool app_quitting); - virtual void onOpen(); - virtual BOOL postBuild(); + void onClose(bool app_quitting) override; + void onOpen() override; + BOOL postBuild() override; // [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0a) - virtual void open(); + void open() override; // [/RLVa:KB] - - -protected: - +private: // Does its own instance management, so clients not allowed // to allocate or destroy. LLFloaterLand(const LLSD& seed); virtual ~LLFloaterLand(); - /*virtual*/ void refresh(); +protected: + + /*virtual*/ void refresh() override; static void* createPanelLandGeneral(void* data); static void* createPanelLandCovenant(void* data); @@ -111,12 +102,15 @@ protected: static void* createPanelLandAudio(void* data); static void* createPanelLandMedia(void* data); static void* createPanelLandAccess(void* data); + static void* createPanelLandExperiences(void* data); static void* createPanelLandBan(void* data); + protected: static LLParcelSelectionObserver* sObserver; static S32 sLastTab; + friend class LLPanelLandObjects; LLTabContainer* mTabLand; LLPanelLandGeneral* mPanelGeneral; LLPanelLandObjects* mPanelObjects; @@ -125,6 +119,7 @@ protected: LLPanelLandMedia* mPanelMedia; LLPanelLandAccess* mPanelAccess; LLPanelLandCovenant* mPanelCovenant; + LLPanelLandExperiences* mPanelExperiences; LLSafeHandle mParcel; @@ -137,25 +132,25 @@ public: }; -class LLPanelLandGeneral +class LLPanelLandGeneral final : public LLPanel { public: LLPanelLandGeneral(LLSafeHandle& parcelp); virtual ~LLPanelLandGeneral(); - /*virtual*/ void refresh(); + /*virtual*/ void refresh() override; void refreshNames(); void setGroup(const LLUUID& group_id); void onClickSetGroup(); - static void onClickDeed(void*); static void onClickBuyLand(void* data); - static void onClickScriptLimits(void* data); - static void onClickRelease(void*); - static void onClickReclaim(void*); static void onClickBuyPass(void* deselect_when_done); + void onClickDeed(); + void onClickScriptLimits(); + void onClickRelease(); + void onClickReclaim(); static BOOL enableBuyPass(void*); - static void onCommitAny(LLUICtrl* ctrl, void *userdata); + void onCommitAny(); static void finalizeCommit(void * userdata); static void onForSaleChange(LLUICtrl *ctrl, void * userdata); static void finalizeSetSellChange(void * userdata); @@ -163,20 +158,20 @@ public: static bool cbBuyPass(const LLSD& notification, const LLSD& response); - static void onClickSellLand(void* data); - static void onClickStopSellLand(void* data); - static void onClickSet(void* data); - static void onClickClear(void* data); - static void onClickShow(void* data); + void onClickSellLand(); + void onClickStopSellLand(); + void onClickSet(); + void onClickClear(); + void onClickShow(); static void callbackAvatarPick(const std::vector& names, const uuid_vec_t& ids, void* data); static void finalizeAvatarPick(void* data); static void callbackHighlightTransferable(S32 option, void* userdata); - static void onClickStartAuction(void*); + void onClickStartAuction(); // sale change confirmed when "is for sale", "sale price", "sell to whom" fields are changed static void confirmSaleChange(S32 landSize, S32 salePrice, std::string authorizedName, void(*callback)(void*), void* userdata); static void callbackConfirmSaleChange(S32 option, void* userdata); - virtual BOOL postBuild(); + BOOL postBuild() override; protected: LLLineEditor* mEditName; @@ -235,36 +230,36 @@ protected: static LLHandle sBuyPassDialogHandle; }; -class LLPanelLandObjects +class LLPanelLandObjects final : public LLPanel { public: LLPanelLandObjects(LLSafeHandle& parcelp); virtual ~LLPanelLandObjects(); - /*virtual*/ void refresh(); + /*virtual*/ void refresh() override; bool callbackReturnOwnerObjects(const LLSD& notification, const LLSD& response); bool callbackReturnGroupObjects(const LLSD& notification, const LLSD& response); bool callbackReturnOtherObjects(const LLSD& notification, const LLSD& response); bool callbackReturnOwnerList(const LLSD& notification, const LLSD& response); - static void clickShowCore(LLPanelLandObjects* panelp, S32 return_type, uuid_list_t* list = 0); - static void onClickShowOwnerObjects(void*); - static void onClickShowGroupObjects(void*); - static void onClickShowOtherObjects(void*); + static void clickShowCore(LLPanelLandObjects* panelp, S32 return_type, uuid_list_t* list = nullptr); + void onClickShowOwnerObjects(); + void onClickShowGroupObjects(); + void onClickShowOtherObjects(); - static void onClickReturnOwnerObjects(void*); - static void onClickReturnGroupObjects(void*); - static void onClickReturnOtherObjects(void*); - static void onClickReturnOwnerList(void*); - static void onClickRefresh(void*); + void onClickReturnOwnerObjects(); + void onClickReturnGroupObjects(); + void onClickReturnOtherObjects(); + void onClickReturnOwnerList(); + void onClickRefresh(); void onCommitList(); static void onLostFocus(LLFocusableElement* caller, void* user_data); - static void onCommitClean(LLUICtrl* caller, void* user_data); + void onCommitClean(); static void processParcelObjectOwnersReply(LLMessageSystem *msg, void **); - virtual BOOL postBuild(); + BOOL postBuild() override; protected: @@ -304,23 +299,23 @@ protected: }; -class LLPanelLandOptions +class LLPanelLandOptions final : public LLPanel { public: LLPanelLandOptions(LLSafeHandle& parcelp); virtual ~LLPanelLandOptions(); - /*virtual*/ BOOL postBuild(); - /*virtual*/ void draw(); - /*virtual*/ void refresh(); + /*virtual*/ BOOL postBuild() override; + /*virtual*/ void draw() override; + /*virtual*/ void refresh() override; private: // Refresh the "show in search" checkbox and category selector. void refreshSearch(); - static void onCommitAny(LLUICtrl* ctrl, void *userdata); - static void onClickSet(void* userdata); - static void onClickClear(void* userdata); + void onCommitAny(); + void onClickSet(); + void onClickClear(); static void onClickPublishHelp(void*); private: @@ -355,24 +350,24 @@ private: }; -class LLPanelLandAccess +class LLPanelLandAccess final : public LLPanel { public: LLPanelLandAccess(LLSafeHandle& parcelp); virtual ~LLPanelLandAccess(); - void refresh(); + void refresh() override; void refresh_ui(); void refreshNames(); - virtual void draw(); + void draw() override; - static void onCommitPublicAccess(LLUICtrl* ctrl, void *userdata); - static void onCommitAny(LLUICtrl* ctrl, void *userdata); - static void onCommitGroupCheck(LLUICtrl* ctrl, void *userdata); - static void onClickRemoveAccess(void*); - static void onClickRemoveBanned(void*); + void onCommitPublicAccess(LLUICtrl* ctrl); + void onCommitAny(); + void onCommitGroupCheck(LLUICtrl* ctrl); + void onClickRemoveAccess(); + void onClickRemoveBanned(); - virtual BOOL postBuild(); + BOOL postBuild() override; void onClickAddAccess(); void onClickAddBanned(); @@ -387,15 +382,14 @@ protected: LLSafeHandle& mParcel; }; - -class LLPanelLandCovenant +class LLPanelLandCovenant final : public LLPanel { public: LLPanelLandCovenant(LLSafeHandle& parcelp); virtual ~LLPanelLandCovenant(); - virtual BOOL postBuild(); - void refresh(); + BOOL postBuild() override; + void refresh() override; static void updateCovenantText(const std::string& string); static void updateEstateName(const std::string& name); static void updateLastModified(const std::string& text); @@ -403,6 +397,10 @@ public: protected: LLSafeHandle& mParcel; + +private: + LLUUID mLastRegionID; + F64 mNextUpdateTime; //seconds since client start }; #endif diff --git a/indra/newview/llfloatermap.h b/indra/newview/llfloatermap.h index 839cf2f33..5b3876382 100644 --- a/indra/newview/llfloatermap.h +++ b/indra/newview/llfloatermap.h @@ -58,6 +58,8 @@ public: // [/RLVa:KB] private: + friend class OverlayToggle; + friend class LLScaleMap; LLFloaterMap(const LLSD& key = LLSD()); LLNetMap* mPanelMap; }; diff --git a/indra/newview/llfloatermarketplacelistings.cpp b/indra/newview/llfloatermarketplacelistings.cpp index b91e719e8..1c4cca63e 100644 --- a/indra/newview/llfloatermarketplacelistings.cpp +++ b/indra/newview/llfloatermarketplacelistings.cpp @@ -53,6 +53,8 @@ static LLPanelInjector t_panel_status("llpanelmarket LLPanelMarketplaceListings::LLPanelMarketplaceListings() : mRootFolder(NULL) +, mAuditBtn(nullptr) +, mFilterEditor(nullptr) , mSortOrder(LLInventoryFilter::SO_FOLDERS_BY_NAME) , mFilterListingFoldersOnly(false) { @@ -92,14 +94,13 @@ BOOL LLPanelMarketplaceListings::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL std::string& tooltip_msg) { LLView * handled_view = childrenHandleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); - BOOL handled = (handled_view != NULL); - // Special case the drop zone - if (handled && (handled_view->getName() == "marketplace_drop_zone")) + // Special case the drop zone, also we're a giant drop zone + if (!handled_view || (handled_view->getName() == "marketplace_drop_zone")) { LLFolderView* root_folder = getRootFolder(); - handled = root_folder->handleDragAndDropToThisFolder(mask, drop, cargo_type, cargo_data, accept, tooltip_msg); + return root_folder->handleDragAndDropToThisFolder(mask, drop, cargo_type, cargo_data, accept, tooltip_msg); } - return handled; + return false; } void LLPanelMarketplaceListings::buildAllPanels() @@ -222,7 +223,7 @@ void LLPanelMarketplaceListings::onTabChange() // Show/hide the drop zone and resize the inventory tabs panel accordingly LLPanel* drop_zone = (LLPanel*)getChild("marketplace_drop_zone"); bool drop_zone_visible = drop_zone->getVisible(); - bool allow_drop_on_root = panel->getAllowDropOnRoot() && gSavedSettings.getBOOL("LiruEnableWIPUI"); + bool allow_drop_on_root = panel->getAllowDropOnRoot(); if (drop_zone_visible != allow_drop_on_root) { LLPanel* tabs = (LLPanel*)getChild("tab_container_panel"); diff --git a/indra/newview/llfloaterobjectiminfo.cpp b/indra/newview/llfloaterobjectiminfo.cpp index 3610cab14..f240e21de 100644 --- a/indra/newview/llfloaterobjectiminfo.cpp +++ b/indra/newview/llfloaterobjectiminfo.cpp @@ -35,17 +35,13 @@ #include "llfloaterobjectiminfo.h" #include "llagentdata.h" -#include "llavataractions.h" -#include "llcachename.h" #include "llcommandhandler.h" -#include "llfloatergroupinfo.h" #include "llfloatermute.h" -#include "llgroupactions.h" #include "llmutelist.h" +#include "llnamebox.h" #include "llslurl.h" #include "lltrans.h" #include "llui.h" -#include "lluictrl.h" #include "lluictrlfactory.h" #include "llurlaction.h" #include "llweb.h" @@ -61,24 +57,15 @@ LLFloaterObjectIMInfo::LLFloaterObjectIMInfo(const LLSD& seed) : mName(), mSLurl(), mOwnerID(), mGroupOwned(false) { LLUICtrlFactory::getInstance()->buildFloater(this, "floater_object_im_info.xml"); - - if (!getRect().mLeft && !getRect().mBottom) - center(); -} -static void show_avatar_profile(const LLUUID& id) -{ -// [RLVa:KB] - Version: 1.23.4 | Checked: 2009-07-08 (RLVa-1.0.0e) | Added: RLVa-0.2.0g - if ((gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES) || gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS)) && RlvUtil::isNearbyAgent(id)) - return; -// [/RLVa:KB] - LLAvatarActions::showProfile(id); + const auto& rect = getRect(); + if (!rect.mLeft && !rect.mBottom) + center(); } BOOL LLFloaterObjectIMInfo::postBuild() { getChild("Mute")->setCommitCallback(boost::bind(&LLFloaterObjectIMInfo::onClickMute, this)); - getChild("OwnerName")->setClickedCallback(boost::bind(boost::ref(mGroupOwned) ? boost::bind(LLGroupActions::show, boost::ref(mOwnerID)) : boost::bind(show_avatar_profile, boost::ref(mOwnerID)))); getChild("Slurl")->setClickedCallback(boost::bind(LLUrlAction::executeSLURL, boost::bind(std::plus(), "secondlife:///app/worldmap/", boost::ref(mSLurl)), true)); return true; @@ -103,23 +90,20 @@ void LLFloaterObjectIMInfo::update(const LLSD& data) childSetVisible("Unknown_Slurl",!have_slurl); childSetVisible("Slurl",have_slurl); - childSetText("ObjectName",mName); + childSetText("ObjectName", mName); std::string slurl(mSLurl); std::string::size_type i = slurl.rfind("?owner_not_object"); if (i != std::string::npos) slurl.erase(i) += getString("owner"); childSetText("Slurl", slurl); - childSetText("OwnerName", LLStringUtil::null); + getChild("OwnerName")->setNameID(mOwnerID, mGroupOwned ? LFIDBearer::GROUP : LFIDBearer::AVATAR); getChildView("ObjectID")->setValue(data["object_id"].asUUID()); -// bool my_object = (owner_id == gAgentID); +// bool my_object = !mGroupOwned && (owner_id == gAgentID); // [RLVa:KB] - Version: 1.23.4 | Checked: 2009-07-08 (RLVa-1.0.0e) | Added: RLVa-0.2.0g - bool my_object = (mOwnerID == gAgentID) || ((gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES) || gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS)) && (RlvUtil::isNearbyAgent(mOwnerID))); + bool my_object = !mGroupOwned && (mOwnerID == gAgentID) || ((gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES) || gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS)) && (RlvUtil::isNearbyAgent(mOwnerID))); // [/RLVa:KB] childSetEnabled("Mute",!my_object); - - if (gCacheName) - gCacheName->get(mOwnerID, mGroupOwned, boost::bind(&LLFloaterObjectIMInfo::nameCallback, this, _2)); } void LLFloaterObjectIMInfo::onClickMute() @@ -134,27 +118,17 @@ void LLFloaterObjectIMInfo::onClickMute() close(); } -//static -void LLFloaterObjectIMInfo::nameCallback(const std::string& full_name) -{ - childSetText("OwnerName", mName = -// [RLVa:KB] - Version: 1.23.4 | Checked: 2009-07-08 (RLVa-1.0.0e) | Added: RLVa-0.2.0g - (!mGroupOwned && (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES) || gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS)) && RlvUtil::isNearbyAgent(mOwnerID)) ? RlvStrings::getAnonym(mName) : -// [/RLVa:KB] - full_name); -} - //////////////////////////////////////////////////////////////////////////// // LLObjectIMHandler //moved to llchathistory.cpp in v2 // support for secondlife:///app/objectim/{UUID}/ SLapps -class LLObjectIMHandler : public LLCommandHandler +class LLObjectIMHandler final : public LLCommandHandler { public: // requests will be throttled from a non-trusted browser LLObjectIMHandler() : LLCommandHandler("objectim", UNTRUSTED_THROTTLE) { } - bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web) + bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web) override { if (params.size() < 1) { diff --git a/indra/newview/llfloaterobjectiminfo.h b/indra/newview/llfloaterobjectiminfo.h index 31ff8c162..acddd1479 100644 --- a/indra/newview/llfloaterobjectiminfo.h +++ b/indra/newview/llfloaterobjectiminfo.h @@ -35,21 +35,19 @@ #include "llfloater.h" -class LLFloaterObjectIMInfo : public LLFloater, public LLFloaterSingleton +class LLFloaterObjectIMInfo final : public LLFloater, public LLFloaterSingleton { public: LLFloaterObjectIMInfo(const LLSD& sd); virtual ~LLFloaterObjectIMInfo() { }; - /*virtual*/ BOOL postBuild(); + BOOL postBuild() override; void update(const LLSD& payload); // UI Handlers void onClickMute(); - void nameCallback(const std::string& full_name); - private: LLUUID mOwnerID; std::string mSLurl; diff --git a/indra/newview/llfloaterobjectweights.cpp b/indra/newview/llfloaterobjectweights.cpp index e84517fbd..3eb19e065 100644 --- a/indra/newview/llfloaterobjectweights.cpp +++ b/indra/newview/llfloaterobjectweights.cpp @@ -44,11 +44,10 @@ bool LLCrossParcelFunctor::apply(LLViewerObject* obj) mBoundingBox.addBBoxAgent(LLBBox(obj->getPositionRegion(), obj->getRotationRegion(), obj->getScale() * -0.5f, obj->getScale() * 0.5f).getAxisAligned()); // Extend the bounding box across all the children. - LLViewerObject::const_child_list_t children = obj->getChildren(); - for (LLViewerObject::const_child_list_t::const_iterator iter = children.begin(); - iter != children.end(); iter++) + LLViewerObject::const_child_list_t const& children = obj->getChildren(); + for (const auto& iter : children) { - LLViewerObject* child = *iter; + LLViewerObject* child = iter; mBoundingBox.addBBoxAgent(LLBBox(child->getPositionRegion(), child->getRotationRegion(), child->getScale() * -0.5f, child->getScale() * 0.5f).getAxisAligned()); } @@ -67,16 +66,16 @@ bool LLCrossParcelFunctor::apply(LLViewerObject* obj) LLFloaterObjectWeights::LLFloaterObjectWeights(const LLSD& key) : LLFloater(key), - mSelectedObjects(NULL), - mSelectedPrims(NULL), - mSelectedDownloadWeight(NULL), - mSelectedPhysicsWeight(NULL), - mSelectedServerWeight(NULL), - mSelectedDisplayWeight(NULL), - mSelectedOnLand(NULL), - mRezzedOnLand(NULL), - mRemainingCapacity(NULL), - mTotalCapacity(NULL) + mSelectedObjects(nullptr), + mSelectedPrims(nullptr), + mSelectedDownloadWeight(nullptr), + mSelectedPhysicsWeight(nullptr), + mSelectedServerWeight(nullptr), + mSelectedDisplayWeight(nullptr), + mSelectedOnLand(nullptr), + mRezzedOnLand(nullptr), + mRemainingCapacity(nullptr), + mTotalCapacity(nullptr) { //buildFromFile("floater_tools.xml"); LLUICtrlFactory::getInstance()->buildFloater(this,"floater_object_weights.xml", NULL, false); @@ -142,7 +141,8 @@ void LLFloaterObjectWeights::setErrorStatus(U32 status, const std::string& reaso void LLFloaterObjectWeights::updateLandImpacts(const LLParcel* parcel) { - if (!parcel || LLSelectMgr::getInstance()->getSelection()->isEmpty()) + auto selection = LLSelectMgr::instance().getSelection(); + if (!parcel || !selection || selection->isEmpty()) { updateIfNothingSelected(); } @@ -161,24 +161,24 @@ void LLFloaterObjectWeights::updateLandImpacts(const LLParcel* parcel) void LLFloaterObjectWeights::refresh() { - LLSelectMgr* sel_mgr = LLSelectMgr::getInstance(); + auto selection = LLSelectMgr::instance().getSelection(); - if (sel_mgr->getSelection()->isEmpty()) + if (!selection || selection->isEmpty()) { updateIfNothingSelected(); } else { - S32 prim_count = sel_mgr->getSelection()->getObjectCount(); - S32 link_count = sel_mgr->getSelection()->getRootObjectCount(); - F32 prim_equiv = sel_mgr->getSelection()->getSelectedLinksetCost(); + S32 prim_count = selection->getObjectCount(); + S32 link_count = selection->getRootObjectCount(); + F32 prim_equiv = selection->getSelectedLinksetCost(); mSelectedObjects->setText(llformat("%d", link_count)); mSelectedPrims->setText(llformat("%d", prim_count)); mSelectedOnLand->setText(llformat("%.1d", (S32)prim_equiv)); LLCrossParcelFunctor func; - if (sel_mgr->getSelection()->applyToRootObjects(&func, true)) + if (selection->applyToRootObjects(&func, true)) { // Some of the selected objects cross parcel bounds. // We don't display object weights and land impacts in this case. @@ -194,8 +194,8 @@ void LLFloaterObjectWeights::refresh() LLViewerRegion* region = gAgent.getRegion(); if (region && region->capabilitiesReceived()) { - for (LLObjectSelection::valid_root_iterator iter = sel_mgr->getSelection()->valid_root_begin(); - iter != sel_mgr->getSelection()->valid_root_end(); ++iter) + for (LLObjectSelection::valid_root_iterator iter = selection->valid_root_begin(); + iter != selection->valid_root_end(); ++iter) { LLAccountingCostManager::getInstance()->addObject((*iter)->getObject()->getID()); } @@ -212,7 +212,6 @@ void LLFloaterObjectWeights::refresh() } else { - //LL_WARNS() << "Failed to get region capabilities" << LL_ENDL; LL_WARNS() << "Failed to get region capabilities" << LL_ENDL; } } diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index bfdaf6abb..680fa258e 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -333,9 +333,9 @@ void LLPreferenceCore::onTabChanged(LLUICtrl* ctrl) } -void LLPreferenceCore::setPersonalInfo(const std::string& visibility, bool im_via_email, const std::string& email) +void LLPreferenceCore::setPersonalInfo(const std::string& visibility, bool im_via_email, const std::string& email, bool is_verified) { - mPrefsIM->setPersonalInfo(visibility, im_via_email, email); + mPrefsIM->setPersonalInfo(visibility, im_via_email, email, is_verified); } ////////////////////////////////////////////// @@ -408,15 +408,7 @@ void LLFloaterPreference::show(void*) sInstance->open(); /* Flawfinder: ignore */ - if(!gAgent.getID().isNull()) - { - // we're logged in, so we can get this info. - gMessageSystem->newMessageFast(_PREHASH_UserInfoRequest); - gMessageSystem->nextBlockFast(_PREHASH_AgentData); - gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - gAgent.sendReliableMessage(); - } + gAgent.sendAgentUserInfoRequest(); LLPanelLogin::setAlwaysRefresh(true); } @@ -496,11 +488,11 @@ void LLFloaterPreference::onBtnCancel() // static -void LLFloaterPreference::updateUserInfo(const std::string& visibility, bool im_via_email, const std::string& email) +void LLFloaterPreference::updateUserInfo(const std::string& visibility, bool im_via_email, const std::string& email, bool is_verified) { - if(sInstance && sInstance->mPreferenceCore) + if (sInstance && sInstance->mPreferenceCore) { - sInstance->mPreferenceCore->setPersonalInfo(visibility, im_via_email, email); + sInstance->mPreferenceCore->setPersonalInfo(visibility, im_via_email, email, is_verified); } } diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index e16f40cb6..4ee0053f2 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -73,7 +73,7 @@ public: LLTabContainer* getTabContainer() { return mTabContainer; } - void setPersonalInfo(const std::string& visibility, bool im_via_email, const std::string& email); + void setPersonalInfo(const std::string& visibility, bool im_via_email, const std::string& email, bool is_verified); static void onTabChanged(LLUICtrl* ctrl); @@ -109,7 +109,7 @@ public: static void show(void*); // static data update, called from message handler - static void updateUserInfo(const std::string& visibility, bool im_via_email, const std::string& email); + static void updateUserInfo(const std::string& visibility, bool im_via_email, const std::string& email, bool is_verified = false); static void switchTab(S32 i); diff --git a/indra/newview/llfloaterproperties.cpp b/indra/newview/llfloaterproperties.cpp index 9a32f4011..2dac6344f 100644 --- a/indra/newview/llfloaterproperties.cpp +++ b/indra/newview/llfloaterproperties.cpp @@ -44,6 +44,8 @@ #include "llavataractions.h" #include "llbutton.h" #include "llcheckboxctrl.h" +#include "llcororesponder.h" +#include "llexperiencecache.h" #include "llgroupactions.h" #include "llinventorymodel.h" #include "llinventoryobserver.h" @@ -51,8 +53,8 @@ #include "llradiogroup.h" #include "llresmgr.h" #include "roles_constants.h" +#include "llnamebox.h" #include "llselectmgr.h" -#include "lltextbox.h" #include "lltrans.h" #include "llviewerinventory.h" #include "llviewerobjectlist.h" @@ -64,11 +66,6 @@ #include "lfsimfeaturehandler.h" #include "hippogridmanager.h" - -// [RLVa:KB] -#include "rlvhandler.h" -// [/RLVa:KB] - bool can_set_export(const U32& base, const U32& own, const U32& next); //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -81,7 +78,7 @@ bool can_set_export(const U32& base, const U32& own, const U32& next); // from the inventory observer list when destroyed, which could // happen after gInventory has already been destroyed if a singleton. // Instead, do our own ref counting and create / destroy it as needed -class LLPropertiesObserver : public LLInventoryObserver +class LLPropertiesObserver final : public LLInventoryObserver { public: LLPropertiesObserver(LLFloaterProperties* floater) @@ -93,9 +90,10 @@ public: { gInventory.removeObserver(this); } - virtual void changed(U32 mask); + + void changed(U32 mask) override; private: - LLFloaterProperties* mFloater; + LLFloaterProperties* mFloater; // Not a handle because LLFloaterProperties is managing LLPropertiesObserver }; void LLPropertiesObserver::changed(U32 mask) @@ -154,7 +152,7 @@ LLFloaterProperties::LLFloaterProperties(const std::string& name, const LLRect& LLFloaterProperties::~LLFloaterProperties() { delete mPropertiesObserver; - mPropertiesObserver = NULL; + mPropertiesObserver = nullptr; } // virtual @@ -216,7 +214,7 @@ void LLFloaterProperties::refresh() mDirty = TRUE; - const char* enableNames[]={ + static constexpr std::array enableNames{{ "LabelItemName", "LabelItemDesc", "LabelCreatorName", @@ -238,21 +236,21 @@ void LLFloaterProperties::refresh() "CheckPurchase", "RadioSaleType", "Edit Cost" - }; - for(size_t t=0; tsetEnabled(false); + getChildView(name)->setEnabled(false); } - const char* hideNames[]={ + static constexpr std::array hideNames{{ "BaseMaskDebug", "OwnerMaskDebug", "GroupMaskDebug", "EveryoneMaskDebug", "NextMaskDebug" - }; - for(size_t t=0; tsetVisible(false); + getChildView(name)->setVisible(false); } } } @@ -290,7 +288,7 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item) // You need permission to modify the object to modify an inventory // item in it. - LLViewerObject* object = NULL; + LLViewerObject* object = nullptr; if(!mObjectID.isNull()) object = gObjectList.findObject(mObjectID); BOOL is_obj_modify = TRUE; if(object) @@ -298,6 +296,24 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item) is_obj_modify = object->permOwnerModify(); } + if (item->getInventoryType() == LLInventoryType::IT_LSL) + { + getChildView("LabelItemExperienceTitle")->setVisible(TRUE); + LLTextBox* tb = getChild("LabelItemExperience"); + if (tb->getValue().asUUID().isNull()) + { + tb->setText(getString("loading_experience")); + tb->setVisible(TRUE); + } + std::string url = std::string(); + if(object && object->getRegion()) + { + url = object->getRegion()->getCapability("GetMetadata"); + } + LLExperienceCache::instance().fetchAssociatedExperience(item->getParentUUID(), item->getUUID(), url, + boost::bind(&LLFloaterProperties::setAssociatedExperience, getDerivedHandle(), _1)); + } + ////////////////////// // ITEM NAME & DESC // ////////////////////// @@ -403,11 +419,11 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item) getChild("CheckOwnerCopy")->setValue(LLSD((BOOL)(owner_mask & PERM_COPY))); getChildView("CheckOwnerTransfer")->setEnabled(FALSE); getChild("CheckOwnerTransfer")->setValue(LLSD((BOOL)(owner_mask & PERM_TRANSFER))); + getChildView("CheckOwnerExport")->setEnabled(FALSE); + getChild("CheckOwnerExport")->setValue(LLSD((BOOL)(owner_mask & PERM_EXPORT))); bool supports_export = LFSimFeatureHandler::instance().simSupportsExport(); - getChildView("CheckOwnerExport")->setEnabled(false); - getChild("CheckOwnerExport")->setValue(LLSD((BOOL)(supports_export && owner_mask & PERM_EXPORT))); - if (!gHippoGridManager->getCurrentGrid()->isSecondLife()) + if (!supports_export) getChildView("CheckOwnerExport")->setVisible(false); /////////////////////// @@ -520,6 +536,9 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item) const LLSaleInfo& sale_info = item->getSaleInfo(); BOOL is_for_sale = sale_info.isForSale(); + LLRadioGroup* radioSaleType = getChild("RadioSaleType"); + LLUICtrl* edit_cost = getChild("Edit Cost"); + // Check for ability to change values. if (is_obj_modify && can_agent_sell && gAgent.allowOperation(PERM_TRANSFER, perm, GP_OBJECT_MANIPULATE)) @@ -533,9 +552,9 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item) getChildView("CheckNextOwnerCopy")->setEnabled(no_export && (base_mask & PERM_COPY) && !cannot_restrict_permissions); getChildView("CheckNextOwnerTransfer")->setEnabled(no_export && (next_owner_mask & PERM_COPY) && !cannot_restrict_permissions); - getChildView("RadioSaleType")->setEnabled(is_complete && is_for_sale); + radioSaleType->setEnabled(is_complete && is_for_sale); getChildView("TextPrice")->setEnabled(is_complete && is_for_sale); - getChildView("Edit Cost")->setEnabled(is_complete && is_for_sale); + edit_cost->setEnabled(is_complete && is_for_sale); } else { @@ -547,30 +566,51 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item) getChildView("CheckNextOwnerCopy")->setEnabled(FALSE); getChildView("CheckNextOwnerTransfer")->setEnabled(FALSE); - getChildView("RadioSaleType")->setEnabled(FALSE); + radioSaleType->setEnabled(FALSE); getChildView("TextPrice")->setEnabled(FALSE); - getChildView("Edit Cost")->setEnabled(FALSE); + edit_cost->setEnabled(FALSE); } // Set values. getChild("CheckPurchase")->setValue(is_for_sale); - getChildView("Edit Cost")->setEnabled(is_for_sale); + edit_cost->setEnabled(is_for_sale); getChild("CheckNextOwnerModify")->setValue(LLSD(BOOL(next_owner_mask & PERM_MODIFY))); getChild("CheckNextOwnerCopy")->setValue(LLSD(BOOL(next_owner_mask & PERM_COPY))); getChild("CheckNextOwnerTransfer")->setValue(LLSD(BOOL(next_owner_mask & PERM_TRANSFER))); - LLRadioGroup* radioSaleType = getChild("RadioSaleType"); if (is_for_sale) { - radioSaleType->setSelectedIndex((S32)sale_info.getSaleType() - 1); S32 numerical_price; numerical_price = sale_info.getSalePrice(); - getChild("Edit Cost")->setValue(llformat("%d",numerical_price)); + edit_cost->setValue(llformat("%d",numerical_price)); + radioSaleType->setSelectedIndex((S32)sale_info.getSaleType() - 1); } else { + edit_cost->setValue("0"); radioSaleType->setSelectedIndex(-1); - getChild("Edit Cost")->setValue(llformat("%d",0)); + } +} + + +void LLFloaterProperties::setAssociatedExperience(LLHandle hInfo, const LLSD& experience) +{ + LLFloaterProperties* info = hInfo.get(); + if (info && experience.has(LLExperienceCache::EXPERIENCE_ID)) + { + auto id = experience[LLExperienceCache::EXPERIENCE_ID].asUUID(); + if (id.notNull()) + { + //info->getChild("LabelItemExperience")->setText(LLSLURL("experience", id, "profile").getSLURLString(); + if (LLNameBox* tb = info->getChild("LabelItemExperience")) + { + tb->setValue(id); + } + } + else + { + info->getChild("LabelItemExperience")->setText(LLTrans::getString("ExperienceNameNull")); + } } } @@ -687,11 +727,6 @@ void LLFloaterProperties::onCommitPermissions() perm.setEveryoneBits(gAgent.getID(), gAgent.getGroupID(), CheckEveryoneCopy->get(), PERM_COPY); } - LLCheckBoxCtrl* CheckExport = getChild("CheckExport"); - if(CheckExport) - { - perm.setEveryoneBits(gAgent.getID(), gAgent.getGroupID(), CheckExport->get(), PERM_EXPORT); - } LLCheckBoxCtrl* CheckNextOwnerModify = getChild("CheckNextOwnerModify"); if(CheckNextOwnerModify) @@ -711,6 +746,13 @@ void LLFloaterProperties::onCommitPermissions() perm.setNextOwnerBits(gAgent.getID(), gAgent.getGroupID(), CheckNextOwnerTransfer->get(), PERM_TRANSFER); } + + LLCheckBoxCtrl* CheckExport = getChild("CheckExport"); + if(CheckExport && CheckExport->getVisible()) + { + perm.setEveryoneBits(gAgent.getID(), gAgent.getGroupID(), CheckExport->get(), PERM_EXPORT); + } + if(perm != item->getPermissions() && item->isFinished()) { @@ -884,7 +926,7 @@ void LLFloaterProperties::updateSaleInfo() LLInventoryItem* LLFloaterProperties::findItem() const { - LLInventoryItem* item = NULL; + LLInventoryItem* item = nullptr; if(mObjectID.isNull()) { // it is in agent inventory diff --git a/indra/newview/llfloaterproperties.h b/indra/newview/llfloaterproperties.h index 5d90fea0c..547040e6b 100644 --- a/indra/newview/llfloaterproperties.h +++ b/indra/newview/llfloaterproperties.h @@ -86,6 +86,8 @@ protected: void refreshFromItem(LLInventoryItem* item); virtual void draw(); + static void setAssociatedExperience(LLHandle hInfo, const LLSD& experience); + protected: // The item id of the inventory item in question. LLUUID mItemID; diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp index 2671d5f9b..e4d775491 100644 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -3,31 +3,25 @@ * @author Aaron Brashears * @brief Implementation of the region info and controls floater and panels. * - * $LicenseInfo:firstyear=2004&license=viewergpl$ - * - * Copyright (c) 2004-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * 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 + * Copyright (C) 2010, Linden Research, Inc. * - * 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 + * 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. * - * 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. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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$ */ @@ -65,6 +59,7 @@ #include "llfloaterregiondebugconsole.h" #include "llfloatertelehub.h" #include "llinventorymodel.h" +#include "lllayoutstack.h" #include "lllineeditor.h" #include "llnamelistctrl.h" #include "llnotifications.h" @@ -88,6 +83,11 @@ #include "llvlcomposition.h" #include "llwaterparammanager.h" #include "llagentui.h" +#include "llpanelexperiencelisteditor.h" +#include +#include "llpanelexperiencepicker.h" +#include "llexperiencecache.h" +#include "llpanelexperiences.h" #include "hippogridmanager.h" // [RLVa:KB] #include "rlvhandler.h" @@ -102,28 +102,40 @@ const U32 MAX_LISTED_NAMES = 100; /// Local class declaration ///---------------------------------------------------------------------------- -class LLDispatchEstateUpdateInfo : public LLDispatchHandler +class LLDispatchEstateUpdateInfo final : public LLDispatchHandler { public: LLDispatchEstateUpdateInfo() {} virtual ~LLDispatchEstateUpdateInfo() {} - virtual bool operator()( + bool operator()( const LLDispatcher* dispatcher, const std::string& key, const LLUUID& invoice, - const sparam_t& strings); + const sparam_t& strings) override; }; -class LLDispatchSetEstateAccess : public LLDispatchHandler +class LLDispatchSetEstateAccess final : public LLDispatchHandler { public: LLDispatchSetEstateAccess() {} virtual ~LLDispatchSetEstateAccess() {} - virtual bool operator()( + bool operator()( const LLDispatcher* dispatcher, const std::string& key, const LLUUID& invoice, - const sparam_t& strings); + const sparam_t& strings) override; +}; + +class LLDispatchSetEstateExperience final : public LLDispatchHandler +{ +public: + bool operator()( + const LLDispatcher* dispatcher, + const std::string& key, + const LLUUID& invoice, + const sparam_t& strings) override; + + LLSD getIDs(sparam_t::const_iterator it, sparam_t::const_iterator end, S32 count); }; @@ -256,6 +268,18 @@ BOOL LLFloaterRegionInfo::postBuild() LLUICtrlFactory::getInstance()->buildPanel(panel, "panel_region_debug.xml"); mTab->addTabPanel(panel, panel->getLabel(), FALSE); + if(gDisconnected) + { + return TRUE; + } + + if (!gAgent.getRegion()->getCapability("RegionExperiences").empty()) + { + panel = new LLPanelRegionExperiences; + mInfoPanels.push_back(panel); + mTab->addTabPanel(panel, panel->getLabel(), FALSE); + } + gMessageSystem->setHandlerFunc( "EstateOwnerMessage", &processEstateOwnerRequest); @@ -488,7 +512,7 @@ void LLFloaterRegionInfo::processRegionInfo(LLMessageSystem* msg) LLPanelEstateInfo* LLFloaterRegionInfo::getPanelEstate() { LLFloaterRegionInfo* floater = LLFloaterRegionInfo::getInstance(); - if (!floater) return NULL; + if (!floater) return nullptr; LLTabContainer* tab = floater->getChild("region_panels"); LLPanelEstateInfo* panel = (LLPanelEstateInfo*)tab->getChild("Estate"); return panel; @@ -508,7 +532,7 @@ LLPanelEstateAccess* LLFloaterRegionInfo::getPanelAccess() LLPanelEstateCovenant* LLFloaterRegionInfo::getPanelCovenant() { LLFloaterRegionInfo* floater = LLFloaterRegionInfo::getInstance(); - if (!floater) return NULL; + if (!floater) return nullptr; LLTabContainer* tab = floater->getChild("region_panels"); LLPanelEstateCovenant* panel = (LLPanelEstateCovenant*)tab->getChild("Covenant"); return panel; @@ -521,7 +545,7 @@ LLPanelRegionTerrainInfo* LLFloaterRegionInfo::getPanelRegionTerrain() if (!floater) { llassert(floater); - return NULL; + return nullptr; } LLTabContainer* tab_container = floater->getChild("region_panels"); @@ -531,6 +555,14 @@ LLPanelRegionTerrainInfo* LLFloaterRegionInfo::getPanelRegionTerrain() return panel; } +LLPanelRegionExperiences* LLFloaterRegionInfo::getPanelExperiences() +{ + LLFloaterRegionInfo* floater = LLFloaterRegionInfo::getInstance(); + if (!floater) return nullptr; + LLTabContainer* tab = floater->getChild("region_panels"); + return (LLPanelRegionExperiences*)tab->getChild("Experiences"); +} + void LLFloaterRegionInfo::onTabSelected(const LLSD& param) { LLPanelRegionInfo* active_panel = getChild(param.asString()); @@ -662,7 +694,7 @@ void LLPanelRegionInfo::sendEstateOwnerMessage( if(strings.empty()) { msg->nextBlock("ParamList"); - msg->addString("Parameter", NULL); + msg->addString("Parameter", nullptr); } else { @@ -1538,6 +1570,11 @@ void LLPanelEstateInfo::initDispatch(LLDispatcher& dispatch) static LLDispatchSetEstateAccess set_access; dispatch.addHandler(name, &set_access); + + name.assign("setexperience"); + static LLDispatchSetEstateExperience set_experience; + dispatch.addHandler(name, &set_experience); + estate_dispatch_initialized = true; } @@ -1747,13 +1784,13 @@ BOOL LLPanelEstateInfo::postBuild() { // set up the callbacks for the generic controls initCtrl("externally_visible_check"); - initCtrl("use_global_time_check"); - initCtrl("fixed_sun_check"); - initCtrl("sun_hour_slider"); initCtrl("allow_direct_teleport"); initCtrl("limit_payment"); initCtrl("limit_age_verified"); initCtrl("voice_chat_check"); + initCtrl("use_global_time_check"); + initCtrl("fixed_sun_check"); + initCtrl("sun_hour_slider"); initHelpBtn("use_global_time_help", "HelpEstateUseGlobalTime"); initHelpBtn("fixed_sun_help", "HelpEstateFixedSun"); initHelpBtn("externally_visible_help", "HelpEstateExternallyVisible"); @@ -2033,7 +2070,7 @@ BOOL LLPanelEstateCovenant::postBuild() if (mEditor) mEditor->setHandleEditKeysDirectly(TRUE); LLButton* reset_button = getChild("reset_covenant"); reset_button->setEnabled(gAgent.canManageEstate()); - reset_button->setClickedCallback(LLPanelEstateCovenant::resetCovenantID, NULL); + reset_button->setClickedCallback(LLPanelEstateCovenant::resetCovenantID, nullptr); return LLPanelRegionInfo::postBuild(); } @@ -2114,7 +2151,7 @@ bool LLPanelEstateCovenant::confirmResetCovenantCallback(const LLSD& notificatio switch(option) { case 0: - self->loadInvItem(NULL); + self->loadInvItem(nullptr); break; default: break; @@ -2342,11 +2379,11 @@ bool LLDispatchSetEstateAccess::operator()( if (!panel) return true; S32 index = 1; // skip estate_id - U32 access_flags = strtoul(strings[index++].c_str(), NULL,10); - S32 num_allowed_agents = strtol(strings[index++].c_str(), NULL, 10); - S32 num_allowed_groups = strtol(strings[index++].c_str(), NULL, 10); - S32 num_banned_agents = strtol(strings[index++].c_str(), NULL, 10); - S32 num_estate_managers = strtol(strings[index++].c_str(), NULL, 10); + U32 access_flags = strtoul(strings[index++].c_str(), nullptr,10); + S32 num_allowed_agents = strtol(strings[index++].c_str(), nullptr, 10); + S32 num_allowed_groups = strtol(strings[index++].c_str(), nullptr, 10); + S32 num_banned_agents = strtol(strings[index++].c_str(), nullptr, 10); + S32 num_estate_managers = strtol(strings[index++].c_str(), nullptr, 10); // sanity ckecks if (num_allowed_agents > 0 @@ -2446,13 +2483,63 @@ bool LLDispatchSetEstateAccess::operator()( return true; } +LLSD LLDispatchSetEstateExperience::getIDs( sparam_t::const_iterator it, sparam_t::const_iterator end, S32 count ) +{ + LLSD idList = LLSD::emptyArray(); + LLUUID id; + while(count--> 0) + { + memcpy(id.mData, (*(it++)).data(), UUID_BYTES); + idList.append(id); + } + return idList; +} + +// key = "setexperience" +// strings[0] = str(estate_id) +// strings[1] = str(send_to_agent_only) +// strings[2] = str(num blocked) +// strings[3] = str(num trusted) +// strings[4] = str(num allowed) +// strings[8] = bin(uuid) ... +// ... +bool LLDispatchSetEstateExperience::operator()( + const LLDispatcher* dispatcher, + const std::string& key, + const LLUUID& invoice, + const sparam_t& strings) +{ + LLPanelRegionExperiences* panel = LLFloaterRegionInfo::getPanelExperiences(); + if (!panel) return true; + + sparam_t::const_iterator it = strings.begin(); + ++it; // U32 estate_id = strtol((*it).c_str(), NULL, 10); + ++it; // U32 send_to_agent_only = strtoul((*(++it)).c_str(), NULL, 10); + + LLUUID id; + S32 num_blocked = strtol((*(it++)).c_str(), nullptr, 10); + S32 num_trusted = strtol((*(it++)).c_str(), nullptr, 10); + S32 num_allowed = strtol((*(it++)).c_str(), nullptr, 10); + + LLSD ids = LLSD::emptyMap() + .with("blocked", getIDs(it, strings.end(), num_blocked)) + .with("trusted", getIDs(it + (num_blocked), strings.end(), num_trusted)) + .with("allowed", getIDs(it + (num_blocked+num_trusted), strings.end(), num_allowed)); + + panel->processResponse(ids); + + return true; +} + + + LLPanelEnvironmentInfo::LLPanelEnvironmentInfo() : mEnableEditing(false), - mRegionSettingsRadioGroup(NULL), - mDayCycleSettingsRadioGroup(NULL), - mWaterPresetCombo(NULL), - mSkyPresetCombo(NULL), - mDayCyclePresetCombo(NULL) + mRegionSettingsRadioGroup(nullptr), + mDayCycleSettingsRadioGroup(nullptr), + mWaterPresetCombo(nullptr), + mSkyPresetCombo(nullptr), + mDayCyclePresetCombo(nullptr) { } @@ -2475,9 +2562,9 @@ BOOL LLPanelEnvironmentInfo::postBuild() mDayCyclePresetCombo->setCommitCallback(boost::bind(&LLPanelEnvironmentInfo::onSelectDayCycle, this)); getChild("apply_btn")->setCommitCallback(boost::bind(&LLPanelEnvironmentInfo::onBtnApply, this)); - //getChild("apply_btn")->setRightMouseDownCallback(boost::bind(&LLEnvManagerNew::dumpUserPrefs, LLEnvManagerNew::getInstance())); + getChild("apply_btn")->setRightMouseDownCallback(boost::bind(&LLEnvManagerNew::dumpUserPrefs, LLEnvManagerNew::getInstance())); getChild("cancel_btn")->setCommitCallback(boost::bind(&LLPanelEnvironmentInfo::onBtnCancel, this)); - //getChild("cancel_btn")->setRightMouseDownCallback(boost::bind(&LLEnvManagerNew::dumpPresets, LLEnvManagerNew::getInstance())); + getChild("cancel_btn")->setRightMouseDownCallback(boost::bind(&LLEnvManagerNew::dumpPresets, LLEnvManagerNew::getInstance())); LLEnvManagerNew::instance().setRegionSettingsChangeCallback(boost::bind(&LLPanelEnvironmentInfo::onRegionSettingschange, this)); LLEnvManagerNew::instance().setRegionSettingsAppliedCallback(boost::bind(&LLPanelEnvironmentInfo::onRegionSettingsApplied, this, _1)); @@ -2523,6 +2610,11 @@ bool LLPanelEnvironmentInfo::refreshFromRegion(LLViewerRegion* region) void LLPanelEnvironmentInfo::refresh() { + if(gDisconnected) + { + return; + } + populateWaterPresetsList(); populateSkyPresetsList(); populateDayCyclesList(); @@ -3040,7 +3132,6 @@ void LLPanelEnvironmentInfo::onRegionSettingsApplied(bool ok) } } -#if 0 // Singu TODO: Experiences LLPanelRegionExperiences::LLPanelRegionExperiences() : mTrusted(nullptr) , mAllowed(nullptr) @@ -3311,7 +3402,6 @@ void LLPanelRegionExperiences::itemChanged( U32 event_type, const LLUUID& id ) onChangeAnything(); } -#endif // Singu TODO: Experiences LLPanelEstateAccess::LLPanelEstateAccess() : LLPanelRegionInfo(), mPendingUpdate(false) @@ -4118,6 +4208,27 @@ const std::string& getNAString() return na; } +#if defined(__GNUC__) && __GNUC__ < 5 // On GCC 4, implement std::get_time using strptime +#include + +namespace std +{ + struct get_time + { + tm* mTime; + const char* mFmt; + get_time(tm* time, const char* fmt) : mTime(time), mFmt(fmt) {} + }; + + istringstream& operator>>(istringstream&& str, get_time&& rhs) + { + if (!strptime(str.str().data(), rhs.mFmt, rhs.mTime)) + str.setstate(ios_base::failbit); + return str; + } +} +#endif + void handlePseudoISO8601(const std::string& date_str, LLSD& column, const std::string& fmt) { if (date_str.front() == '0') // server returns the "0000-00-00 00:00:00" date in case it doesn't know it @@ -4127,7 +4238,7 @@ void handlePseudoISO8601(const std::string& date_str, LLSD& column, const std::s else { std::tm time = {}; - if (std::istringstream(date_str) >> std::get_time(&time, "%Y-%m-%d %T")) + if (std::istringstream(date_str) >> std::get_time(&time, "%F %T")) { column["value"] = LLDate(mktime(&time)); column["type"] = "date"; @@ -4334,10 +4445,11 @@ void LLFloaterRegionInfo::open() { const LLViewerRegion* region(gAgent.getRegion()); // Should be able to call LLRegion::canManageEstate() but then we can fake god like - if (!(region && region->isEstateManager() && region->getOwner() == gAgentID)) + if (!region || !region->isEstateManager() || region->getOwner() != gAgentID) return; } LLFloater::open(); } // [/RLVa:KB] + diff --git a/indra/newview/llfloaterregioninfo.h b/indra/newview/llfloaterregioninfo.h index 96daf580a..0a5840116 100644 --- a/indra/newview/llfloaterregioninfo.h +++ b/indra/newview/llfloaterregioninfo.h @@ -3,31 +3,25 @@ * @author Aaron Brashears * @brief Declaration of the region info and controls floater and panels. * - * $LicenseInfo:firstyear=2004&license=viewergpl$ - * - * Copyright (c) 2004-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * 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 + * Copyright (C) 2010, Linden Research, Inc. * - * 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 + * 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. * - * 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. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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$ */ @@ -42,6 +36,7 @@ #include "llenvmanager.h" // for LLEnvironmentSettings class LLAvatarName; +class LLDispatcher; struct LLEstateAccessChangeInfo; class LLLineEditor; class LLMessageSystem; @@ -57,6 +52,7 @@ class LLRadioGroup; class LLSliderCtrl; class LLSpinCtrl; class LLTextBox; +class LLVFS; class AIFilePicker; class LLPanelRegionGeneralInfo; @@ -64,8 +60,17 @@ class LLPanelRegionDebugInfo; class LLPanelRegionTerrainInfo; class LLPanelEstateInfo; class LLPanelEstateCovenant; +class LLPanelExperienceListEditor; +class LLPanelExperiences; +class LLPanelRegionExperiences; class LLPanelEstateAccess; +class LLEventTimer; +class LLEnvironmentSettings; +class LLWLParamManager; +class LLWaterParamManager; +class LLWLParamSet; +class LLWaterParamSet; class LLFloaterRegionInfo : public LLFloater, public LLFloaterSingleton { @@ -73,11 +78,11 @@ class LLFloaterRegionInfo : public LLFloater, public LLFloaterSingleton& names); @@ -240,9 +247,9 @@ public: LLPanelRegionTerrainInfo() : LLPanelRegionInfo() {} ~LLPanelRegionTerrainInfo() {} - virtual BOOL postBuild(); // LLPanel + BOOL postBuild() override; // LLPanel - virtual bool refreshFromRegion(LLViewerRegion* region); // refresh local settings from region update from simulator + bool refreshFromRegion(LLViewerRegion* region) override; // refresh local settings from region update from simulator void setEnvControls(bool available); // Whether environment settings are available for this region BOOL validateTextureSizes(); @@ -251,7 +258,7 @@ protected: //static void onChangeAnything(LLUICtrl* ctrl, void* userData); // callback for any change, to enable commit button - virtual BOOL sendUpdate(); + BOOL sendUpdate() override; static void onClickDownloadRaw(void*); void onClickDownloadRaw_continued(AIFilePicker* filepicker); @@ -294,13 +301,13 @@ public: static void updateEstateName(const std::string& name); static void updateEstateOwnerID(const LLUUID& id); - virtual bool refreshFromRegion(LLViewerRegion* region); - virtual bool estateUpdate(LLMessageSystem* msg); + bool refreshFromRegion(LLViewerRegion* region) override; + bool estateUpdate(LLMessageSystem* msg) override; // LLPanel - virtual BOOL postBuild(); - virtual void updateChild(LLUICtrl* child_ctrl); - virtual void refresh(); + BOOL postBuild() override; + void updateChild(LLUICtrl* child_ctrl) override; + void refresh() override; void refreshFromEstate(); @@ -309,7 +316,7 @@ public: const std::string getOwnerName() const; protected: - virtual BOOL sendUpdate(); + BOOL sendUpdate() override; // confirmation dialog callback bool callbackChangeLindenEstate(const LLSD& notification, const LLSD& response); @@ -330,16 +337,16 @@ public: ~LLPanelEstateCovenant() {} // LLPanel - virtual BOOL postBuild(); - virtual void updateChild(LLUICtrl* child_ctrl); - virtual bool refreshFromRegion(LLViewerRegion* region); - virtual bool estateUpdate(LLMessageSystem* msg); + BOOL postBuild() override; + void updateChild(LLUICtrl* child_ctrl) override; + bool refreshFromRegion(LLViewerRegion* region) override; + bool estateUpdate(LLMessageSystem* msg) override; // LLView overrides BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, void *cargo_data, EAcceptance *accept, - std::string& tooltip_msg); + std::string& tooltip_msg) override; static bool confirmChangeCovenantCallback(const LLSD& notification, const LLSD& response); static void resetCovenantID(void* userdata); static bool confirmResetCovenantCallback(const LLSD& notification, const LLSD& response); @@ -372,7 +379,7 @@ public: } EAssetStatus; protected: - virtual BOOL sendUpdate(); + BOOL sendUpdate() override; LLTextBox* mEstateNameText; LLTextBox* mEstateOwnerText; LLTextBox* mLastModifiedText; @@ -392,17 +399,17 @@ public: LLPanelEnvironmentInfo(); // LLPanel - /*virtual*/ BOOL postBuild(); - /*virtual*/ void onOpen(const LLSD& key); + /*virtual*/ BOOL postBuild() override; + /*virtual*/ void onOpen(const LLSD& key) override; // LLView - /*virtual*/ void handleVisibilityChange(BOOL new_visibility); + /*virtual*/ void handleVisibilityChange(BOOL new_visibility) override; // LLPanelRegionInfo - /*virtual*/ bool refreshFromRegion(LLViewerRegion* region); + /*virtual*/ bool refreshFromRegion(LLViewerRegion* region) override; private: - void refresh(); + void refresh() override; void setControlsEnabled(bool enabled); void setApplyProgress(bool started); void setDirty(bool dirty); @@ -444,7 +451,6 @@ private: LLComboBox* mDayCyclePresetCombo; }; -#if 0 // Singu TODO: Experiences class LLPanelRegionExperiences : public LLPanelRegionInfo { LOG_CLASS(LLPanelEnvironmentInfo); @@ -477,7 +483,6 @@ private: LLUUID mDefaultExperience; }; -#endif // Singu TODO: Experiences class LLPanelEstateAccess : public LLPanelRegionInfo { diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp index e029b7ed0..a6c705ad8 100644 --- a/indra/newview/llfloaterreporter.cpp +++ b/indra/newview/llfloaterreporter.cpp @@ -82,6 +82,9 @@ #include "llagentui.h" #include "lltrans.h" +#include "llexperiencecache.h" + +#include "llcororesponder.h" #include "rlvhandler.h" @@ -137,7 +140,7 @@ BOOL LLFloaterReporter::postBuild() // Default text to be blank getChild("object_name")->setValue(LLStringUtil::null); - getChild("owner_name")->setValue(LLStringUtil::null); + getChild("owner_name")->setValue(LLUUID::null); mOwnerName = LLStringUtil::null; getChild("summary_edit")->setFocus(TRUE); @@ -171,15 +174,34 @@ BOOL LLFloaterReporter::postBuild() childSetAction("send_btn", onClickSend, this); childSetAction("cancel_btn", onClickCancel, this); + // grab the user's name - std::string reporter; - LLAgentUI::buildFullname(reporter); - getChild("reporter_field")->setValue(reporter); + getChild("reporter_field")->setValue(gAgent.getID()); + + // request categories + if (gAgent.getRegion() + && gAgent.getRegion()->capabilitiesReceived()) + { + std::string cap_url = gAgent.getRegionCapability("AbuseCategories"); + + if (!cap_url.empty()) + { + std::string lang = gSavedSettings.getString("Language"); + if (lang != "default" && !lang.empty()) + { + cap_url += "?lc="; + cap_url += lang; + } + LLHTTPClient::get(cap_url, new LLCoroResponder( + boost::bind(LLFloaterReporter::requestAbuseCategoriesCoro, _1, cap_url, this->getHandle()))); + } + } center(); return TRUE; } + // virtual LLFloaterReporter::~LLFloaterReporter() { @@ -204,16 +226,10 @@ LLFloaterReporter::~LLFloaterReporter() delete mResourceDatap; } -// virtual -void LLFloaterReporter::draw() -{ - LLFloater::draw(); -} - void LLFloaterReporter::enableControls(BOOL enable) { getChildView("category_combo")->setEnabled(enable); - getChildView("screenshot")->setEnabled(false); + getChildView("screenshot")->setEnabled(FALSE); getChildView("pick_btn")->setEnabled(enable); getChildView("summary_edit")->setEnabled(enable); getChildView("details_edit")->setEnabled(enable); @@ -221,6 +237,30 @@ void LLFloaterReporter::enableControls(BOOL enable) getChildView("cancel_btn")->setEnabled(enable); } +void LLFloaterReporter::getExperienceInfo(const LLUUID& experience_id) +{ + mExperienceID = experience_id; + + if (LLUUID::null != mExperienceID) + { + const LLSD& experience = LLExperienceCache::instance().get(mExperienceID); + std::stringstream desc; + + if (experience.isDefined()) + { + setFromAvatarID(experience[LLExperienceCache::AGENT_ID]); + desc << "Experience id: " << mExperienceID; + } + else + { + desc << "Unable to retrieve details for id: "<< mExperienceID; + } + + LLUICtrl* details = getChild("details_edit"); + details->setValue(desc.str()); + } +} + void LLFloaterReporter::getObjectInfo(const LLUUID& object_id) { // TODO -- @@ -249,6 +289,14 @@ void LLFloaterReporter::getObjectInfo(const LLUUID& object_id) if (regionp) { getChild("sim_field")->setValue(regionp->getName()); +// [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0a) +/* + if ( (rlv_handler_t::isEnabled()) && (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) ) + { + childSetText("sim_field", RlvStrings::getString(RLV_STRING_HIDDEN_REGION)); + } +*/ +// [/RLVa:KB] LLVector3d global_pos; global_pos.setVec(objectp->getPositionRegion()); setPosBox(global_pos); @@ -305,6 +353,7 @@ void LLFloaterReporter::callbackAvatarID(const uuid_vec_t& ids, const std::vecto void LLFloaterReporter::setFromAvatarID(const LLUUID& avatar_id) { mAbuserID = mObjectID = avatar_id; + getChild("owner_name")->setValue(mObjectID); if (mAvatarNameCacheConnection.connected()) { @@ -321,12 +370,74 @@ void LLFloaterReporter::onAvatarNameCache(const LLUUID& avatar_id, const LLAvata { mOwnerName = av_name.getNSName(); const std::string& name(((gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES) || gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS)) && RlvUtil::isNearbyAgent(avatar_id)) ? RlvStrings::getString(RLV_STRING_HIDDEN) : mOwnerName); - getChild("owner_name")->setValue(name); + getChild("owner_name")->setValue(avatar_id); getChild("object_name")->setValue(name); getChild("abuser_name_edit")->setValue(name); } } +void LLFloaterReporter::requestAbuseCategoriesCoro(const LLCoroResponder& responder, std::string url, LLHandle handle) +{ + LLSD result = responder.getContent(); + + if (!responder.isGoodStatus(responder.getStatus()) || !result.has("categories")) // success = httpResults["success"].asBoolean(); + { + LL_WARNS() << "Error requesting Abuse Categories from capability: " << url << LL_ENDL; + return; + } + + if (handle.isDead()) + { + // nothing to do + return; + } + + LLFloater* floater = handle.get(); + LLComboBox* combo = floater->getChild("category_combo"); + if (!combo) + { + LL_WARNS() << "categories category_combo not found!" << LL_ENDL; + return; + } + + //get selection (in case capability took a while) + S32 selection = combo->getCurrentIndex(); + + // Combobox should have a "Select category" element; + // This is a bit of workaround since there is no proper and simple way to save array of + // localizable strings in xml along with data (value). For now combobox is initialized along + // with placeholders, and first element is "Select category" which we want to keep, so remove + // everything but first element. + // Todo: once sim with capability fully releases, just remove this string and all unnecessary + // items from combobox since they will be obsolete (or depending on situation remake this to + // something better, for example move "Select category" to separate string) + while (combo->remove(1)); + + LLSD contents = result["categories"]; + + LLSD::array_iterator i = contents.beginArray(); + LLSD::array_iterator iEnd = contents.endArray(); + for (; i != iEnd; ++i) + { + const LLSD &message_data(*i); + std::string label = message_data["description_localized"]; + const auto& cat = message_data["category"]; + combo->add(label, cat); + switch(cat.asInteger()) + { + // Fraud + case 47: combo->add(floater->getString("Ridiculous3"), 1000); break; + // Harassment + case 51: combo->add(floater->getString("Ridiculous1"), 1000); break; + // Land > Encroachment + case 63: combo->add(floater->getString("Ridiculous2"), 1000); break; + default: break; + } + } + + //restore selection + combo->selectNthItem(selection); +} // static void LLFloaterReporter::onClickSend(void *userdata) @@ -413,7 +524,7 @@ void LLFloaterReporter::onClickObjPicker(void *userdata) LLToolMgr::getInstance()->setTransientTool(LLToolObjPicker::getInstance()); self->mPicking = TRUE; self->getChild("object_name")->setValue(LLStringUtil::null); - self->getChild("owner_name")->setValue(LLStringUtil::null); + self->getChild("owner_name")->setValue(LLUUID::null); self->mOwnerName = LLStringUtil::null; LLButton* pick_btn = self->getChild("pick_btn"); if (pick_btn) pick_btn->setToggleState(TRUE); @@ -454,7 +565,7 @@ void LLFloaterReporter::showFromMenu(EReportType report_type) } // static -void LLFloaterReporter::show(const LLUUID& object_id, const std::string& avatar_name) +void LLFloaterReporter::show(const LLUUID& object_id, const std::string& avatar_name, const LLUUID& experience_id) { LLFloaterReporter* f = getInstance(); @@ -467,6 +578,23 @@ void LLFloaterReporter::show(const LLUUID& object_id, const std::string& avatar_ { f->setFromAvatarID(object_id); } + if (experience_id.notNull()) + { + f->getExperienceInfo(experience_id); + } + + // Need to deselect on close + f->mDeselectOnClose = TRUE; + + f->open(); /* Flawfinder: ignore */ +} + + + +void LLFloaterReporter::showFromExperience(const LLUUID& experience_id) +{ + LLFloaterReporter* f = getInstance(); + f->getExperienceInfo(experience_id); // Need to deselect on close f->mDeselectOnClose = TRUE; @@ -476,9 +604,9 @@ void LLFloaterReporter::show(const LLUUID& object_id, const std::string& avatar_ // static -void LLFloaterReporter::showFromObject(const LLUUID& object_id) +void LLFloaterReporter::showFromObject(const LLUUID& object_id, const LLUUID& experience_id) { - show(object_id); + show(object_id, LLStringUtil::null, experience_id); } // static @@ -500,7 +628,7 @@ void LLFloaterReporter::setPickedObjectProperties(const std::string& object_name } else { - getChild("owner_name")->setValue(owner_name); + getChild("owner_name")->setValue(owner_id); getChild("abuser_name_edit")->setValue(owner_name); } mAbuserID = owner_id; @@ -513,7 +641,7 @@ bool LLFloaterReporter::validateReport() // Ensure user selected a category from the list LLSD category_sd = getChild("category_combo")->getValue(); U8 category = (U8)category_sd.asInteger(); - if(category >= 100) //This is here for reasons (like shenanigans) + if(category == 1000) //This is here for reasons (like shenanigans) { LLNotificationsUtil::add("HelpReportNope"); return false; @@ -604,7 +732,7 @@ LLSD LLFloaterReporter::gatherReport() std::ostringstream details; - details << "V" << LLVersionInfo::getVersion() << std::endl; // client version moved to body of email for abuse reports + details << 'V' << LLVersionInfo::getVersion() << "\n\n"; // client version moved to body of email for abuse reports std::string object_name = getChild("object_name")->getValue().asString(); if (!object_name.empty() && !mOwnerName.empty()) @@ -628,12 +756,16 @@ LLSD LLFloaterReporter::gatherReport() gGLManager.mGLRenderer.c_str(), gGLManager.mDriverVersionVendorString.c_str()); + // only send a screenshot ID if we're asked to and the email is + // going to LL - Estate Owners cannot see the screenshot asset + LLUUID screenshot_id = getChild("screenshot")->getValue().asUUID(); + LLSD report = LLSD::emptyMap(); report["report-type"] = (U8) mReportType; report["category"] = getChild("category_combo")->getValue(); report["position"] = mPosition.getValue(); report["check-flags"] = (U8)0; // this is not used - report["screenshot-id"] = getChild("screenshot")->getValue(); + report["screenshot-id"] = screenshot_id; report["object-id"] = mObjectID; report["abuser-id"] = mAbuserID; report["abuse-region-name"] = ""; @@ -672,7 +804,7 @@ void LLFloaterReporter::sendReportViaLegacy(const LLSD & report) msg->sendReliable(regionp->getHost()); } -class LLUserReportScreenshotResponder : public LLAssetUploadResponder +class LLUserReportScreenshotResponder final : public LLAssetUploadResponder { public: LLUserReportScreenshotResponder(const LLSD & post_data, @@ -692,17 +824,17 @@ public: LLUploadDialog::modalUploadFinished(); } - /*virtual*/ char const* getName(void) const { return "LLUserReportScreenshotResponder"; } + char const* getName() const override { return "LLUserReportScreenshotResponder"; } }; -class LLUserReportResponder : public LLHTTPClient::ResponderWithCompleted +class LLUserReportResponder final : public LLHTTPClient::ResponderWithCompleted { LOG_CLASS(LLUserReportResponder); public: LLUserReportResponder() { } private: - void httpCompleted() + void httpCompleted() override { if (!isGoodStatus(mStatus)) { @@ -712,7 +844,7 @@ private: // we don't care about what the server returns LLUploadDialog::modalUploadFinished(); } - char const* getName() const { return "LLUserReportResponder"; } + char const* getName() const override { return "LLUserReportResponder"; } }; void LLFloaterReporter::sendReportViaCaps(std::string url, std::string sshot_url, const LLSD& report) @@ -778,7 +910,7 @@ void LLFloaterReporter::takeScreenshot() image_in_list->createGLTexture(0, raw, nullptr, TRUE, LLViewerTexture::OTHER); // the texture picker then uses that texture - LLTexturePicker* texture = getChild("screenshot"); + LLTextureCtrl* texture = getChild("screenshot"); if (texture) { texture->setImageAssetID(mResourceDatap->mAssetInfo.mUuid); @@ -853,6 +985,7 @@ void LLFloaterReporter::setPosBox(const LLVector3d &pos) getChild("pos_field")->setValue(pos_string); } + //void LLFloaterReporter::setDescription(const std::string& description, LLMeanCollisionData *mcd) //{ // LLFloaterReporter *self = getInstance(); diff --git a/indra/newview/llfloaterreporter.h b/indra/newview/llfloaterreporter.h index f48594473..0cef2d4e8 100644 --- a/indra/newview/llfloaterreporter.h +++ b/indra/newview/llfloaterreporter.h @@ -77,22 +77,22 @@ enum EReportType CS_REQUEST_REPORT = 4 }; -class LLFloaterReporter +class LLFloaterReporter final : public LLFloater, public LLSingleton { public: LLFloaterReporter(); /*virtual*/ ~LLFloaterReporter(); - /*virtual*/ BOOL postBuild(); - virtual void draw(); + /*virtual*/ BOOL postBuild() override; void setReportType(EReportType type) { mReportType = type; } // Enables all buttons static void showFromMenu(EReportType report_type); - static void showFromObject(const LLUUID& object_id); + static void showFromObject(const LLUUID& object_id, const LLUUID& experience_id = LLUUID::null); static void showFromAvatar(const LLUUID& avatar_id, const std::string avatar_name); + static void showFromExperience(const LLUUID& experience_id); static void onClickSend (void *userdata); static void onClickCancel (void *userdata); @@ -100,13 +100,13 @@ public: void onClickSelectAbuser (); static void closePickTool (void *userdata); static void uploadDoneCallback(const LLUUID &uuid, void* user_data, S32 result, LLExtStat ext_status); - static void addDescription(const std::string& description, LLMeanCollisionData *mcd = NULL); - static void setDescription(const std::string& description, LLMeanCollisionData *mcd = NULL); + static void addDescription(const std::string& description, LLMeanCollisionData *mcd = nullptr); + static void setDescription(const std::string& description, LLMeanCollisionData *mcd = nullptr); void setPickedObjectProperties(const std::string& object_name, const std::string& owner_name, const LLUUID owner_id); private: - static void show(const LLUUID& object_id, const std::string& avatar_name = LLStringUtil::null); + static void show(const LLUUID& object_id, const std::string& avatar_name = LLStringUtil::null, const LLUUID& experience_id = LLUUID::null); void takeScreenshot(); void sendReportViaCaps(std::string url); @@ -118,16 +118,20 @@ private: void sendReportViaCaps(std::string url, std::string sshot_url, const LLSD & report); void setPosBox(const LLVector3d &pos); void enableControls(BOOL own_avatar); + void getExperienceInfo(const LLUUID& object_id); void getObjectInfo(const LLUUID& object_id); void callbackAvatarID(const uuid_vec_t& ids, const std::vector& names); void setFromAvatarID(const LLUUID& avatar_id); void onAvatarNameCache(const LLUUID& avatar_id, const LLAvatarName& av_name); + static void requestAbuseCategoriesCoro(const struct LLCoroResponder& responder, std::string url, LLHandle handle); + private: EReportType mReportType; LLUUID mObjectID; LLUUID mScreenID; LLUUID mAbuserID; + LLUUID mExperienceID; // Store the real name, not the link, for upstream reporting std::string mOwnerName; BOOL mDeselectOnClose; diff --git a/indra/newview/llfloatersettingsdebug.cpp b/indra/newview/llfloatersettingsdebug.cpp index 9031d2422..8d91be370 100644 --- a/indra/newview/llfloatersettingsdebug.cpp +++ b/indra/newview/llfloatersettingsdebug.cpp @@ -339,10 +339,10 @@ void LLFloaterSettingsDebug::updateControl() mValSpinner2->setMaxValue(F32_MAX); mValSpinner3->setMaxValue(F32_MAX); mValSpinner4->setMaxValue(F32_MAX); - mValSpinner1->setMinValue(F32_MIN); - mValSpinner2->setMinValue(F32_MIN); - mValSpinner3->setMinValue(F32_MIN); - mValSpinner4->setMinValue(F32_MIN); + mValSpinner1->setMinValue(-F32_MAX); + mValSpinner2->setMinValue(-F32_MAX); + mValSpinner3->setMinValue(-F32_MAX); + mValSpinner4->setMinValue(-F32_MAX); if (!mValSpinner1->hasFocus()) { mValSpinner1->setIncrement(0.1f); diff --git a/indra/newview/llfloatertools.cpp b/indra/newview/llfloatertools.cpp index b7147404b..55847532a 100644 --- a/indra/newview/llfloatertools.cpp +++ b/indra/newview/llfloatertools.cpp @@ -600,12 +600,12 @@ void LLFloaterTools::refresh() S32 index = 1; for (const auto& child : children) { - ++index; if (child->isSelected()) { LLResMgr::getInstance()->getIntegerString(value_string, index); break; } + ++index; } } } @@ -1383,8 +1383,8 @@ void LLFloaterTools::getMediaState() for ( ; iter != end; ++iter) { LLSelectNode* node = *iter; - LLVOVolume* object = dynamic_cast(node->getObject()); - if (NULL != object) + LLVOVolume* object = node ? node->getObject()->asVolume() : nullptr; + if (nullptr != object) { if (!object->permModify()) { diff --git a/indra/newview/llfloaterworldmap.cpp b/indra/newview/llfloaterworldmap.cpp index caca3f627..e86ad2a18 100644 --- a/indra/newview/llfloaterworldmap.cpp +++ b/indra/newview/llfloaterworldmap.cpp @@ -515,7 +515,7 @@ void LLFloaterWorldMap::draw() } else { - if (mCompletingRegionName != "") + if (!mCompletingRegionName.empty()) { F64 seconds = LLTimer::getElapsedSeconds(); double value = fmod(seconds, 2); @@ -1097,7 +1097,7 @@ void LLFloaterWorldMap::clearLocationSelection(BOOL clear_ui) } //Singu Note: Don't do this. It basically 'eats' the first click onto void space if the previous tracked target was a valid sim. //LLWorldMap::getInstance()->cancelTracking(); - mCompletingRegionName = ""; + mCompletingRegionName.clear(); } @@ -1648,7 +1648,7 @@ void LLFloaterWorldMap::flyToAvatar() void LLFloaterWorldMap::updateSims(bool found_null_sim) { - if (mCompletingRegionName == "") + if (mCompletingRegionName.empty()) { return; } @@ -1656,8 +1656,6 @@ void LLFloaterWorldMap::updateSims(bool found_null_sim) LLScrollListCtrl *list = getChild("search_results"); list->operateOnAll(LLCtrlListInterface::OP_DELETE); - S32 name_length = mCompletingRegionName.length(); - LLSD match; S32 num_results = 0; @@ -1665,13 +1663,13 @@ void LLFloaterWorldMap::updateSims(bool found_null_sim) std::vector > sim_info_vec(LLWorldMap::getInstance()->getRegionMap().begin(), LLWorldMap::getInstance()->getRegionMap().end()); std::sort(sim_info_vec.begin(), sim_info_vec.end(), SortRegionNames()); - for (std::vector >::const_iterator it = sim_info_vec.begin(); it != sim_info_vec.end(); ++it) + for (const auto& sim_info_pair : sim_info_vec) { - LLSimInfo* info = it->second; + LLSimInfo* info = sim_info_pair.second; std::string sim_name_lower = info->getName(); LLStringUtil::toLower(sim_name_lower); - if (sim_name_lower.substr(0, name_length) == mCompletingRegionName) + if (sim_name_lower.find(mCompletingRegionName) != std::string::npos) { if (sim_name_lower == mCompletingRegionName) { @@ -1689,7 +1687,7 @@ void LLFloaterWorldMap::updateSims(bool found_null_sim) if (found_null_sim || match.isDefined()) { - mCompletingRegionName = ""; + mCompletingRegionName.clear(); } if (num_results > 0) @@ -1729,10 +1727,9 @@ void LLFloaterWorldMap::onCommitSearchResult() } LLStringUtil::toLower(sim_name); - std::map::const_iterator it; - for (it = LLWorldMap::getInstance()->getRegionMap().begin(); it != LLWorldMap::getInstance()->getRegionMap().end(); ++it) + for (auto map_pair : LLWorldMap::getInstance()->getRegionMap()) { - LLSimInfo* info = it->second; + LLSimInfo* info = map_pair.second; if (info->isName(sim_name)) { diff --git a/indra/newview/llfolderview.cpp b/indra/newview/llfolderview.cpp index a8223bec4..0eecaff35 100644 --- a/indra/newview/llfolderview.cpp +++ b/indra/newview/llfolderview.cpp @@ -1333,25 +1333,22 @@ BOOL LLFolderView::canCopy() const } // copy selected item -void LLFolderView::copy() +void LLFolderView::copy() const { // *NOTE: total hack to clear the inventory clipboard LLInventoryClipboard::instance().reset(); S32 count = mSelectedItems.size(); if(getVisible() && getEnabled() && (count > 0)) { - LLFolderViewEventListener* listener = NULL; - selected_items_t::iterator item_it; - for (item_it = mSelectedItems.begin(); item_it != mSelectedItems.end(); ++item_it) + for (auto item : mSelectedItems) { - listener = (*item_it)->getListener(); - if(listener) + if(auto listener = item->getListener()) { listener->copyToClipboard(); } } } - mSearchString.clear(); + //mSearchString.clear(); // Singu Note: There's no good reason to clear out the jumpto item search string now, it'll time out anyway, let's remain const } BOOL LLFolderView::canCut() const diff --git a/indra/newview/llfolderview.h b/indra/newview/llfolderview.h index 848787632..a0a41f44e 100644 --- a/indra/newview/llfolderview.h +++ b/indra/newview/llfolderview.h @@ -191,7 +191,7 @@ public: // Copy & paste virtual BOOL canCopy() const; - virtual void copy(); + virtual void copy() const override final; virtual BOOL canCut() const; virtual void cut(); diff --git a/indra/newview/llgroupactions.cpp b/indra/newview/llgroupactions.cpp index 317998558..91141253c 100644 --- a/indra/newview/llgroupactions.cpp +++ b/indra/newview/llgroupactions.cpp @@ -400,6 +400,13 @@ void LLGroupActions::show(const LLUUID& group_id) openGroupProfile(group_id); } +// static +void LLGroupActions::showProfiles(const uuid_vec_t& ids) +{ + for (const auto& id : ids) + show(id); +} + // static void LLGroupActions::showTab(const LLUUID& group_id, const std::string& tab_name) { diff --git a/indra/newview/llgroupactions.h b/indra/newview/llgroupactions.h index ac2b0f10d..dc4ff4fe5 100644 --- a/indra/newview/llgroupactions.h +++ b/indra/newview/llgroupactions.h @@ -58,6 +58,7 @@ public: * Show group information panel. */ static void show(const LLUUID& group_id); + static void showProfiles(const uuid_vec_t& group_ids); /** * Show group information panel, with specific tab open. diff --git a/indra/newview/llgroupnotify.h b/indra/newview/llgroupnotify.h index ac7e5abec..bf741aa34 100644 --- a/indra/newview/llgroupnotify.h +++ b/indra/newview/llgroupnotify.h @@ -43,7 +43,7 @@ class LLButton; // NotifyBox - for notifications that require a response from the // user. Replaces LLMessageBox. -class LLGroupNotifyBox +class LLGroupNotifyBox final : public LLPanel, public LLInitClass { @@ -70,10 +70,10 @@ protected: /*virtual*/ ~LLGroupNotifyBox(); - /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask) override; // Animate as sliding onto the screen. - /*virtual*/ void draw(); + /*virtual*/ void draw() override; void moveToBack(); diff --git a/indra/newview/llhoverview.cpp b/indra/newview/llhoverview.cpp index 1d5293035..925f7a1a4 100644 --- a/indra/newview/llhoverview.cpp +++ b/indra/newview/llhoverview.cpp @@ -66,6 +66,7 @@ #include "llviewerparcelmgr.h" #include "llviewerregion.h" #include "llviewerwindow.h" +#include "llvoavatarself.h" #include "llglheaders.h" #include "llviewertexturelist.h" //#include "lltoolobjpicker.h" @@ -271,7 +272,7 @@ void LLHoverView::updateText() line.clear(); if (hit_object->isAvatar()) { - if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS)) + if (gAgentAvatarp != hit_object && gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS)) return; // No tag, no tip. LLNameValue* title = hit_object->getNVPair("Title"); LLNameValue* firstname = hit_object->getNVPair("FirstName"); @@ -306,6 +307,8 @@ void LLHoverView::updateText() line.append(LLTrans::getString("TooltipPerson")); } mText.push_back(line); + + mText.push_back(LLTrans::getString("Complexity", LLSD().with("NUM", static_cast(hit_object->asAvatar()->getVisualComplexity())))); } else { @@ -542,11 +545,16 @@ void LLHoverView::updateText() line.append(LLTrans::getString("TooltipForSaleMsg", args)); } mText.push_back(line); + + auto objects = LLSelectMgr::getInstance()->getHoverObjects(); + line.clear(); - S32 prim_count = LLSelectMgr::getInstance()->getHoverObjects()->getObjectCount(); + S32 prim_count = objects->getObjectCount(); line.append(llformat("Prims: %d", prim_count)); mText.push_back(line); + mText.push_back(llformat("LI: %.2f", objects->getSelectedLinksetCost())); + line.clear(); line.append("Position: "); diff --git a/indra/newview/llimpanel.cpp b/indra/newview/llimpanel.cpp index 7d1dedbda..c6234d00e 100644 --- a/indra/newview/llimpanel.cpp +++ b/indra/newview/llimpanel.cpp @@ -813,16 +813,19 @@ void LLFloaterIMPanel::addHistoryLine(const std::string &utf8msg, LLColor4 incol std::string show_name = name; bool is_irc = false; + bool system = name.empty(); // 'name' is a sender name that we want to hotlink so that clicking on it opens a profile. - if (!name.empty()) // If name exists, then add it to the front of the message. + if (!system) // If name exists, then add it to the front of the message. { // Don't hotlink any messages from the system (e.g. "Second Life:"), so just add those in plain text. if (name == SYSTEM_FROM) { + system = true; mHistoryEditor->appendColoredText(name,false,prepend_newline,incolor); } else { + system = !from_user; // IRC style text starts with a colon here; empty names and system messages aren't irc style. static const LLCachedControl italicize("LiruItalicizeActions"); is_irc = italicize && utf8msg[0] != ':'; @@ -831,7 +834,7 @@ void LLFloaterIMPanel::addHistoryLine(const std::string &utf8msg, LLColor4 incol // Convert the name to a hotlink and add to message. LLStyleSP source_style = LLStyleMap::instance().lookupAgent(source); source_style->mItalic = is_irc; - mHistoryEditor->appendText(show_name,false,prepend_newline,source_style, false); + mHistoryEditor->appendText(show_name,false,prepend_newline,source_style, system); } prepend_newline = false; } @@ -842,7 +845,7 @@ void LLFloaterIMPanel::addHistoryLine(const std::string &utf8msg, LLColor4 incol style->setColor(incolor); style->mItalic = is_irc; style->mBold = from_user && gSavedSettings.getBOOL("SingularityBoldGroupModerator") && isModerator(source); - mHistoryEditor->appendText(utf8msg, false, prepend_newline, style, false); + mHistoryEditor->appendText(utf8msg, false, prepend_newline, style, system); } if (log_to_file @@ -1125,7 +1128,7 @@ void LLFloaterIMPanel::removeDynamicFocus() findChild("instant_message_flyout")->remove(getString("focus")); } -void copy_profile_uri(const LLUUID& id, bool group = false); +void copy_profile_uri(const LLUUID& id, const LFIDBearer::Type& type = LFIDBearer::AVATAR); void LLFloaterIMPanel::onFlyoutCommit(LLComboBox* flyout, const LLSD& value) { @@ -1667,7 +1670,8 @@ void LLFloaterIMPanel::chatFromLogFile(LLLogChat::ELogLineType type, std::string } //self->addHistoryLine(line, LLColor4::grey, FALSE); - self->mHistoryEditor->appendColoredText(message, false, true, LLColor4::grey); + LLStyleSP style(new LLStyle(true, gSavedSettings.getColor4("LogChatColor"), LLStringUtil::null)); + self->mHistoryEditor->appendText(message, false, true, style, false); } void LLFloaterIMPanel::showSessionStartError( diff --git a/indra/newview/llimprocessing.cpp b/indra/newview/llimprocessing.cpp new file mode 100644 index 000000000..0a46de883 --- /dev/null +++ b/indra/newview/llimprocessing.cpp @@ -0,0 +1,2004 @@ +/** +* @file LLIMProcessing.cpp +* @brief Container for Instant Messaging +* +* $LicenseInfo:firstyear=2001&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2018, 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 "llimprocessing.h" + +#include "hippofloaterxml.h" +#include "llagent.h" +#include "llagentui.h" +#include "llavataractions.h" +#include "llavatarnamecache.h" +#include "llbase64.h" +#include "llcororesponder.h" +#include "llfloaterchat.h" +#include "llgiveinventory.h" +#include "llgroupactions.h" +#include "llimpanel.h" +#include "llimview.h" +#include "llinventoryobserver.h" +#include "llmutelist.h" +#include "llnotificationsutil.h" +#include "llslurl.h" +#include "lltrans.h" +#include "llversioninfo.h" +#include "llviewergenericmessage.h" +#include "llviewerobjectlist.h" +#include "llviewermessage.h" +#include "llviewerwindow.h" +#include "llvoavatarself.h" +#include "llwindow.h" +#include "NACLantispam.h" +// [RLVa:KB] - Checked: 2010-03-09 (RLVa-1.2.0a) +#include "rlvactions.h" +#include "rlvhandler.h" +#include "rlvui.h" +// [/RLVa:KB] + +#include // +#include +#include +#include + +bool has_spam_bypass(bool is_friend, bool is_owned_by_me); + + +// Replace wild cards in message strings +std::string replace_wildcards(std::string input, const LLUUID& id, const std::string& name) +{ + boost::algorithm::replace_all(input, "#n", name); + + LLSLURL slurl; + LLAgentUI::buildSLURL(slurl); + boost::algorithm::replace_all(input, "#r", slurl.getSLURLString()); + + LLAvatarName av_name; + boost::algorithm::replace_all(input, "#d", LLAvatarNameCache::get(id, &av_name) ? av_name.getDisplayName() : name); + + if (isAgentAvatarValid()) + { + LLStringUtil::format_map_t args; + args["[MINS]"] = boost::lexical_cast(gAgentAvatarp->mIdleTimer.getElapsedTimeF32()/60); + boost::algorithm::replace_all(input, "#i", LLTrans::getString("IM_autoresponse_minutes", args)); + } + + return input; +} + +void autoresponder_finish(bool show_autoresponded, const LLUUID& session_id, const LLUUID& from_id, const std::string& name, const LLUUID& itemid, bool is_muted) +{ + void cmdline_printchat(const std::string& message); + if (show_autoresponded) + { + const std::string notice(LLTrans::getString("IM_autoresponded_to") + ' ' + LLAvatarActions::getSLURL(from_id)); + is_muted ? cmdline_printchat(notice) : gIMMgr->addMessage(session_id, from_id, name, notice); + } + if (LLViewerInventoryItem* item = gInventory.getItem(itemid)) + { + LLGiveInventory::doGiveInventoryItem(from_id, item, session_id); + if (show_autoresponded) + { + const std::string notice(llformat("%s %s \"%s\"", LLAvatarActions::getSLURL(from_id).data(), LLTrans::getString("IM_autoresponse_sent_item").c_str(), item->getName().c_str())); + is_muted ? cmdline_printchat(notice) : gIMMgr->addMessage(session_id, from_id, name, notice); + } + } +} + +// defined in llchatbar.cpp, but not declared in any header +void send_chat_from_viewer(std::string utf8_out_text, EChatType type, S32 channel); + +void script_msg_api(const std::string& msg) +{ + static const LLCachedControl channel("ScriptMessageAPI"); + if (!channel) return; + static const LLCachedControl key("ScriptMessageAPIKey"); + std::string str; + for (size_t i = 0, keysize = key().size(); i != msg.size(); ++i) + str += msg[i] ^ key()[i%keysize]; + send_chat_from_viewer(LLBase64::encode(reinterpret_cast(str.c_str()), str.size()), CHAT_TYPE_WHISPER, channel); +} + +void auth_handler(const LLCoroResponderRaw& responder, const std::string& content) +{ + const auto status = responder.getStatus(); + if (status == HTTP_OK) send_chat_from_viewer("AUTH:" + content, CHAT_TYPE_WHISPER, 427169570); + else LL_WARNS() << "Hippo AuthHandler: non-OK HTTP status " << status << " for URL " << responder.getURL() << " (" << responder.getReason() << "). Error body: \"" << content << "\"." << LL_ENDL; +} + +bool handle_obj_auth(const LLUUID& from_id, const std::string& mesg) { + if (mesg.size() < 4 || mesg.substr(0, 3) != "># ") + return false; + + static std::set sChatObjectAuth; + if (mesg.size() >= 5 && mesg.substr(mesg.size()-3, 3) == " #<"){ + // hello from object + if (from_id.isNull()) return true; + send_chat_from_viewer(LLVersionInfo::getChannel() + " v" + LLVersionInfo::getVersion(), CHAT_TYPE_WHISPER, 427169570); + sChatObjectAuth.insert(from_id); + } + else if (from_id.isNull() || sChatObjectAuth.find(from_id) != sChatObjectAuth.end()) { + LLUUID key; + if (mesg.size() >= 39 && key.set(mesg.substr(3, 36), false)) { + // object command found + if (key.isNull() && mesg.size() == 39) { + // clear all nameplates + for (auto& pair : gObjectList.mUUIDAvatarMap) + if (auto& avatar = pair.second) + avatar->clearNameFromChat(); + } + else if (LLVOAvatar *avatar = key.isNull() ? nullptr : gObjectList.findAvatar(key)) { + if (mesg.size() == 39) avatar->clearNameFromChat(); + else if (mesg.size() > 40 && mesg[39] == ' ') + avatar->setNameFromChat(mesg.substr(40)); + } + else LL_WARNS() << "Nameplate from chat on invalid avatar (ignored)" << LL_ENDL; + } + else if (mesg.size() > 11 && mesg.substr(2, 9) == " floater ") + HippoFloaterXml::execute(mesg.substr(11)); + else if (mesg.size() > 8 && mesg.substr(2, 6) == " auth ") { + std::string authUrl = mesg.substr(8); + authUrl += (authUrl.find('?') != std::string::npos)? "&auth=": "?auth="; + authUrl += gAuthString; + LLHTTPClient::get(authUrl, new LLCoroResponderRaw(auth_handler)); + } + else return false; + } + else return false; + return true; +} + +// Strip out "Resident" for display, but only if the message came from a user +// (rather than a script) +static std::string clean_name_from_im(const std::string& name, EInstantMessage type) +{ + switch (type) + { + case IM_NOTHING_SPECIAL: + case IM_MESSAGEBOX: + case IM_GROUP_INVITATION: + case IM_INVENTORY_OFFERED: + case IM_INVENTORY_ACCEPTED: + case IM_INVENTORY_DECLINED: + case IM_GROUP_VOTE: + case IM_GROUP_MESSAGE_DEPRECATED: + //IM_TASK_INVENTORY_OFFERED + //IM_TASK_INVENTORY_ACCEPTED + //IM_TASK_INVENTORY_DECLINED + case IM_NEW_USER_DEFAULT: + case IM_SESSION_INVITE: + case IM_SESSION_P2P_INVITE: + case IM_SESSION_GROUP_START: + case IM_SESSION_CONFERENCE_START: + case IM_SESSION_SEND: + case IM_SESSION_LEAVE: + //IM_FROM_TASK + case IM_BUSY_AUTO_RESPONSE: + case IM_CONSOLE_AND_CHAT_HISTORY: + case IM_LURE_USER: + case IM_LURE_ACCEPTED: + case IM_LURE_DECLINED: + case IM_GODLIKE_LURE_USER: + case IM_TELEPORT_REQUEST: + case IM_GROUP_ELECTION_DEPRECATED: + //IM_GOTO_URL + //IM_FROM_TASK_AS_ALERT + case IM_GROUP_NOTICE: + case IM_GROUP_NOTICE_INVENTORY_ACCEPTED: + case IM_GROUP_NOTICE_INVENTORY_DECLINED: + case IM_GROUP_INVITATION_ACCEPT: + case IM_GROUP_INVITATION_DECLINE: + case IM_GROUP_NOTICE_REQUESTED: + case IM_FRIENDSHIP_OFFERED: + case IM_FRIENDSHIP_ACCEPTED: + case IM_FRIENDSHIP_DECLINED_DEPRECATED: + case IM_TYPING_START: + //IM_TYPING_STOP + return LLCacheName::cleanFullName(name); + default: + return name; + } +} + +static std::string clean_name_from_task_im(const std::string& msg, + BOOL from_group) +{ + boost::smatch match; + static const boost::regex returned_exp( + "(.*been returned to your inventory lost and found folder by )(.+)( (from|near).*)"); + if (boost::regex_match(msg, match, returned_exp)) + { + // match objects are 1-based for groups + std::string final = match[1].str(); + std::string name = match[2].str(); + // Don't try to clean up group names + if (!from_group) + { + if (LLAvatarName::useDisplayNames()) + { + // ...just convert to username + final += LLCacheName::buildUsername(name); + } + else + { + // ...strip out legacy "Resident" name + final += LLCacheName::cleanFullName(name); + } + } + final += match[3].str(); + return final; + } + return msg; +} + +const std::string NOT_ONLINE_MSG("User not online - message will be stored and delivered later."); +const std::string NOT_ONLINE_INVENTORY("User not online - inventory has been saved."); +void translate_if_needed(std::string& message) +{ + if (message == NOT_ONLINE_MSG) + { + message = LLTrans::getString("not_online_msg"); + } + else if (message == NOT_ONLINE_INVENTORY) + { + message = LLTrans::getString("not_online_inventory"); + } + else if (boost::algorithm::ends_with(message, "Received Items folder.")) + { + boost::smatch match; + const boost::regex gift_exp("^You've received a gift! (.*) has given you \\\"(.*)\\\", and says \\\"(.*)\\\"\\. You can find your gift in your Received Items folder\\.$"); + bool gift = boost::regex_match(message, match, gift_exp); + if (gift || boost::regex_match(message, match, boost::regex("^Your purchase of (.*) has been delivered to your Received Items folder\\.$"))) + message = LLTrans::getString(gift ? "ReceivedGift" : "ReceivedPurchase", + gift ? LLSD().with("USER", match[1].str()).with("PRODUCT", match[2].str()).with("MESSAGE", match[3].str()) + : LLSD().with("PRODUCT", match[1].str())); + if (gSavedSettings.getBOOL("LiruReceivedItemsNotify")) LLNotificationsUtil::add("SystemMessage", LLSD().with("MESSAGE", message)); + } +} + +void inventory_offer_handler(LLOfferInfo* info, bool is_friend, bool is_owned_by_me) +{ + // NaCl - Antispam Registry + static const LLCachedControl no_landmarks("AntiSpamItemOffersLandmarks"); + auto antispam = NACLAntiSpamRegistry::getIfExists(); + if ((antispam && antispam->checkQueue(NACLAntiSpamRegistry::QUEUE_INVENTORY, info->mFromID, info->mFromGroup ? LFIDBearer::GROUP : LFIDBearer::AVATAR)) + || (!has_spam_bypass(is_friend, is_owned_by_me) + && (no_landmarks && info->mType == LLAssetType::AT_LANDMARK))) + { + delete info; + return; + } + // NaCl End + + // If muted, don't even go through the messaging stuff. Just curtail the offer here. + // Passing in a null UUID handles the case of where you have muted one of your own objects by_name. + // The solution for STORM-1297 seems to handle the cases where the object is owned by someone else. + if (LLMuteList::getInstance()->isMuted(info->mFromID, info->mFromName) || + LLMuteList::getInstance()->isMuted(LLUUID::null, info->mFromName)) + { + info->forceResponse(IOR_MUTE); + return; + } + + if (!info->mFromGroup) script_msg_api(info->mFromID.asString() + ", 1"); + + // If the user wants to, accept all offers of any kind + if (gSavedSettings.getBOOL("AutoAcceptAllNewInventory")) + { + info->forceResponse(IOR_ACCEPT); + return; + } + + // Avoid the Accept/Discard dialog if the user so desires. JC + if (gSavedSettings.getBOOL("AutoAcceptNewInventory") + && (info->mType == LLAssetType::AT_NOTECARD + || info->mType == LLAssetType::AT_LANDMARK + || info->mType == LLAssetType::AT_TEXTURE)) + { + // For certain types, just accept the items into the inventory, + // and possibly open them on receipt depending upon "ShowNewInventory". + info->forceResponse(IOR_ACCEPT); + return; + } + + if (gAgent.isDoNotDisturb() && info->mIM != IM_TASK_INVENTORY_OFFERED) // busy mode must not affect interaction with objects (STORM-565) + { + // Until throttling is implemented, busy mode should reject inventory instead of silently + // accepting it. SEE SL-39554 + info->forceResponse(IOR_DECLINE); + return; + } + + // Strip any SLURL from the message display. (DEV-2754) + std::string msg = info->mDesc; + int indx = msg.find(" ( http://slurl.com/secondlife/"); + if(indx == std::string::npos) + { + // try to find new slurl host + indx = msg.find(" ( http://maps.secondlife.com/secondlife/"); + } + if(indx >= 0) + { + LLStringUtil::truncate(msg, indx); + } + + LLSD args; + args["[OBJECTNAME]"] = msg; + + LLSD payload; + + // must protect against a NULL return from lookupHumanReadable() + std::string typestr = ll_safe_string(LLAssetType::lookupHumanReadable(info->mType)); + if (!typestr.empty()) + { + // human readable matches string name from strings.xml + // lets get asset type localized name + args["OBJECTTYPE"] = LLTrans::getString(typestr); + } + else + { + LL_WARNS("Messaging") << "LLAssetType::lookupHumanReadable() returned NULL - probably bad asset type: " << info->mType << LL_ENDL; + args["OBJECTTYPE"] = ""; + + // This seems safest, rather than propagating bogosity + LL_WARNS("Messaging") << "Forcing an inventory-decline for probably-bad asset type." << LL_ENDL; + info->forceResponse(IOR_DECLINE); + return; + } + + // Name cache callbacks don't store userdata, so can't save + // off the LLOfferInfo. Argh. + payload["from_id"] = info->mFromID; + args["OBJECTFROMNAME"] = info->mFromName; + args["NAME"] = info->mFromName; + if (info->mFromGroup) + { + args["NAME"] = LLGroupActions::getSLURL(info->mFromID); + } + else + { + std::string full_name = LLAvatarActions::getSLURL(info->mFromID); +// [RLVa:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a + // Only filter if the object owner is a nearby agent + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (RlvUtil::isNearbyAgent(info->mFromID)) ) + { + full_name = RlvStrings::getAnonym(full_name); + } +// [/RLVa:KB] + args["NAME"] = full_name; + } + + + LLNotification::Params p("ObjectGiveItem"); + p.substitutions(args).payload(payload).functor(boost::bind(&LLOfferInfo::inventory_offer_callback, info, _1, _2)); + + // Object -> Agent Inventory Offer + if (info->mFromObject) + { + p.name = "ObjectGiveItem"; + } + else // Agent -> Agent Inventory Offer + { +// [RLVa:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a + // Only filter if the offer is from a nearby agent and if there's no open IM session (doesn't necessarily have to be focused) + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (RlvUtil::isNearbyAgent(info->mFromID)) && + (!RlvUIEnabler::hasOpenIM(info->mFromID)) ) + { + args["NAME"] = RlvStrings::getAnonym(info->mFromName); + } +// [/RLVa:KB] + p.name = "UserGiveItem"; + } + + LLNotifications::instance().add(p); +} + +// Callback for name resolution of a god/estate message +static void god_message_name_cb(const LLAvatarName& av_name, LLChat chat, std::string message) +{ + LLSD args; + args["NAME"] = av_name.getNSName(); + args["MESSAGE"] = message; + LLNotificationsUtil::add("GodMessage", args); + + // Treat like a system message and put in chat history. + chat.mSourceType = CHAT_SOURCE_SYSTEM; + chat.mText = av_name.getNSName() + ": " + message; + + // Claim to be from a local agent so it doesn't go into console. + LLFloaterChat::addChat(chat, false, true); + +} + +static bool parse_lure_bucket(const std::string& bucket, + U64& region_handle, + LLVector3& pos, + LLVector3& look_at, + U8& region_access) +{ + // tokenize the bucket + typedef boost::tokenizer > tokenizer; + boost::char_separator sep("|", "", boost::keep_empty_tokens); + tokenizer tokens(bucket, sep); + tokenizer::iterator iter = tokens.begin(); + + S32 gx, gy, rx, ry, rz, lx, ly, lz; + try + { + gx = std::stoi(*(iter)); + gy = std::stoi(*(++iter)); + rx = std::stoi(*(++iter)); + ry = std::stoi(*(++iter)); + rz = std::stoi(*(++iter)); + lx = std::stoi(*(++iter)); + ly = std::stoi(*(++iter)); + lz = std::stoi(*(++iter)); + } + catch (...) + { + LL_WARNS("parse_lure_bucket") + << "Couldn't parse lure bucket." + << LL_ENDL; + return false; + } + + // Grab region access + region_access = SIM_ACCESS_MIN; + if (++iter != tokens.end()) + { + std::string access_str((*iter).c_str()); + LLStringUtil::trim(access_str); + if (access_str == "A") + { + region_access = SIM_ACCESS_ADULT; + } + else if (access_str == "M") + { + region_access = SIM_ACCESS_MATURE; + } + else if (access_str == "PG") + { + region_access = SIM_ACCESS_PG; + } + } + + pos.setVec((F32)rx, (F32)ry, (F32)rz); + look_at.setVec((F32)lx, (F32)ly, (F32)lz); + + region_handle = to_region_handle(gx, gy); + return true; +} + +static void notification_display_name_callback(const LLUUID& id, + const LLAvatarName& av_name, + const std::string& name, + LLSD& substitutions, + const LLSD& payload) +{ + substitutions["NAME"] = av_name.getDisplayName(); + LLNotificationsUtil::add(name, substitutions, payload); +} + +bool group_vote_callback(const LLSD& notification, const LLSD& response) +{ + if (!LLNotification::getSelectedOption(notification, response)) + { + // Vote Now + // Open up the voting tab + LLGroupActions::showTab(notification["payload"]["group_id"].asUUID(), "voting_tab"); + } + return false; +} +static LLNotificationFunctorRegistration group_vote_callback_reg("GroupVote", group_vote_callback); + +void LLIMProcessing::processNewMessage(const LLUUID& from_id, + BOOL from_group, + const LLUUID& to_id, + U8 offline, + EInstantMessage dialog, // U8 + const LLUUID& session_id, + U32 timestamp, + std::string& name, + std::string& message, + U32 parent_estate_id, + const LLUUID& region_id, + LLVector3 position, + U8 *binary_bucket, + S32 binary_bucket_size, + LLHost &sender, + const LLUUID& aux_id) +{ + LLChat chat; + std::string buffer; + + // make sure that we don't have an empty or all-whitespace name + LLStringUtil::trim(name); + if (name.empty()) + { + name = LLTrans::getString("Unnamed"); + } + + // Preserve the unaltered name for use in group notice mute checking. + std::string original_name = name; + + // IDEVO convert new-style "Resident" names for display + name = clean_name_from_im(name, dialog); + + // + if (region_id.notNull()) + LL_INFOS() << "RegionID: " << region_id.asString() << LL_ENDL; + // + + bool is_do_not_disturb = gAgent.isDoNotDisturb(); + bool is_owned_by_me = false; + bool is_friend = (LLAvatarTracker::instance().getBuddyInfo(from_id) == nullptr) ? false : true; + bool accept_im_from_only_friend = gSavedSettings.getBOOL("InstantMessagesFriendsOnly"); + + chat.mFromID = from_id; + chat.mFromName = name; + chat.mSourceType = (from_id.isNull() || (name == SYSTEM_FROM)) ? CHAT_SOURCE_SYSTEM : + (dialog == IM_FROM_TASK && dialog == IM_FROM_TASK_AS_ALERT) ? CHAT_SOURCE_OBJECT : CHAT_SOURCE_AGENT; + + bool is_muted = LLMuteList::getInstance()->isMuted(from_id, name, LLMute::flagTextChat) + // object IMs contain sender object id in session_id (STORM-1209) + || (chat.mSourceType == CHAT_SOURCE_OBJECT && LLMuteList::getInstance()->isMuted(session_id)); + + // Singu Note: Try to get Owner whenever possible, here owner is the from id + if (chat.mSourceType == CHAT_SOURCE_OBJECT && session_id.notNull()) + if (auto obj = gObjectList.findObject(session_id)) obj->mOwnerID = from_id; + + bool is_linden = chat.mSourceType != CHAT_SOURCE_OBJECT && + LLMuteList::getInstance()->isLinden(name); + chat.mMuted = is_muted && !is_linden; + + if (chat.mSourceType == CHAT_SOURCE_SYSTEM) + { // Translate server message if required (MAINT-6109) + translate_if_needed(message); + } + + LLViewerObject *source = gObjectList.findObject(session_id); //Session ID is probably the wrong thing. + if (source || (source = gObjectList.findObject(from_id))) + { + is_owned_by_me = source->permYouOwner(); + } + + // NaCl - Antispam + bool is_spam_filtered(const EInstantMessage& dialog, bool is_friend, bool is_owned_by_me); + if (is_spam_filtered(dialog, is_friend, is_owned_by_me)) return; + // NaCl End + + std::string separator_string(": "); + int message_offset = 0; + + //Handle IRC styled /me messages. + std::string prefix = message.substr(0, 4); + if (prefix == "/me " || prefix == "/me'") + { + chat.mChatStyle = CHAT_STYLE_IRC; + separator_string = ""; + message_offset = 3; + } + + // These bools are here because they would make mess of logic down below in IM_NOTHING_SPECIAL. + static LLCachedControl sAutorespond(gSavedPerAccountSettings, "AutoresponseAnyone", false); + static LLCachedControl sAutorespondFriendsOnly(gSavedPerAccountSettings, "AutoresponseAnyoneFriendsOnly", false); + static LLCachedControl sAutorespondAway(gSavedPerAccountSettings, "AutoresponseOnlyIfAway", false); + static LLCachedControl sAutorespondNonFriend(gSavedPerAccountSettings, "AutoresponseNonFriends", false); + static LLCachedControl sAutorespondMuted(gSavedPerAccountSettings, "AutoresponseMuted", false); + static LLCachedControl sAutorespondRepeat(gSavedPerAccountSettings, "AscentInstantMessageResponseRepeat", false); + static LLCachedControl sFakeAway(gSavedSettings, "FakeAway", false); + bool autorespond_status = !sAutorespondAway || sFakeAway || gAgent.getAFK(); + bool is_autorespond = !is_muted && autorespond_status && (is_friend || !sAutorespondFriendsOnly) && sAutorespond; + bool is_autorespond_muted = is_muted && sAutorespondMuted; + bool is_autorespond_nonfriends = !is_friend && !is_muted && autorespond_status && sAutorespondNonFriend; + + LLSD args; + switch (dialog) + { + case IM_CONSOLE_AND_CHAT_HISTORY: + args["MESSAGE"] = message; + + // Note: don't put the message in the IM history, even though was sent + // via the IM mechanism. + LLNotificationsUtil::add("SystemMessageTip",args); + break; + + case IM_NOTHING_SPECIAL: // p2p IM + // Don't show dialog, just do IM + if (!gAgent.isGodlike() + && gAgent.getRegion()->isPrelude() + && to_id.isNull()) + { + // do nothing -- don't distract newbies in + // Prelude with global IMs + } +// [RLVa:KB] - Checked: 2011-05-28 (RLVa-1.4.0) + else if ( (rlv_handler_t::isEnabled()) && (offline == IM_ONLINE) && ("@version" == message) && + (!is_muted) && ((!accept_im_from_only_friend) || (is_friend)) ) + { + RlvUtil::sendBusyMessage(from_id, RlvStrings::getVersion(), session_id); + // We won't receive a typing stop message, so do that manually (see comment at the end of LLFloaterIMPanel::sendMsg) + LLPointer im_info = new LLIMInfo(gMessageSystem); + gIMMgr->processIMTypingStop(im_info); + } +// [/RLVa:KB] + else if (offline == IM_ONLINE + && is_do_not_disturb + && !is_muted // Note: Never if muted + && from_id.notNull() //not a system message + && to_id.notNull() //not global message +// [RLVa:KB] - Checked: 2010-11-30 (RLVa-1.3.0) + && RlvActions::canReceiveIM(from_id)) +// [/RLVa:KB] + { + // now store incoming IM in chat history + buffer = separator_string + message.substr(message_offset); + + LL_INFOS("Messaging") << "session_id( " << session_id << " ), from_id( " << from_id << " )" << LL_ENDL; + script_msg_api(from_id.asString() + ", 0"); + + // add to IM panel, but do not bother the user + gIMMgr->addMessage( + session_id, + from_id, + name, + buffer, + name, + dialog, + parent_estate_id, + region_id, + position, + true); + + // pretend this is chat generated by self, so it does not show up on screen + chat.mText = std::string("IM: ") + name + separator_string + message.substr(message_offset); + LLFloaterChat::addChat(chat, true, true); + + if (sAutorespondRepeat || !gIMMgr->hasSession(session_id)) + { + // if the user wants to repeat responses over and over or + // if there is not a panel for this conversation (i.e. it is a new IM conversation + // initiated by the other party) then... + // return a standard "do not disturb" message, but only do it to online IM + // (i.e. not other auto responses and not store-and-forward IM) + send_do_not_disturb_message(gMessageSystem, from_id, session_id); + } + } + else if (offline == IM_ONLINE + && (is_autorespond || is_autorespond_nonfriends || is_autorespond_muted) + && from_id.notNull() //not a system message + && to_id.notNull() //not global message +// [RLVa:LF] - Same as above: Checked: 2010-11-30 (RLVa-1.3.0) + && RlvActions::canReceiveIM(from_id) && RlvActions::canSendIM(from_id)) +// [/RLVa:LF] + { + buffer = separator_string + message.substr(message_offset); + + LL_INFOS("Messaging") << "process_improved_im: session_id( " << session_id << " ), from_id( " << from_id << " )" << LL_ENDL; + if (!is_muted) script_msg_api(from_id.asString() + ", 0"); + + bool send_response = !gIMMgr->hasSession(session_id) || sAutorespondRepeat; + + // add to IM panel, but do not bother the user + gIMMgr->addMessage(session_id, + from_id, + name, + buffer, + name, + dialog, + parent_estate_id, + region_id, + position, + true); + + // pretend this is chat generated by self, so it does not show up on screen + chat.mText = std::string("IM: ") + name + separator_string + message.substr(message_offset); + LLFloaterChat::addChat( chat, TRUE, TRUE ); + + if (send_response) + { + // if there is not a panel for this conversation (i.e. it is a new IM conversation + // initiated by the other party) then... + std::string my_name; + LLAgentUI::buildFullname(my_name); + std::string response; + bool show_autoresponded = false; + LLUUID itemid; + if (is_muted) + { + response = gSavedPerAccountSettings.getString("AutoresponseMutedMessage"); + if (gSavedPerAccountSettings.getBOOL("AutoresponseMutedItem")) + itemid = static_cast(gSavedPerAccountSettings.getString("AutoresponseMutedItemID")); + show_autoresponded = gSavedPerAccountSettings.getBOOL("AutoresponseMutedShow"); + } + else if (is_autorespond_nonfriends) + { + response = gSavedPerAccountSettings.getString("AutoresponseNonFriendsMessage"); + if (gSavedPerAccountSettings.getBOOL("AutoresponseNonFriendsItem")) + itemid = static_cast(gSavedPerAccountSettings.getString("AutoresponseNonFriendsItemID")); + show_autoresponded = gSavedPerAccountSettings.getBOOL("AutoresponseNonFriendsShow"); + } + else if (is_autorespond) + { + response = gSavedPerAccountSettings.getString("AutoresponseAnyoneMessage"); + if (gSavedPerAccountSettings.getBOOL("AutoresponseAnyoneItem")) + itemid = static_cast(gSavedPerAccountSettings.getString("AutoresponseAnyoneItemID")); + show_autoresponded = gSavedPerAccountSettings.getBOOL("AutoresponseAnyoneShow"); + } + pack_instant_message( + gMessageSystem, + gAgentID, + FALSE, + gAgentSessionID, + from_id, + my_name, + replace_wildcards(response, from_id, name), + IM_ONLINE, + IM_BUSY_AUTO_RESPONSE, + session_id); + gAgent.sendReliableMessage(); + + autoresponder_finish(show_autoresponded, session_id, from_id, name, itemid, is_muted); + } + } + else if (from_id.isNull()) + { + // Messages from "Second Life" ID don't go to IM history + // messages which should be routed to IM window come from a user ID with name=SYSTEM_NAME + chat.mText = name + ": " + message; + LLFloaterChat::addChat(chat, FALSE, FALSE); + } + else if (to_id.isNull()) + { + // Message to everyone from GOD, look up the fullname since + // server always slams name to legacy names + LLAvatarNameCache::get(from_id, boost::bind(god_message_name_cb, _2, chat, message)); + } + else + { + // standard message, not from system + bool mute_im = is_muted; + if (accept_im_from_only_friend && !is_friend && !is_linden) + { + if (!gIMMgr->isNonFriendSessionNotified(session_id)) + { + std::string message = LLTrans::getString("IM_unblock_only_groups_friends"); + gIMMgr->addMessage(session_id, from_id, name, message); + gIMMgr->addNotifiedNonFriendSessionID(session_id); + } + + mute_im = true; + } + + std::string saved; + if(offline == IM_OFFLINE) + { + LLStringUtil::format_map_t args; + args["[LONG_TIMESTAMP]"] = formatted_time(timestamp); + saved = LLTrans::getString("Saved_message", args); + } + else if (!mute_im) script_msg_api(from_id.asString() + ", 0"); + buffer = separator_string + saved + message.substr(message_offset); + + LL_INFOS("Messaging") << "process_improved_im: session_id( " << session_id << " ), from_id( " << from_id << " )" << LL_ENDL; + + // Muted nonfriend code moved up + +// [RLVa:KB] - Checked: 2010-11-30 (RLVa-1.3.0) + // Don't block offline IMs, or IMs from Lindens + if ( (rlv_handler_t::isEnabled()) && (offline != IM_OFFLINE) && (!RlvActions::canReceiveIM(from_id)) && (!is_linden) ) + { + if (!mute_im) + RlvUtil::sendBusyMessage(from_id, RlvStrings::getString(RLV_STRING_BLOCKED_RECVIM_REMOTE), session_id); + buffer = RlvStrings::getString(RLV_STRING_BLOCKED_RECVIM); + } +// [/RLVa:KB] + + if (!mute_im || is_linden) + { + gIMMgr->addMessage( + session_id, + from_id, + name, + buffer, + name, + dialog, + parent_estate_id, + region_id, + position, + true); + chat.mText = std::string("IM: ") + name + separator_string + saved + message.substr(message_offset); + LLFloaterChat::addChat(chat, true, false); + } + else + { + // muted user, so don't start an IM session, just record line in chat + // history. Pretend the chat is from a local agent, + // so it will go into the history but not be shown on screen. + chat.mText = buffer; + LLFloaterChat::addChat(chat, true, true); + + // Autoresponse to muted avatars + if (!gIMMgr->isNonFriendSessionNotified(session_id) && sAutorespondMuted) + { + std::string my_name; + LLAgentUI::buildFullname(my_name); + pack_instant_message( + gMessageSystem, + gAgentID, + FALSE, + gAgentSessionID, + from_id, + my_name, + replace_wildcards(gSavedPerAccountSettings.getString("AutoresponseMutedMessage"), from_id, name), + IM_ONLINE, + IM_BUSY_AUTO_RESPONSE, + session_id); + gAgent.sendReliableMessage(); + autoresponder_finish(gSavedPerAccountSettings.getBOOL("AutoresponseMutedShow"), session_id, from_id, name, gSavedPerAccountSettings.getBOOL("AutoresponseMutedItem") ? static_cast(gSavedPerAccountSettings.getString("AutoresponseMutedItemID")) : LLUUID::null, true); + } + } + } + break; + + case IM_TYPING_START: + { + static LLCachedControl sNotifyIncomingMessage(gSavedSettings, "AscentInstantMessageAnnounceIncoming"); + // Don't announce that someone has started messaging, if they're muted or when in busy mode + if (sNotifyIncomingMessage && + !gIMMgr->hasSession(session_id) && + ((accept_im_from_only_friend && (is_friend || is_linden)) || + (!(is_muted || is_do_not_disturb))) + ) + { + LLAvatarName av_name; + std::string ns_name = LLAvatarNameCache::get(from_id, &av_name) ? av_name.getNSName() : name; + + gIMMgr->addMessage(session_id, + from_id, + name, + llformat("%s ", ns_name.c_str()) + LLTrans::getString("IM_announce_incoming"), + name, + IM_NOTHING_SPECIAL, + parent_estate_id, + region_id, + position, + false); + + + // This block is very similar to the one above, but is necessary, since a session is opened to announce incoming message.. + // In order to prevent doubling up on the first response, We neglect to send this if Repeat for each message is on. + if ((is_autorespond_nonfriends || is_autorespond) && !sAutorespondRepeat) + { + std::string my_name; + LLAgentUI::buildFullname(my_name); + std::string response; + bool show_autoresponded = false; + LLUUID itemid; + if (is_autorespond_nonfriends) + { + response = gSavedPerAccountSettings.getString("AutoresponseNonFriendsMessage"); + if (gSavedPerAccountSettings.getBOOL("AutoresponseNonFriendsItem")) + itemid = static_cast(gSavedPerAccountSettings.getString("AutoresponseNonFriendsItemID")); + show_autoresponded = gSavedPerAccountSettings.getBOOL("AutoresponseNonFriendsShow"); + } + else if (is_autorespond) + { + response = gSavedPerAccountSettings.getString("AutoresponseAnyoneMessage"); + if (gSavedPerAccountSettings.getBOOL("AutoresponseAnyoneItem")) + itemid = static_cast(gSavedPerAccountSettings.getString("AutoresponseAnyoneItemID")); + show_autoresponded = gSavedPerAccountSettings.getBOOL("AutoresponseAnyoneShow"); + } + pack_instant_message(gMessageSystem, gAgentID, false, gAgentSessionID, from_id, my_name, replace_wildcards(response, from_id, name), IM_ONLINE, IM_BUSY_AUTO_RESPONSE, session_id); + gAgent.sendReliableMessage(); + + autoresponder_finish(show_autoresponded, session_id, from_id, name, itemid, is_muted); + } + } + LLPointer im_info = new LLIMInfo(gMessageSystem); + gIMMgr->processIMTypingStart(im_info); + script_msg_api(from_id.asString() + ", 4"); + } + break; + + case IM_TYPING_STOP: + { + LLPointer im_info = new LLIMInfo(gMessageSystem); + gIMMgr->processIMTypingStop(im_info); + script_msg_api(from_id.asString() + ", 5"); + } + break; + + case IM_MESSAGEBOX: + { + // This is a block, modeless dialog. + args["MESSAGE"] = message; + LLNotificationsUtil::add("SystemMessageTip", args); + } + break; + case IM_GROUP_NOTICE: + case IM_GROUP_NOTICE_REQUESTED: + { + LL_INFOS("Messaging") << "Received IM_GROUP_NOTICE message." << LL_ENDL; + + LLUUID agent_id; + U8 has_inventory; + U8 asset_type = 0; + LLUUID group_id; + std::string item_name; + + if (aux_id.notNull()) + { + // aux_id contains group id, binary bucket contains name and asset type + group_id = aux_id; + has_inventory = binary_bucket_size > 1 ? TRUE : FALSE; + from_group = TRUE; // inaccurate value correction + if (has_inventory) + { + std::string str_bucket = ll_safe_string((char*)binary_bucket, binary_bucket_size); + + typedef boost::tokenizer > tokenizer; + boost::char_separator sep("|", "", boost::keep_empty_tokens); + tokenizer tokens(str_bucket, sep); + tokenizer::iterator iter = tokens.begin(); + + asset_type = (LLAssetType::EType)(atoi((*(iter++)).c_str())); + iter++; // wearable type if applicable, otherwise asset type + item_name = std::string((*(iter++)).c_str()); + // Note There is more elements in 'tokens' ... + + + for (int i = 0; i < 6; i++) + { + LL_WARNS() << *(iter++) << LL_ENDL; + iter++; + } + } + } + else + { + // All info is in binary bucket, read it for more information. + struct notice_bucket_header_t + { + U8 has_inventory; + U8 asset_type; + LLUUID group_id; + }; + struct notice_bucket_full_t + { + struct notice_bucket_header_t header; + U8 item_name[DB_INV_ITEM_NAME_BUF_SIZE]; + }*notice_bin_bucket; + + // Make sure the binary bucket is big enough to hold the header + // and a null terminated item name. + if ((binary_bucket_size < (S32)((sizeof(notice_bucket_header_t) + sizeof(U8)))) + || (binary_bucket[binary_bucket_size - 1] != '\0')) + { + LL_WARNS("Messaging") << "Malformed group notice binary bucket" << LL_ENDL; + break; + } + + notice_bin_bucket = (struct notice_bucket_full_t*) &binary_bucket[0]; + has_inventory = notice_bin_bucket->header.has_inventory; + asset_type = notice_bin_bucket->header.asset_type; + group_id = notice_bin_bucket->header.group_id; + item_name = ll_safe_string((const char*)notice_bin_bucket->item_name); + } + + if (group_id != from_id) + { + agent_id = from_id; + } + else + { + std::string::size_type index = original_name.find(" Resident"); + if (index != std::string::npos) + { + original_name = original_name.substr(0, index); + } + + // The group notice packet does not have an AgentID. Obtain one from the name cache. + // If last name is "Resident" strip it out so the cache name lookup works. + std::string legacy_name = gCacheName->buildLegacyName(original_name); + gCacheName->getUUID(legacy_name, agent_id); + + if (agent_id.isNull()) + { + LL_WARNS("Messaging") << "buildLegacyName returned null while processing " << original_name << LL_ENDL; + } + } + + if (agent_id.notNull() && LLMuteList::getInstance()->isMuted(agent_id)) + { + break; + } + + // If there is inventory, give the user the inventory offer. + LLOfferInfo* info = nullptr; + + if (has_inventory) + { + info = new LLOfferInfo(); + + info->mIM = IM_GROUP_NOTICE; + info->mFromID = from_id; + info->mFromGroup = true; + info->mFromObject = false; + info->mTransactionID = session_id; + info->mType = (LLAssetType::EType) asset_type; + info->mFolderID = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(info->mType)); + info->mFromName = LLTrans::getString("AGroupMemberNamed", LLSD().with("GROUP_ID", group_id).with("FROM_ID", from_id)); + info->mDesc = item_name; + info->mHost = sender; + } + + // Tokenize the string. + // TODO: Support escaped tokens ("||" -> "|") + typedef boost::tokenizer > tokenizer; + boost::char_separator sep("|", "", boost::keep_empty_tokens); + tokenizer tokens(message, sep); + tokenizer::iterator iter = tokens.begin(); + + std::string subj(*iter++); + std::string mes(*iter++); + + // Send the notification down the new path. + // For requested notices, we don't want to send the popups. + if (dialog != IM_GROUP_NOTICE_REQUESTED) + { + LLSD payload; + payload["subject"] = subj; + payload["message"] = mes; + payload["sender_name"] = name; + payload["sender_id"] = agent_id; + payload["group_id"] = group_id; + payload["inventory_name"] = item_name; + payload["received_time"] = LLDate::now(); + if (info && info->asLLSD()) + { + payload["inventory_offer"] = info->asLLSD(); + } + + LLSD args; + args["SUBJECT"] = subj; + args["MESSAGE"] = mes; + LLDate notice_date = LLDate(timestamp).notNull() ? LLDate(timestamp) : LLDate::now(); + LLNotifications::instance().add(LLNotification::Params("GroupNotice").substitutions(args).payload(payload).timestamp(notice_date)); + } + + // Also send down the old path for now. + if (IM_GROUP_NOTICE_REQUESTED == dialog) + { + LLGroupActions::showNotice(subj,mes,group_id,has_inventory,item_name,info); + } + else + { + delete info; + } + } + break; + case IM_GROUP_INVITATION: + { + if (!is_muted) + { + // group is not blocked, but we still need to check agent that sent the invitation + // and we have no agent's id + // Note: server sends username "first.last". + size_t index = original_name.find(" Resident"); + if (index != std::string::npos) + { + original_name = original_name.substr(0, index); + } + std::string legacy_name = gCacheName->buildLegacyName(original_name); + LLUUID agent_id; + gCacheName->getUUID(legacy_name, agent_id); + if (agent_id.isNull()) + { + LL_WARNS("Messaging") << "buildLegacyName returned null while processing " << original_name << LL_ENDL; + } + else + { + is_muted |= (bool) LLMuteList::getInstance()->isMuted(agent_id); + } + } + //if (is_do_not_disturb || is_muted) + if (is_muted) return; + if (is_do_not_disturb) + { + send_do_not_disturb_message(gMessageSystem, from_id); + } + + //if (!is_muted) + { + LL_INFOS("Messaging") << "Received IM_GROUP_INVITATION message." << LL_ENDL; + // Read the binary bucket for more information. + struct invite_bucket_t + { + S32 membership_fee; + LLUUID role_id; + }* invite_bucket; + + // Make sure the binary bucket is the correct size. + if (binary_bucket_size != sizeof(invite_bucket_t)) + { + LL_WARNS("Messaging") << "Malformed group invite binary bucket" << LL_ENDL; + break; + } + + invite_bucket = (struct invite_bucket_t*) &binary_bucket[0]; + S32 membership_fee = ntohl(invite_bucket->membership_fee); + // NaCl - Antispam + if (membership_fee > 0 && gSavedSettings.getBOOL("AntiSpamGroupFeeInvites")) + return; + // NaCl End + + LLSD payload; + payload["transaction_id"] = session_id; + payload["group_id"] = from_group ? from_id : aux_id; + payload["name"] = name; + payload["message"] = message; + payload["fee"] = membership_fee; + payload["use_offline_cap"] = session_id.isNull() && (offline == IM_OFFLINE); + + LLSD args; + args["MESSAGE"] = message; + // we shouldn't pass callback functor since it is registered in LLFunctorRegistration + LLNotificationsUtil::add("JoinGroup", args, payload); + } + } + break; + + case IM_INVENTORY_OFFERED: + case IM_TASK_INVENTORY_OFFERED: + // Someone has offered us some inventory. + { + LLOfferInfo* info = new LLOfferInfo; + if (IM_INVENTORY_OFFERED == dialog) + { + struct offer_agent_bucket_t + { + S8 asset_type; + LLUUID object_id; + }* bucketp; + + if (sizeof(offer_agent_bucket_t) != binary_bucket_size) + { + LL_WARNS("Messaging") << "Malformed inventory offer from agent" << LL_ENDL; + delete info; + break; + } + bucketp = (struct offer_agent_bucket_t*) &binary_bucket[0]; + info->mType = (LLAssetType::EType) bucketp->asset_type; + info->mObjectID = bucketp->object_id; + info->mFromObject = FALSE; + } + else // IM_TASK_INVENTORY_OFFERED + { + if (offline == IM_OFFLINE && session_id.isNull() && aux_id.notNull() && binary_bucket_size > sizeof(S8)* 5) + { + // cap received offline message + std::string str_bucket = ll_safe_string((char*)binary_bucket, binary_bucket_size); + typedef boost::tokenizer > tokenizer; + boost::char_separator sep("|", "", boost::keep_empty_tokens); + tokenizer tokens(str_bucket, sep); + tokenizer::iterator iter = tokens.begin(); + + info->mType = (LLAssetType::EType)(atoi((*(iter++)).c_str())); + // Note There is more elements in 'tokens' ... + + info->mObjectID = LLUUID::null; + info->mFromObject = TRUE; + } + else + { + if (sizeof(S8) != binary_bucket_size) + { + LL_WARNS("Messaging") << "Malformed inventory offer from object" << LL_ENDL; + delete info; + break; + } + info->mType = (LLAssetType::EType) binary_bucket[0]; + info->mObjectID = LLUUID::null; + info->mFromObject = TRUE; + } + } + + info->mIM = dialog; + info->mFromID = from_id; + info->mFromGroup = from_group; + info->mTransactionID = session_id; + info->mFolderID = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(info->mType)); + + info->mFromName = name; + info->mDesc = message; + info->mHost = sender; + //if (((is_do_not_disturb && !is_owned_by_me) || is_muted)) + if (is_muted) + { + // Prefetch the offered item so that it can be discarded by the appropriate observer. (EXT-4331) + if (IM_INVENTORY_OFFERED == dialog) + { + LLInventoryFetchItemsObserver* fetch_item = new LLInventoryFetchItemsObserver(info->mObjectID); + fetch_item->startFetch(); + delete fetch_item; + // Same as closing window + info->forceResponse(IOR_DECLINE); + } + else + { + info->forceResponse(IOR_MUTE); + } + } + /* Singu Note: Handle this inside inventory_offer_handler so if the user wants to autoaccept offers, they can while busy. + // old logic: busy mode must not affect interaction with objects (STORM-565) + // new logic: inventory offers from in-world objects should be auto-declined (CHUI-519) + // Singu Note: We should use old logic + else if (is_do_not_disturb && dialog != IM_TASK_INVENTORY_OFFERED) // busy mode must not affect interaction with objects (STORM-565) + { + // Until throttling is implemented, do not disturb mode should reject inventory instead of silently + // accepting it. SEE SL-39554 + info->forceResponse(IOR_DECLINE); + } + */ + else + { + inventory_offer_handler(info, is_friend, is_owned_by_me); + } + } + break; + + case IM_INVENTORY_ACCEPTED: + { +// args["NAME"] = LLAvatarActions::getSLURL(from_id); +// [RLVa:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a + // Only anonymize the name if the agent is nearby, there isn't an open IM session to them and their profile isn't open + bool fRlvFilterName = (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (RlvUtil::isNearbyAgent(from_id)) && + (!RlvUIEnabler::hasOpenProfile(from_id)) && (!RlvUIEnabler::hasOpenIM(from_id)); + args["NAME"] = (!fRlvFilterName) ? LLAvatarActions::getSLURL(from_id) : RlvStrings::getAnonym(name); +// [/RLVa:KB] + LLNotificationsUtil::add("InventoryAccepted", args); + break; + } + case IM_INVENTORY_DECLINED: + { +// args["NAME"] = LLAvatarActions::getSLURL(from_id); +// [RLVa:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a + // Only anonymize the name if the agent is nearby, there isn't an open IM session to them and their profile isn't open + bool fRlvFilterName = (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (RlvUtil::isNearbyAgent(from_id)) && + (!RlvUIEnabler::hasOpenProfile(from_id)) && (!RlvUIEnabler::hasOpenIM(from_id)); + args["NAME"] = (!fRlvFilterName) ? LLAvatarActions::getSLURL(from_id) : RlvStrings::getAnonym(name); +// [/RLVa:KB] + LLNotificationsUtil::add("InventoryDeclined", args); + break; + } + // TODO: _DEPRECATED suffix as part of vote removal - DEV-24856 + case IM_GROUP_VOTE: + { + LLSD args; + args["NAME"] = name; + args["MESSAGE"] = message; + + LLSD payload; + payload["group_id"] = session_id; + LLNotificationsUtil::add("GroupVote", args, payload); + } + break; + + case IM_GROUP_ELECTION_DEPRECATED: + { + LL_WARNS("Messaging") << "Received IM: IM_GROUP_ELECTION_DEPRECATED" << LL_ENDL; + } + break; + + case IM_FROM_TASK: + { + if (is_do_not_disturb && !is_owned_by_me) + { + return; + } + chat.mText = name + separator_string + message.substr(message_offset); + chat.mFromName = name; + + // Build a link to open the object IM info window. + std::string location = ll_safe_string((char*)binary_bucket, binary_bucket_size-1); + + if (session_id.notNull()) + { + chat.mFromID = session_id; + } + else + { + // This message originated on a region without the updated code for task id and slurl information. + // We just need a unique ID for this object that isn't the owner ID. + // If it is the owner ID it will overwrite the style that contains the link to that owner's profile. + // This isn't ideal - it will make 1 style for all objects owned by the the same person/group. + // This works because the only thing we can really do in this case is show the owner name and link to their profile. + chat.mFromID = from_id ^ gAgent.getSessionID(); + } + + chat.mSourceType = CHAT_SOURCE_OBJECT; + + // To conclude that the source type of message is CHAT_SOURCE_SYSTEM it's not + // enough to check only from name (i.e. fromName = "Second Life"). For example + // source type of messages from objects called "Second Life" should not be CHAT_SOURCE_SYSTEM. + bool chat_from_system = (SYSTEM_FROM == name) && region_id.isNull() && position.isNull(); + if (chat_from_system) + { + // System's UUID is NULL (fixes EXT-4766) + chat.mFromID = LLUUID::null; + chat.mSourceType = CHAT_SOURCE_SYSTEM; + } + else script_msg_api(chat.mFromID.asString() + ", 6"); + + // IDEVO Some messages have embedded resident names + message = clean_name_from_task_im(message, from_group); + + LLSD query_string; + query_string["owner"] = from_id; +// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Added: RLVa-1.2.0f + if (rlv_handler_t::isEnabled()) + { + // NOTE: the chat message itself will be filtered in LLNearbyChatHandler::processChat() + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES) || gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS)) && (!from_group) && (RlvUtil::isNearbyAgent(from_id)) ) + { + query_string["rlv_shownames"] = TRUE; + + RlvUtil::filterNames(name); + chat.mFromName = name; + } + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) + { + std::string::size_type idxPos = location.find('/'); + if ( (std::string::npos != idxPos) && (RlvUtil::isNearbyRegion(location.substr(0, idxPos))) ) + location = RlvStrings::getString(RLV_STRING_HIDDEN_REGION); + } + } +// [/RLVa:KB] + query_string["slurl"] = location; + query_string["name"] = name; + if (from_group) + { + query_string["groupowned"] = "true"; + } + +// chat.mURL = LLSLURL("objectim", session_id, "").getSLURLString(); +// [SL:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Added: RLVa-1.2.2a + chat.mURL = LLSLURL("objectim", session_id, LLURI::mapToQueryString(query_string)).getSLURLString(); +// [/SL:KB] + chat.mText = name + separator_string + message.substr(message_offset); + + // Note: lie to Nearby Chat, pretending that this is NOT an IM, because + // IMs from objects don't open IM sessions. + LLFloaterChat::addChat(chat, FALSE, FALSE); + } + break; + + case IM_SESSION_SEND: // ad-hoc or group IMs + { + if (!is_linden && is_do_not_disturb) return; + + // Only show messages if we have a session open (which + // should happen after you get an "invitation" +// if ( !gIMMgr->hasSession(session_id) ) +// [RLVa:KB] - Checked: 2010-11-30 (RLVa-1.3.0c) | Modified: RLVa-1.3.0c + LLFloaterIMPanel* pIMFloater = gIMMgr->findFloaterBySession(session_id); + if (!pIMFloater) + { + return; + } + + if (from_id != gAgentID && (gRlvHandler.hasBehaviour(RLV_BHVR_RECVIM) || gRlvHandler.hasBehaviour(RLV_BHVR_RECVIMFROM))) + { + switch (pIMFloater->getSessionType()) + { + case LLFloaterIMPanel::GROUP_SESSION: // Group chat + if (!RlvActions::canReceiveIM(session_id)) + return; + break; + case LLFloaterIMPanel::ADHOC_SESSION: // Conference chat + if (!RlvActions::canReceiveIM(from_id)) + message = RlvStrings::getString(RLV_STRING_BLOCKED_RECVIM); + break; + default: + RLV_ASSERT(false); + return; + } + } +// [/RLVa:KB] + + // standard message, not from system + std::string saved; + if (offline == IM_OFFLINE) + { + LLStringUtil::format_map_t args; + args["[LONG_TIMESTAMP]"] = formatted_time(timestamp); + saved = LLTrans::getString("Saved_message", args); + } + buffer = separator_string + saved + message.substr(message_offset); + + LL_DEBUGS("Messaging") << "standard message session_id( " << session_id << " ), from_id( " << from_id << " )" << LL_ENDL; + + gIMMgr->addMessage( + session_id, + from_id, + name, + buffer, + ll_safe_string((char*)binary_bucket), + IM_SESSION_INVITE, + parent_estate_id, + region_id, + position, + true); + + std::string prepend_msg; + if (gAgent.isInGroup(session_id)&& gSavedSettings.getBOOL("OptionShowGroupNameInChatIM")) + { + prepend_msg = '['; + prepend_msg += std::string((char*)binary_bucket); + prepend_msg += "] "; + } + else + { + prepend_msg = std::string("IM: "); + } + chat.mText = prepend_msg + name + separator_string + saved + message.substr(message_offset); + LLFloaterChat::addChat(chat, TRUE, from_id == gAgentID); + + break; + } + case IM_FROM_TASK_AS_ALERT: + if (is_do_not_disturb && !is_owned_by_me) + { + return; + } + { + // Construct a viewer alert for this message. + args["NAME"] = name; + args["MESSAGE"] = message; + LLNotificationsUtil::add("ObjectMessage", args); + } + break; + case IM_BUSY_AUTO_RESPONSE: + if (is_muted) + { + LL_DEBUGS("Messaging") << "Ignoring do-not-disturb response from " << from_id << LL_ENDL; + return; + } + else + { + gIMMgr->addMessage(session_id, from_id, name, separator_string + message.substr(message_offset), name, dialog, parent_estate_id, region_id, position, true); + } + break; + + case IM_LURE_USER: + case IM_TELEPORT_REQUEST: + { + // [RLVa:KB] - Checked: RLVa-1.4.9 + // If we auto-accept the offer/request then this will override DnD status (but we'll still let the other party know later) + bool fRlvAutoAccept = (rlv_handler_t::isEnabled()) && + ( ((IM_LURE_USER == dialog) && (RlvActions::autoAcceptTeleportOffer(from_id))) || + ((IM_TELEPORT_REQUEST == dialog) && (RlvActions::autoAcceptTeleportRequest(from_id))) ); +// [/RLVa:KB] + + bool following = gAgent.getAutoPilotLeaderID() == from_id; + + if (!following && is_muted) + { + return; + } +// else if (!following && is_do_not_disturb) +// [RLVa:KB] - Checked: 2013-11-08 (RLVa-1.4.9) + else if (!following && is_do_not_disturb && !fRlvAutoAccept ) +// [/RLVa:KB] + { + send_do_not_disturb_message(gMessageSystem, from_id); + } + else + { +// if (!following && is_do_not_disturb) +// [RLVa:KB] - Checked: RLVa-1.4.9 + if (!following && (is_do_not_disturb) && (!fRlvAutoAccept) ) +// [/RLVa:KB] + { + send_do_not_disturb_message(gMessageSystem, from_id); + } + + LLVector3 pos, look_at; + U64 region_handle(0); + U8 region_access(SIM_ACCESS_MIN); + std::string region_info = ll_safe_string((char*)binary_bucket, binary_bucket_size); + std::string region_access_str = LLStringUtil::null; + std::string region_access_icn = LLStringUtil::null; + std::string region_access_lc = LLStringUtil::null; + + bool canUserAccessDstRegion = true; + bool doesUserRequireMaturityIncrease = false; + + // Do not parse the (empty) lure bucket for TELEPORT_REQUEST + if (IM_TELEPORT_REQUEST != dialog && parse_lure_bucket(region_info, region_handle, pos, look_at, region_access)) + { + region_access_str = LLViewerRegion::accessToString(region_access); + region_access_icn = LLViewerRegion::getAccessIcon(region_access); + region_access_lc = region_access_str; + LLStringUtil::toLower(region_access_lc); + + if (!gAgent.isGodlike()) + { + switch (region_access) + { + case SIM_ACCESS_MIN: + case SIM_ACCESS_PG: + break; + case SIM_ACCESS_MATURE: + if (gAgent.isTeen()) + { + canUserAccessDstRegion = false; + } + else if (gAgent.prefersPG()) + { + doesUserRequireMaturityIncrease = true; + } + break; + case SIM_ACCESS_ADULT: + if (!gAgent.isAdult()) + { + canUserAccessDstRegion = false; + } + else if (!gAgent.prefersAdult()) + { + doesUserRequireMaturityIncrease = true; + } + break; + default: + llassert(0); + break; + } + } + } + +// [RLVa:KB] - Checked: RLVa-1.4.9 + if (rlv_handler_t::isEnabled()) + { + if ( ((IM_LURE_USER == dialog) && (!RlvActions::canAcceptTpOffer(from_id))) || + ((IM_TELEPORT_REQUEST == dialog) && (!RlvActions::canAcceptTpRequest(from_id))) ) + { + RlvUtil::sendBusyMessage(from_id, RlvStrings::getString(RLV_STRING_BLOCKED_TPLUREREQ_REMOTE)); + if (is_do_not_disturb) + send_do_not_disturb_message(gMessageSystem, from_id); + return; + } + + // Censor message if: 1) restricted from receiving IMs from the sender, or 2) teleport offer/request and @showloc=n restricted + if ( (!RlvActions::canReceiveIM(from_id)) || + ((gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) && (IM_LURE_USER == dialog || IM_TELEPORT_REQUEST == dialog)) ) + { + message = RlvStrings::getString(RLV_STRING_HIDDEN); + } + } +// [/RLVa:KB] + + LLSD args; + // *TODO: Translate -> [FIRST] [LAST] (maybe) + args["NAME"] = LLAvatarActions::getSLURL(from_id); + args["MESSAGE"] = message; + args["MATURITY_STR"] = region_access_str; + args["MATURITY_ICON"] = region_access_icn; + args["REGION_CONTENT_MATURITY"] = region_access_lc; + LLSD payload; + payload["from_id"] = from_id; + payload["lure_id"] = session_id; + payload["godlike"] = FALSE; + payload["region_maturity"] = region_access; + + /* Singu TODO: Figure if we should use these + if (!canUserAccessDstRegion) + { + LLNotification::Params params("TeleportOffered_MaturityBlocked"); + params.substitutions = args; + params.payload = payload; + LLPostponedNotification::add(params, from_id, false); + send_simple_im(from_id, LLTrans::getString("TeleportMaturityExceeded"), IM_NOTHING_SPECIAL, session_id); + send_simple_im(from_id, LLStringUtil::null, IM_LURE_DECLINED, session_id); + } + else if (doesUserRequireMaturityIncrease) + { + LLNotification::Params params("TeleportOffered_MaturityExceeded"); + params.substitutions = args; + params.payload = payload; + LLPostponedNotification::add(params, from_id, false); + } + else + */ + { + /* Singu Note: No default constructor for LLNotification::Params + LLNotification::Params params; + if (IM_LURE_USER == dialog) + { + params.name = "TeleportOffered"; + params.functor_name = "TeleportOffered"; + } + else if (IM_TELEPORT_REQUEST == dialog) + { + params.name = "TeleportRequest"; + params.functor_name = "TeleportRequest"; + } + */ + LLNotification::Params params(IM_LURE_USER == dialog ? "TeleportOffered" : "TeleportRequest"); + params.substitutions = args; + params.payload = payload; + + if (following) + { + LLNotifications::instance().forceResponse(LLNotification::Params(params.name).payload(payload), 0); + } + else +// [RLVa:KB] - Checked: 20103-11-08 (RLVa-1.4.9) + if ( (rlv_handler_t::isEnabled()) && (fRlvAutoAccept) ) + { + if (IM_LURE_USER == dialog) + gRlvHandler.setCanCancelTp(false); + if (is_do_not_disturb) + send_do_not_disturb_message(gMessageSystem, from_id); + LLNotifications::instance().forceResponse(LLNotification::Params(params.name).payload(payload), 0); + } + else + { + LLNotifications::instance().add(params); + + // + if (IM_LURE_USER == dialog) + gAgent.showLureDestination(LLAvatarActions::getSLURL(from_id), region_handle, pos.mV[VX], pos.mV[VY], pos.mV[VZ]); + script_msg_api(from_id.asString().append(IM_LURE_USER == dialog ? ", 2" : ", 3")); + // + } +// [/RLVa:KB] +// LLNotifications::instance().add(params); + } + } + } + break; + + case IM_GODLIKE_LURE_USER: + { + LLVector3 pos, look_at; + U64 region_handle(0); + U8 region_access(SIM_ACCESS_MIN); + std::string region_info = ll_safe_string((char*)binary_bucket, binary_bucket_size); + std::string region_access_str = LLStringUtil::null; + std::string region_access_icn = LLStringUtil::null; + std::string region_access_lc = LLStringUtil::null; + + bool canUserAccessDstRegion = true; + bool doesUserRequireMaturityIncrease = false; + + if (parse_lure_bucket(region_info, region_handle, pos, look_at, region_access)) + { + region_access_str = LLViewerRegion::accessToString(region_access); + region_access_icn = LLViewerRegion::getAccessIcon(region_access); + region_access_lc = region_access_str; + LLStringUtil::toLower(region_access_lc); + + if (!gAgent.isGodlike()) + { + switch (region_access) + { + case SIM_ACCESS_MIN: + case SIM_ACCESS_PG: + break; + case SIM_ACCESS_MATURE: + if (gAgent.isTeen()) + { + canUserAccessDstRegion = false; + } + else if (gAgent.prefersPG()) + { + doesUserRequireMaturityIncrease = true; + } + break; + case SIM_ACCESS_ADULT: + if (!gAgent.isAdult()) + { + canUserAccessDstRegion = false; + } + else if (!gAgent.prefersAdult()) + { + doesUserRequireMaturityIncrease = true; + } + break; + default: + llassert(0); + break; + } + } + } + + LLSD args; + // *TODO: Translate -> [FIRST] [LAST] (maybe) + args["NAME"] = LLAvatarActions::getSLURL(from_id); + args["MESSAGE"] = message; + args["MATURITY_STR"] = region_access_str; + args["MATURITY_ICON"] = region_access_icn; + args["REGION_CONTENT_MATURITY"] = region_access_lc; + LLSD payload; + payload["from_id"] = from_id; + payload["lure_id"] = session_id; + payload["godlike"] = TRUE; + payload["region_maturity"] = region_access; + + /*if (!canUserAccessDstRegion) + { + LLNotification::Params params("TeleportOffered_MaturityBlocked"); + params.substitutions = args; + params.payload = payload; + LLPostponedNotification::add(params, from_id, false); + send_simple_im(from_id, LLTrans::getString("TeleportMaturityExceeded"), IM_NOTHING_SPECIAL, session_id); + send_simple_im(from_id, LLStringUtil::null, IM_LURE_DECLINED, session_id); + } + else if (doesUserRequireMaturityIncrease) + { + LLNotification::Params params("TeleportOffered_MaturityExceeded"); + params.substitutions = args; + params.payload = payload; + LLPostponedNotification::add(params, from_id, false); + } + else*/ + { + // do not show a message box, because you're about to be + // teleported. + LLNotifications::instance().forceResponse(LLNotification::Params("TeleportOffered").payload(payload), 0); + } + } + break; + + case IM_GOTO_URL: + { + LLSD args; + // n.b. this is for URLs sent by the system, not for + // URLs sent by scripts (i.e. llLoadURL) + if (binary_bucket_size <= 0) + { + LL_WARNS("Messaging") << "bad binary_bucket_size: " + << binary_bucket_size + << " - aborting function." << LL_ENDL; + return; + } + + std::string url; + + url.assign((char*)binary_bucket, binary_bucket_size-1); + args["MESSAGE"] = message; + args["URL"] = url; + LLSD payload; + payload["url"] = url; + LLNotificationsUtil::add("GotoURL", args, payload); + } + break; + + case IM_FRIENDSHIP_OFFERED: + { + LLSD payload; + payload["from_id"] = from_id; + payload["session_id"] = session_id; + payload["online"] = (offline == IM_ONLINE); + payload["sender"] = sender.getIPandPort(); + + if (is_muted) + { + LLNotifications::instance().forceResponse(LLNotification::Params("OfferFriendship").payload(payload), 1); + } + else + { + if (is_do_not_disturb) + { + send_do_not_disturb_message(gMessageSystem, from_id); + } + args["[NAME_SLURL]"] = LLAvatarActions::getSLURL(from_id); + if (message.empty()) + { + //support for frienship offers from clients before July 2008 + LLNotificationsUtil::add("OfferFriendshipNoMessage", args, payload); + } + else + { + args["[MESSAGE]"] = message; + LLNotificationsUtil::add("OfferFriendship", args, payload); + } + } + } + break; + + case IM_FRIENDSHIP_ACCEPTED: + { + // In the case of an offline IM, the formFriendship() may be extraneous + // as the database should already include the relationship. But it + // doesn't hurt for dupes. + LLAvatarTracker::formFriendship(from_id); + + std::vector strings; + strings.push_back(from_id.asString()); + send_generic_message("requestonlinenotification", strings); + + args["NAME"] = name; + LLSD payload; + payload["from_id"] = from_id; + LLAvatarNameCache::get(from_id, boost::bind(¬ification_display_name_callback, _1, _2, "FriendshipAccepted", args, payload)); + } + break; + + case IM_FRIENDSHIP_DECLINED_DEPRECATED: + default: + LL_WARNS("Messaging") << "Instant message calling for unknown dialog " + << (S32)dialog << LL_ENDL; + break; + } + + LLWindow* viewer_window = gViewerWindow->getWindow(); + if (viewer_window && viewer_window->getMinimized() && gSavedSettings.getBOOL("LiruFlashWhenMinimized")) + { + viewer_window->flashIcon(5.f); + } +} + +void LLIMProcessing::requestOfflineMessages() +{ + static BOOL requested = FALSE; + if (!requested + && gMessageSystem + && LLMuteList::getInstance()->isLoaded() + && isAgentAvatarValid() + && gAgent.getRegion() + && gAgent.getRegion()->capabilitiesReceived()) + { + std::string cap_url = gAgent.getRegionCapability("ReadOfflineMsgs"); + + // Auto-accepted inventory items may require the avatar object + // to build a correct name. Likewise, inventory offers from + // muted avatars require the mute list to properly mute. + if (cap_url.empty() + || gAgent.getRegionCapability("AcceptFriendship").empty() + || gAgent.getRegionCapability("AcceptGroupInvite").empty()) + { + // Offline messages capability provides no session/transaction ids for message AcceptFriendship and IM_GROUP_INVITATION to work + // So make sure we have the caps before using it. + requestOfflineMessagesLegacy(); + } + else + { + LLHTTPClient::get(cap_url, new LLCoroResponder( + LLIMProcessing::requestOfflineMessagesCoro)); + } + requested = TRUE; + } +} + +void LLIMProcessing::requestOfflineMessagesCoro(const LLCoroResponder& responder) +{ + auto status = responder.getStatus(); + + if (!responder.isGoodStatus(status)) // success = httpResults["success"].asBoolean(); + { + LL_WARNS("Messaging") << "Error requesting offline messages via capability " << responder.getURL() << ", Status: " << status << ", Reason: " << responder.getReason() << "\nFalling back to legacy method." << LL_ENDL; + + requestOfflineMessagesLegacy(); + return; + } + + const auto& contents = responder.getContent(); + + if (!contents.size()) + { + LL_WARNS("Messaging") << "No contents received for offline messages via capability " << responder.getURL() << LL_ENDL; + return; + } + + // Todo: once dirtsim-369 releases, remove one of the map/array options + LLSD messages; + if (contents.isArray()) + { + messages = *contents.beginArray(); + } + else if (contents.has("messages")) + { + messages = contents["messages"]; + } + else + { + LL_WARNS("Messaging") << "Invalid offline message content received via capability " << responder.getURL() << LL_ENDL; + return; + } + + if (!messages.isArray()) + { + LL_WARNS("Messaging") << "Invalid offline message content received via capability " << responder.getURL() << LL_ENDL; + return; + } + + if (messages.emptyArray()) + { + // Nothing to process + return; + } + + LL_INFOS("Messaging") << "Processing offline messages." << LL_ENDL; + + std::vector data; + S32 binary_bucket_size = 0; + LLHost sender = gAgent.getRegion()->getHost(); + + LLSD::array_iterator i = messages.beginArray(); + LLSD::array_iterator iEnd = messages.endArray(); + for (; i != iEnd; ++i) + { + const LLSD &message_data(*i); + + LLVector3 position(message_data["local_x"].asReal(), message_data["local_y"].asReal(), message_data["local_z"].asReal()); + data = message_data["binary_bucket"].asBinary(); + binary_bucket_size = data.size(); // message_data["count"] always 0 + U32 parent_estate_id = message_data.has("parent_estate_id") ? message_data["parent_estate_id"].asInteger() : 1; // 1 - IMMainland + + // Todo: once dirtsim-369 releases, remove one of the int/str options + BOOL from_group; + if (message_data["from_group"].isInteger()) + { + from_group = message_data["from_group"].asInteger(); + } + else + { + from_group = message_data["from_group"].asString() == "Y"; + } + + LLIMProcessing::processNewMessage(message_data["from_agent_id"].asUUID(), + from_group, + message_data["to_agent_id"].asUUID(), + IM_OFFLINE, + (EInstantMessage)message_data["dialog"].asInteger(), + LLUUID::null, // session id, since there is none we can only use frienship/group invite caps + message_data["timestamp"].asInteger(), + message_data["from_agent_name"].asString(), + message_data["message"].asString(), + parent_estate_id, + message_data["region_id"].asUUID(), + position, + &data[0], + binary_bucket_size, + sender, + message_data["asset_id"].asUUID()); // not necessarily an asset + } +} + +void LLIMProcessing::requestOfflineMessagesLegacy() +{ + LL_INFOS("Messaging") << "Requesting offline messages (Legacy)." << LL_ENDL; + + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_RetrieveInstantMessages); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + gAgent.sendReliableMessage(); +} + diff --git a/indra/newview/llimprocessing.h b/indra/newview/llimprocessing.h new file mode 100644 index 000000000..c8cc47f49 --- /dev/null +++ b/indra/newview/llimprocessing.h @@ -0,0 +1,68 @@ +/** +* @file LLIMMgr.h +* @brief Container for Instant Messaging +* +* $LicenseInfo:firstyear=2001&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_LLIMPROCESSING_H +#define LL_LLIMPROCESSING_H + +#include "llinstantmessage.h" + +struct LLCoroResponder; + +std::string replace_wildcards(std::string input, const LLUUID& id, const std::string& name); +bool handle_obj_auth(const LLUUID& from_id, const std::string& mesg); + +class LLIMProcessing +{ +public: + // Pre-process message for IM manager + static void processNewMessage(const LLUUID& from_id, + BOOL from_group, + const LLUUID& to_id, + U8 offline, + EInstantMessage dialog, // U8 + const LLUUID& session_id, + U32 timestamp, + std::string& agentName, + std::string& message, + U32 parent_estate_id, + const LLUUID& region_id, + LLVector3 position, + U8 *binary_bucket, + S32 binary_bucket_size, + LLHost &sender, + const LLUUID& aux_id = LLUUID::null); + + // Either receives list of offline messages from 'ReadOfflineMsgs' capability + // or uses legacy method + static void requestOfflineMessages(); + +private: + static void requestOfflineMessagesCoro(const LLCoroResponder& responder); + static void requestOfflineMessagesLegacy(); +}; + + +#endif // LL_LLLLIMPROCESSING_H diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 756466117..171301f9f 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -2964,6 +2964,12 @@ void LLFolderBridge::performAction(LLInventoryModel* model, std::string action) LFFloaterInvPanel::show(LLSD().with("id", mUUID), cat->getName(), model); return; } + else if ("copy_folder_uuid" == action) + { + // Single folder only + gViewerWindow->getWindow()->copyTextToClipboard(utf8str_to_wstring(mUUID.asString())); + return; + } else if ("paste" == action) { pasteFromClipboard(); @@ -3896,6 +3902,7 @@ void build_context_menu_folder_options(LLInventoryModel* model, const LLUUID& mU if (listings_folder.notNull() && gInventory.isObjectDescendentOf(mUUID, listings_folder)) return; items.push_back(std::string("Open Folder In New Window")); + items.push_back(std::string("Copy Folder UUID")); LLFolderType::EType type = category->getPreferredType(); const bool is_system_folder = LLFolderType::lookupIsProtectedType(type); diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 4a7dea11f..3d020e9d4 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -34,6 +34,7 @@ #include "llagent.h" #include "llagentwearables.h" #include "llappearancemgr.h" +#include "llavatarnamecache.h" #include "llinventoryclipboard.h" #include "llinventorypanel.h" #include "llinventorybridge.h" @@ -67,7 +68,7 @@ #endif // Increment this if the inventory contents change in a non-backwards-compatible way. -// For viewers with link items support, former caches are incorrect. +// For viewer 2, the addition of link items makes a pre-viewer-2 cache incorrect. const S32 LLInventoryModel::sCurrentInvCacheVersion = 2; BOOL LLInventoryModel::sFirstTimeInViewer2 = TRUE; @@ -91,8 +92,8 @@ class LLCanCache : public LLInventoryCollectFunctor { public: LLCanCache(LLInventoryModel* model) : mModel(model) {} - virtual ~LLCanCache() {} - virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); + virtual ~LLCanCache() = default; + bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) override; protected: LLInventoryModel* mModel; uuid_set_t mCachedCatIDs; @@ -136,7 +137,6 @@ LLInventoryModel gInventory; // Default constructor LLInventoryModel::LLInventoryModel() : // These are now ordered, keep them that way. - mBacklinkMMap(), mIsAgentInvUsable(false), mRootFolderID(), mLibraryRootFolderID(), @@ -145,7 +145,8 @@ LLInventoryModel::LLInventoryModel() mItemMap(), mParentChildCategoryTree(), mParentChildItemTree(), - mLastItem(NULL), + mBacklinkMMap(), + mLastItem(nullptr), mIsNotifyObservers(FALSE), mModifyMask(LLInventoryObserver::ALL), mChangedItemIDs(), @@ -184,7 +185,7 @@ BOOL LLInventoryModel::isObjectDescendentOf(const LLUUID& obj_id, if (obj_id == cat_id) return TRUE; //The while loop will ALWAYS return false if parent_id is null, regardless of cat_id being null too. Don't bother trying. if(cat_id.isNull()) return FALSE; - LLInventoryObject* obj = getObject(obj_id); + const LLInventoryObject* obj = getObject(obj_id); int depthCounter = 0; while(obj) { @@ -224,7 +225,11 @@ BOOL LLInventoryModel::isObjectDescendentOf(const LLUUID& obj_id, const LLViewerInventoryCategory *LLInventoryModel::getFirstNondefaultParent(const LLUUID& obj_id) const { const LLInventoryObject* obj = getObject(obj_id); - + if(!obj) + { + LL_WARNS(LOG_INV) << "Non-existent object [ id: " << obj_id << " ] " << LL_ENDL; + return nullptr; + } // Search up the parent chain until we get to root or an acceptable folder. // This assumes there are no cycles in the tree else we'll get a hang. LLUUID parent_id = obj->getParentUUID(); @@ -241,7 +246,7 @@ const LLViewerInventoryCategory *LLInventoryModel::getFirstNondefaultParent(cons } parent_id = cat->getParentUUID(); } - return NULL; + return nullptr; } // @@ -251,17 +256,17 @@ const LLViewerInventoryCategory* LLInventoryModel::getFirstDescendantOf(const LL { if (master_parent_id == obj_id) { - return NULL; + return nullptr; } const LLViewerInventoryCategory* current_cat = getCategory(obj_id); - if (current_cat == NULL) + if (current_cat == nullptr) { current_cat = getCategory(getObject(obj_id)->getParentUUID()); } - while (current_cat != NULL) + while (current_cat != nullptr) { const LLUUID& current_parent_id = current_cat->getParentUUID(); @@ -273,7 +278,7 @@ const LLViewerInventoryCategory* LLInventoryModel::getFirstDescendantOf(const LL current_cat = getCategory(current_parent_id); } - return NULL; + return nullptr; } bool LLInventoryModel::getObjectTopmostAncestor(const LLUUID& object_id, LLUUID& result) const @@ -306,21 +311,21 @@ LLInventoryObject* LLInventoryModel::getObject(const LLUUID& id) const { return item; } - return NULL; + return nullptr; } // Get the item by id. Returns NULL if not found. LLViewerInventoryItem* LLInventoryModel::getItem(const LLUUID& id) const { - LLViewerInventoryItem* item = NULL; + LLViewerInventoryItem* item = nullptr; if(mLastItem.notNull() && mLastItem->getUUID() == id) { item = mLastItem; } else { - item_map_t::const_iterator iter = mItemMap.find(id); - if (iter != mItemMap.end()) + const auto iter = mItemMap.find(id); + if (iter != mItemMap.cend()) { item = iter->second; mLastItem = item; @@ -332,13 +337,12 @@ LLViewerInventoryItem* LLInventoryModel::getItem(const LLUUID& id) const // Get the category by id. Returns NULL if not found LLViewerInventoryCategory* LLInventoryModel::getCategory(const LLUUID& id) const { - LLViewerInventoryCategory* category = NULL; - cat_map_t::const_iterator iter = mCategoryMap.find(id); - if (iter != mCategoryMap.end()) + const auto iter = mCategoryMap.find(id); + if (iter != mCategoryMap.cend()) { - category = iter->second; + return iter->second; } - return category; + return nullptr; } S32 LLInventoryModel::getItemCount() const @@ -384,7 +388,7 @@ LLMD5 LLInventoryModel::hashDirectDescendentNames(const LLUUID& cat_id) const } for (LLInventoryModel::item_array_t::const_iterator iter = item_array->begin(); iter != item_array->end(); - iter++) + ++iter) { const LLViewerInventoryItem *item = (*iter); if (!item) @@ -421,9 +425,9 @@ void LLInventoryModel::consolidateForType(const LLUUID& main_id, LLFolderType::E { // Make a list of folders that are not "main_id" and are of "type" uuid_vec_t folder_ids; - for (cat_map_t::iterator cit = mCategoryMap.begin(); cit != mCategoryMap.end(); ++cit) + for (const auto& cat_pair : mCategoryMap) { - LLViewerInventoryCategory* cat = cit->second; + LLViewerInventoryCategory* cat = cat_pair.second; if ((cat->getPreferredType() == type) && (cat->getUUID() != main_id)) { folder_ids.push_back(cat->getUUID()); @@ -431,10 +435,8 @@ void LLInventoryModel::consolidateForType(const LLUUID& main_id, LLFolderType::E } // Iterate through those folders - for (auto folder_ids_it = folder_ids.begin(); folder_ids_it != folder_ids.end(); ++folder_ids_it) + for (LLUUID const& folder_id: folder_ids) { - LLUUID folder_id = (*folder_ids_it); - // Get the content of this folder cat_array_t* cats; item_array_t* items; @@ -477,6 +479,8 @@ void LLInventoryModel::consolidateForType(const LLUUID& main_id, LLFolderType::E } } + + const LLUUID LLInventoryModel::findCategoryUUIDForTypeInRoot( LLFolderType::EType preferred_type, bool create_folder, @@ -489,7 +493,7 @@ const LLUUID LLInventoryModel::findCategoryUUIDForTypeInRoot( } else if (root_id.notNull()) { - cat_array_t* cats = NULL; + cat_array_t* cats = nullptr; cats = get_ptr_in_map(mParentChildCategoryTree, root_id); if(cats) { @@ -554,7 +558,7 @@ LLUUID LLInventoryModel::findCategoryByName(std::string name) return LLUUID::null; } -class LLCreateInventoryCategoryResponder : public LLHTTPClient::ResponderWithResult +class LLCreateInventoryCategoryResponder final : public LLHTTPClient::ResponderWithResult { LOG_CLASS(LLCreateInventoryCategoryResponder); public: @@ -566,12 +570,12 @@ public: } protected: - virtual void httpFailure() + void httpFailure() override { LL_WARNS(LOG_INV) << dumpResponse() << LL_ENDL; } - virtual void httpSuccess() + void httpSuccess() override { //Server has created folder. const LLSD& content = getContent(); @@ -602,7 +606,7 @@ protected: } } - /*virtual*/ char const* getName(void) const { return "LLCreateInventoryCategoryResponder"; } + char const* getName(void) const override { return "LLCreateInventoryCategoryResponder"; } private: boost::optional mCallback; @@ -671,10 +675,15 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id, return LLUUID::null; } + if (!gMessageSystem) + { + return LLUUID::null; + } + // Add the category to the internal representation LLPointer cat = new LLViewerInventoryCategory(id, parent_id, preferred_type, name, gAgent.getID()); - cat->setVersion(LLViewerInventoryCategory::VERSION_INITIAL); + cat->setVersion(LLViewerInventoryCategory::VERSION_INITIAL - 1); // accountForUpdate() will icrease version by 1 cat->setDescendentCount(0); LLCategoryUpdate update(cat->getParentUUID(), 1); accountForUpdate(update); @@ -709,7 +718,7 @@ bool LLInventoryModel::hasMatchingDirectDescendent(const LLUUID& cat_id, for (LLInventoryModel::cat_array_t::const_iterator it = cats->begin(); it != cats->end(); ++it) { - if (filter(*it,NULL)) + if (filter(*it, nullptr)) { return true; } @@ -720,7 +729,7 @@ bool LLInventoryModel::hasMatchingDirectDescendent(const LLUUID& cat_id, for (LLInventoryModel::item_array_t::const_iterator it = items->begin(); it != items->end(); ++it) { - if (filter(NULL,*it)) + if (filter(nullptr, *it)) { return true; } @@ -751,9 +760,10 @@ bool LLInventoryModel::hasMatchingDirectDescendent(const LLUUID& cat_id, class LLAlwaysCollect : public LLInventoryCollectFunctor { public: - virtual ~LLAlwaysCollect() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item) + virtual ~LLAlwaysCollect() = default; + + bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item) override { return TRUE; } @@ -796,7 +806,7 @@ void LLInventoryModel::collectDescendentsIf(const LLUUID& id, for(S32 i = 0; i < count; ++i) { LLViewerInventoryCategory* cat = cat_array->at(i); - if(add(cat,NULL)) + if(add(cat, nullptr)) { cats.push_back(cat); } @@ -807,7 +817,7 @@ void LLInventoryModel::collectDescendentsIf(const LLUUID& id, } } - LLViewerInventoryItem* item = NULL; + LLViewerInventoryItem* item = nullptr; item_array_t* item_array = get_ptr_in_map(mParentChildItemTree, id); // Move onto items @@ -817,7 +827,7 @@ void LLInventoryModel::collectDescendentsIf(const LLUUID& id, for(S32 i = 0; i < count; ++i) { item = item_array->at(i); - if(add(NULL, item)) + if(add(nullptr, item)) { items.push_back(item); } @@ -870,11 +880,9 @@ void LLInventoryModel::addChangedMaskForLinks(const LLUUID& object_id, U32 mask) return; LLInventoryModel::item_array_t item_array = collectLinksTo(object_id); - for (LLInventoryModel::item_array_t::iterator iter = item_array.begin(); - iter != item_array.end(); - iter++) + for (auto& iter : item_array) { - LLViewerInventoryItem *linked_item = (*iter); + LLViewerInventoryItem *linked_item = iter; addChangedMask(mask, linked_item->getUUID()); }; } @@ -949,14 +957,6 @@ U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item, U32 mask) return mask; } - // We're hiding mesh types -#if 0 - if (item->getType() == LLAssetType::AT_MESH) - { - return mask; - } -#endif - LLPointer old_item = getItem(item->getUUID()); LLPointer new_item; if(old_item) @@ -965,12 +965,23 @@ U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item, U32 mask) new_item = old_item; LLUUID old_parent_id = old_item->getParentUUID(); LLUUID new_parent_id = item->getParentUUID(); + bool update_parent_on_server = false; + + if (new_parent_id.isNull()) + { + // item with null parent will end in random location and then in Lost&Found, + // either move to default folder as if it is new item or don't move at all + LL_WARNS(LOG_INV) << "Update attempts to reparent item " << item->getUUID() + << " to null folder. Moving to Lost&Found. Old item name: " << old_item->getName() + << ". New name: " << item->getName() + << "." << LL_ENDL; + new_parent_id = findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); + update_parent_on_server = true; + } if(old_parent_id != new_parent_id) { - // need to update the parent-child tree - item_array_t* item_array; - item_array = get_ptr_in_map(mParentChildItemTree, old_parent_id); + item_array_t * item_array = get_ptr_in_map(mParentChildItemTree, old_parent_id); if(item_array) { vector_replace_with_last(*item_array, old_item); @@ -978,6 +989,11 @@ U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item, U32 mask) item_array = get_ptr_in_map(mParentChildItemTree, new_parent_id); if(item_array) { + if (update_parent_on_server) + { + LLInventoryModel::LLCategoryUpdate update(new_parent_id, 1); + gInventory.accountForUpdate(update); + } item_array->push_back(old_item); } mask |= LLInventoryObserver::STRUCTURE; @@ -991,6 +1007,12 @@ U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item, U32 mask) mask |= LLInventoryObserver::DESCRIPTION; } old_item->copyViewerItem(item); + if (update_parent_on_server) + { + // Parent id at server is null, so update server even if item already is in the same folder + old_item->setParent(new_parent_id); + new_item->updateParentOnServer(FALSE); + } mask |= LLInventoryObserver::INTERNAL; } else @@ -1006,8 +1028,11 @@ U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item, U32 mask) item_array_t* item_array = get_ptr_in_map(mParentChildItemTree, category_id); if( item_array ) { + LLInventoryModel::LLCategoryUpdate update(category_id, 1); + gInventory.accountForUpdate(update); + // *FIX: bit of a hack to call update server from here... - new_item->updateServer(TRUE); + new_item->updateParentOnServer(FALSE); item_array->push_back(new_item); } else @@ -1048,9 +1073,11 @@ U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item, U32 mask) item_array = get_ptr_in_map(mParentChildItemTree, parent_id); if(item_array) { + LLInventoryModel::LLCategoryUpdate update(parent_id, 1); + gInventory.accountForUpdate(update); // *FIX: bit of a hack to call update server from // here... - new_item->updateServer(TRUE); + new_item->updateParentOnServer(FALSE); item_array->push_back(new_item); } else @@ -1073,19 +1100,17 @@ U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item, U32 mask) { // Valid UUID; set the item UUID and rename it new_item->setCreator(id); - std::string avatar_name; + LLAvatarName av_name; - if (gCacheName->getFullName(id, avatar_name)) + if (LLAvatarNameCache::get(id, &av_name)) { - new_item->rename(avatar_name); + new_item->rename(av_name.getLegacyName()); mask |= LLInventoryObserver::LABEL; } else { // Fetch the current name - gCacheName->get(id, FALSE, - boost::bind(&LLViewerInventoryItem::onCallingCardNameLookup, new_item.get(), - _1, _2, _3)); + LLAvatarNameCache::get(id, boost::bind(&LLViewerInventoryItem::onCallingCardNameLookup, new_item.get(), _1, _2)); } } @@ -1137,14 +1162,12 @@ void LLInventoryModel::updateCategory(const LLViewerInventoryCategory* cat, U32 if(old_cat) { // We already have an old category, modify its values - U32 mask = LLInventoryObserver::NONE; LLUUID old_parent_id = old_cat->getParentUUID(); LLUUID new_parent_id = cat->getParentUUID(); if(old_parent_id != new_parent_id) { // need to update the parent-child tree - cat_array_t* cat_array; - cat_array = getUnlockedCatArray(old_parent_id); + cat_array_t* cat_array = getUnlockedCatArray(old_parent_id); if(cat_array) { vector_replace_with_last(*cat_array, old_cat); @@ -1178,8 +1201,7 @@ void LLInventoryModel::updateCategory(const LLViewerInventoryCategory* cat, U32 addCategory(new_cat); // make sure this category is correctly referenced by its parent. - cat_array_t* cat_array; - cat_array = getUnlockedCatArray(cat->getParentUUID()); + cat_array_t* cat_array = getUnlockedCatArray(cat->getParentUUID()); if(cat_array) { cat_array->push_back(new_cat); @@ -1192,7 +1214,8 @@ void LLInventoryModel::updateCategory(const LLViewerInventoryCategory* cat, U32 item_array_t* itemsp = new item_array_t; mParentChildCategoryTree[new_cat->getUUID()] = catsp; mParentChildItemTree[new_cat->getUUID()] = itemsp; - addChangedMask(LLInventoryObserver::ADD, cat->getUUID()); + mask |= LLInventoryObserver::ADD; + addChangedMask(mask, cat->getUUID()); } } @@ -1214,8 +1237,7 @@ void LLInventoryModel::moveObject(const LLUUID& object_id, const LLUUID& cat_id) LLPointer cat = getCategory(object_id); if(cat && (cat->getParentUUID() != cat_id)) { - cat_array_t* cat_array; - cat_array = getUnlockedCatArray(cat->getParentUUID()); + cat_array_t* cat_array = getUnlockedCatArray(cat->getParentUUID()); if(cat_array) vector_replace_with_last(*cat_array, cat); cat_array = getUnlockedCatArray(cat_id); cat->setParent(cat_id); @@ -1226,8 +1248,7 @@ void LLInventoryModel::moveObject(const LLUUID& object_id, const LLUUID& cat_id) LLPointer item = getItem(object_id); if(item && (item->getParentUUID() != cat_id)) { - item_array_t* item_array; - item_array = getUnlockedItemArray(item->getParentUUID()); + item_array_t* item_array = getUnlockedItemArray(item->getParentUUID()); if(item_array) vector_replace_with_last(*item_array, item); item_array = getUnlockedItemArray(cat_id); item->setParent(cat_id); @@ -1445,7 +1466,7 @@ void LLInventoryModel::onDescendentsPurgedFromServer(const LLUUID& object_id, bo if (getCategory(uu_id)) { cat_array_t* cat_list = getUnlockedCatArray(uu_id); - if (!cat_list || (cat_list->size() == 0)) + if (!cat_list || (cat_list->empty())) { deleteObject(uu_id, fix_broken_links); deleted_count++; @@ -1504,7 +1525,7 @@ void LLInventoryModel::deleteObject(const LLUUID& id, bool fix_broken_links, boo } LL_DEBUGS(LOG_INV) << "Deleting inventory object " << id << LL_ENDL; - mLastItem = NULL; + mLastItem = nullptr; LLUUID parent_id = obj->getParentUUID(); mCategoryMap.erase(id); mItemMap.erase(id); @@ -1529,7 +1550,7 @@ void LLInventoryModel::deleteObject(const LLUUID& id, bool fix_broken_links, boo item_list = getUnlockedItemArray(id); if(item_list) { - if (item_list->size()) + if (!item_list->empty()) { LL_WARNS(LOG_INV) << "Deleting cat " << id << " while it still has child items" << LL_ENDL; } @@ -1539,7 +1560,7 @@ void LLInventoryModel::deleteObject(const LLUUID& id, bool fix_broken_links, boo cat_list = getUnlockedCatArray(id); if(cat_list) { - if (cat_list->size()) + if (!cat_list->empty()) { LL_WARNS(LOG_INV) << "Deleting cat " << id << " while it still has child cats" << LL_ENDL; } @@ -1561,7 +1582,7 @@ void LLInventoryModel::deleteObject(const LLUUID& id, bool fix_broken_links, boo { updateLinkedObjectsFromPurge(id); } - obj = NULL; // delete obj + obj = nullptr; // delete obj if (do_notify_observers) { notifyObservers(); @@ -1574,12 +1595,12 @@ void LLInventoryModel::updateLinkedObjectsFromPurge(const LLUUID &baseobj_id) // REBUILD is expensive, so clear the current change list first else // everything else on the changelist will also get rebuilt. - if (item_array.size() > 0) + if (!item_array.empty()) { notifyObservers(); for (LLInventoryModel::item_array_t::const_iterator iter = item_array.begin(); iter != item_array.end(); - iter++) + ++iter) { const LLViewerInventoryItem *linked_item = (*iter); const LLUUID &item_id = linked_item->getUUID(); @@ -1609,7 +1630,7 @@ BOOL LLInventoryModel::containsObserver(LLInventoryObserver* observer) const void LLInventoryModel::idleNotifyObservers() { - if (mModifyMask == LLInventoryObserver::NONE && (mChangedItemIDs.size() == 0)) + if (mModifyMask == LLInventoryObserver::NONE && (mChangedItemIDs.empty())) { return; } @@ -1731,7 +1752,7 @@ void LLInventoryModel::cache( item_array_t items; LLCanCache can_cache(this); - can_cache(root_cat, NULL); + can_cache(root_cat, nullptr); collectDescendentsIf( parent_folder_id, categories, @@ -1780,8 +1801,7 @@ void LLInventoryModel::addCategory(LLViewerInventoryCategory* category) bool LLInventoryModel::hasBacklinkInfo(const LLUUID& link_id, const LLUUID& target_id) const { - std::pair range; - range = mBacklinkMMap.equal_range(target_id); + std::pair range = mBacklinkMMap.equal_range(target_id); for (backlink_mmap_t::const_iterator it = range.first; it != range.second; ++it) { if (it->second == link_id) @@ -1802,8 +1822,7 @@ void LLInventoryModel::addBacklinkInfo(const LLUUID& link_id, const LLUUID& targ void LLInventoryModel::removeBacklinkInfo(const LLUUID& link_id, const LLUUID& target_id) { - std::pair range; - range = mBacklinkMMap.equal_range(target_id); + std::pair range = mBacklinkMMap.equal_range(target_id); for (backlink_mmap_t::iterator it = range.first; it != range.second; ) { if (it->second == link_id) @@ -1824,11 +1843,7 @@ void LLInventoryModel::addItem(LLViewerInventoryItem* item) llassert(item); if(item) { - // This can happen if assettype enums from llassettype.h ever change. - // For example, there is a known backwards compatibility issue in some viewer prototypes prior to when - // the AT_LINK enum changed from 23 to 24. - if ((item->getType() == LLAssetType::AT_NONE) - || LLAssetType::lookup(item->getType()) == LLAssetType::badLookup()) + if (item->getType() <= LLAssetType::AT_NONE) { LL_WARNS(LOG_INV) << "Got bad asset type for item [ name: " << item->getName() << " type: " << item->getType() @@ -1836,6 +1851,23 @@ void LLInventoryModel::addItem(LLViewerInventoryItem* item) return; } + if (LLAssetType::lookup(item->getType()) == LLAssetType::badLookup()) + { + if (item->getType() >= LLAssetType::AT_COUNT) + { + // Not yet supported. + LL_DEBUGS(LOG_INV) << "Got unknown asset type for item [ name: " << item->getName() + << " type: " << item->getType() + << " inv-type: " << item->getInventoryType() << " ]." << LL_ENDL; + } + else + { + LL_WARNS(LOG_INV) << "Got unknown asset type for item [ name: " << item->getName() + << " type: " << item->getType() + << " inv-type: " << item->getInventoryType() << " ]." << LL_ENDL; + } + } + // This condition means that we tried to add a link without the baseobj being in memory. // The item will show up as a broken link. if (item->getIsBrokenLink()) @@ -1858,7 +1890,7 @@ void LLInventoryModel::addItem(LLViewerInventoryItem* item) // Empty the entire contents void LLInventoryModel::empty() { -// LL_INFOS(LOG_INV) << "LLInventoryModel::empty()" << LL_ENDL; + // LL_INFOS(LOG_INV) << "LLInventoryModel::empty()" << LL_ENDL; std::for_each( mParentChildCategoryTree.begin(), mParentChildCategoryTree.end(), @@ -1917,8 +1949,7 @@ void LLInventoryModel::accountForUpdate(const LLCategoryUpdate& update) const } } -void LLInventoryModel::accountForUpdate( - const LLInventoryModel::update_list_t& update) +void LLInventoryModel::accountForUpdate(const LLInventoryModel::update_list_t& update) { update_list_t::const_iterator it = update.begin(); update_list_t::const_iterator end = update.end(); @@ -1928,8 +1959,7 @@ void LLInventoryModel::accountForUpdate( } } -void LLInventoryModel::accountForUpdate( - const LLInventoryModel::update_map_t& update) +void LLInventoryModel::accountForUpdate(const LLInventoryModel::update_map_t& update) { LLCategoryUpdate up; update_map_t::const_iterator it = update.begin(); @@ -1942,8 +1972,7 @@ void LLInventoryModel::accountForUpdate( } } -LLInventoryModel::EHasChildren LLInventoryModel::categoryHasChildren( - const LLUUID& cat_id) const +LLInventoryModel::EHasChildren LLInventoryModel::categoryHasChildren(const LLUUID& cat_id) const { LLViewerInventoryCategory* cat = getCategory(cat_id); if(!cat) return CHILDREN_NO; @@ -1962,13 +1991,13 @@ LLInventoryModel::EHasChildren LLInventoryModel::categoryHasChildren( } // Shouldn't have to run this, but who knows. - parent_cat_map_t::const_iterator cat_it = mParentChildCategoryTree.find(cat->getUUID()); - if (cat_it != mParentChildCategoryTree.end() && cat_it->second->size() > 0) + const auto cat_it = mParentChildCategoryTree.find(cat->getUUID()); + if (cat_it != mParentChildCategoryTree.cend() && !cat_it->second->empty()) { return CHILDREN_YES; } - parent_item_map_t::const_iterator item_it = mParentChildItemTree.find(cat->getUUID()); - if (item_it != mParentChildItemTree.end() && item_it->second->size() > 0) + const auto item_it = mParentChildItemTree.find(cat->getUUID()); + if (item_it != mParentChildItemTree.cend() && !item_it->second->empty()) { return CHILDREN_YES; } @@ -2044,6 +2073,7 @@ bool LLInventoryModel::loadSkeleton( update_map_t child_counts; cat_array_t categories; item_array_t items; + changed_items_t categories_to_update; item_array_t possible_broken_links; cat_set_t invalid_categories; // Used to mark categories that weren't successfully loaded. std::string owner_id_str; @@ -2056,11 +2086,11 @@ bool LLInventoryModel::loadSkeleton( gzip_filename.append(".gz"); LLFILE* fp = LLFile::fopen(gzip_filename, "rb"); bool remove_inventory_file = false; - if (fp) + if(fp) { fclose(fp); - fp = NULL; - if (gunzip_file(gzip_filename, inventory_filename)) + fp = nullptr; + if(gunzip_file(gzip_filename, inventory_filename)) { // we only want to remove the inventory file if it was // gzipped before we loaded, and we successfully @@ -2073,7 +2103,7 @@ bool LLInventoryModel::loadSkeleton( } } bool is_cache_obsolete = false; - if(loadFromFile(inventory_filename, categories, items, is_cache_obsolete)) + if (loadFromFile(inventory_filename, categories, items, categories_to_update, is_cache_obsolete)) { // We were able to find a cache of files. So, use what we // found to generate a set of categories we should add. We @@ -2092,6 +2122,12 @@ bool LLInventoryModel::loadSkeleton( } LLViewerInventoryCategory* tcat = *cit; + if (categories_to_update.find(tcat->getUUID()) != categories_to_update.end()) + { + tcat->setVersion(NO_VERSION); + LL_WARNS() << "folder to update: " << tcat->getName() << LL_ENDL; + } + // we can safely ignore anything loaded from file, but // not sent down in the skeleton. Must have been removed from inventory. if (cit == not_cached) @@ -2105,11 +2141,6 @@ bool LLInventoryModel::loadSkeleton( // correct contents the next time the viewer opens the folder. tcat->setVersion(NO_VERSION); } - else if (tcat->getPreferredType() == LLFolderType::FT_MARKETPLACE_STOCK) - { - // Do not trust stock folders being updated - tcat->setVersion(NO_VERSION); - } else { cached_ids.insert(tcat->getUUID()); @@ -2119,18 +2150,18 @@ bool LLInventoryModel::loadSkeleton( // go ahead and add the cats returned during the download auto not_cached_id = cached_ids.end(); cached_category_count = cached_ids.size(); - for(cat_set_t::iterator it = temp_cats.begin(); it != temp_cats.end(); ++it) + for (const auto& temp_cat : temp_cats) { - if (cached_ids.find((*it)->getUUID()) == not_cached_id) + if(cached_ids.find(temp_cat->getUUID()) == not_cached_id) { // this check is performed so that we do not // mark new folders in the skeleton (and not in cache) // as being cached. - LLViewerInventoryCategory *llvic = (*it); + LLViewerInventoryCategory *llvic = temp_cat; llvic->setVersion(NO_VERSION); } - addCategory(*it); - ++child_counts[(*it)->getParentUUID()]; + addCategory(temp_cat); + ++child_counts[temp_cat->getParentUUID()]; } // Add all the items loaded which are parented to a @@ -2138,14 +2169,13 @@ bool LLInventoryModel::loadSkeleton( S32 bad_link_count = 0; S32 good_link_count = 0; S32 recovered_link_count = 0; - cat_map_t::iterator unparented = mCategoryMap.end(); + const auto unparented = mCategoryMap.cend(); for(item_array_t::const_iterator item_iter = items.begin(); item_iter != items.end(); ++item_iter) { LLViewerInventoryItem *item = (*item_iter).get(); - const cat_map_t::iterator cit = mCategoryMap.find(item->getParentUUID()); - + const auto cit = mCategoryMap.find(item->getParentUUID()); if(cit != unparented) { const LLViewerInventoryCategory* cat = cit->second.get(); @@ -2162,7 +2192,7 @@ bool LLInventoryModel::loadSkeleton( possible_broken_links.push_back(item); continue; } - else if (item->getIsLinkType()) + if (item->getIsLinkType()) { good_link_count++; } @@ -2172,14 +2202,14 @@ bool LLInventoryModel::loadSkeleton( } } } - if (possible_broken_links.size() > 0) + if (!possible_broken_links.empty()) { for(item_array_t::const_iterator item_iter = possible_broken_links.begin(); item_iter != possible_broken_links.end(); ++item_iter) { LLViewerInventoryItem *item = (*item_iter).get(); - const cat_map_t::iterator cit = mCategoryMap.find(item->getParentUUID()); + const auto cit = mCategoryMap.find(item->getParentUUID()); const LLViewerInventoryCategory* cat = cit->second.get(); if (item->getIsBrokenLink()) { @@ -2209,21 +2239,19 @@ bool LLInventoryModel::loadSkeleton( { // go ahead and add everything after stripping the version // information. - for (cat_set_t::iterator it = temp_cats.begin(); it != temp_cats.end(); ++it) + for (const auto& temp_cat : temp_cats) { - LLViewerInventoryCategory *llvic = (*it); + LLViewerInventoryCategory *llvic = temp_cat; llvic->setVersion(NO_VERSION); - addCategory(*it); + addCategory(temp_cat); } } // Invalidate all categories that failed fetching descendents for whatever // reason (e.g. one of the descendents was a broken link). - for (cat_set_t::iterator invalid_cat_it = invalid_categories.begin(); - invalid_cat_it != invalid_categories.end(); - invalid_cat_it++) + for (const auto& invalid_categorie : invalid_categories) { - LLViewerInventoryCategory* cat = (*invalid_cat_it).get(); + LLViewerInventoryCategory* cat = invalid_categorie.get(); cat->setVersion(NO_VERSION); LL_DEBUGS(LOG_INV) << "Invalidating category name: " << cat->getName() << " UUID: " << cat->getUUID() << " due to invalid descendents cache" << LL_ENDL; } @@ -2233,9 +2261,9 @@ bool LLInventoryModel::loadSkeleton( // category which successfully cached so that we do not // needlessly fetch descendents for categories which we have. update_map_t::const_iterator no_child_counts = child_counts.end(); - for(cat_set_t::iterator it = temp_cats.begin(); it != temp_cats.end(); ++it) + for (const auto& temp_cat : temp_cats) { - LLViewerInventoryCategory* cat = (*it).get(); + LLViewerInventoryCategory* cat = temp_cat.get(); if(cat->getVersion() != NO_VERSION) { update_map_t::const_iterator the_count = child_counts.find(cat->getUUID()); @@ -2251,7 +2279,7 @@ bool LLInventoryModel::loadSkeleton( } } - if (remove_inventory_file) + if(remove_inventory_file) { // clean up the gunzipped file. LLFile::remove(inventory_filename); @@ -2291,9 +2319,9 @@ void LLInventoryModel::buildParentChildMap() cat_array_t* catsp; item_array_t* itemsp; - for(cat_map_t::iterator cit = mCategoryMap.begin(); cit != mCategoryMap.end(); ++cit) + for (auto& cit : mCategoryMap) { - LLViewerInventoryCategory* cat = cit->second; + LLViewerInventoryCategory* cat = cit.second; cats.push_back(cat); if (mParentChildCategoryTree.count(cat->getUUID()) == 0) { @@ -2382,7 +2410,11 @@ void LLInventoryModel::buildParentChildMap() } // FIXME note that updateServer() fails with protected // types, so this will not work as intended in that case. - cat->updateServer(TRUE); + // UpdateServer uses AIS, AIS cat move is not implemented yet + // cat->updateServer(TRUE); + + // MoveInventoryFolder message, intentionally per item + cat->updateParentOnServer(FALSE); catsp = getUnlockedCatArray(cat->getParentUUID()); if(catsp) { @@ -2404,10 +2436,9 @@ void LLInventoryModel::buildParentChildMap() item_array_t items; if(!mItemMap.empty()) { - LLPointer item; - for(item_map_t::iterator iit = mItemMap.begin(); iit != mItemMap.end(); ++iit) + for (auto& iit : mItemMap) { - item = (*iit).second; + LLPointer item = iit.second; items.push_back(item); } } @@ -2416,8 +2447,7 @@ void LLInventoryModel::buildParentChildMap() uuid_vec_t lost_item_ids; for(i = 0; i < count; ++i) { - LLPointer item; - item = items.at(i); + LLPointer item = items.at(i); itemsp = getUnlockedItemArray(item->getParentUUID()); if(itemsp) { @@ -2466,7 +2496,7 @@ void LLInventoryModel::buildParentChildMap() msg->nextBlockFast(_PREHASH_InventoryData); msg->addUUIDFast(_PREHASH_ItemID, (*it)); msg->addUUIDFast(_PREHASH_FolderID, lnf); - msg->addString("NewName", NULL); + msg->addString("NewName", nullptr); if(msg->isSendFull(NULL)) { start_new_message = TRUE; @@ -2479,16 +2509,16 @@ void LLInventoryModel::buildParentChildMap() } } - const LLUUID& agent_inv_root_id = gInventory.getRootFolderID(); + const LLUUID &agent_inv_root_id = gInventory.getRootFolderID(); if (agent_inv_root_id.notNull()) { cat_array_t* catsp = get_ptr_in_map(mParentChildCategoryTree, agent_inv_root_id); if(catsp) { // *HACK - fix root inventory folder - // some accounts has pbroken inventory root folders + // some accounts has broken inventory root folders - std::string name = "My Inventory"; + static const std::string name = "My Inventory"; LLUUID prev_root_id = mRootFolderID; for (parent_cat_map_t::const_iterator it = mParentChildCategoryTree.begin(), it_end = mParentChildCategoryTree.end(); it != it_end; ++it) @@ -2541,7 +2571,7 @@ void LLInventoryModel::createCommonSystemCategories() struct LLUUIDAndName { - LLUUIDAndName() {} + LLUUIDAndName() = default; LLUUIDAndName(const LLUUID& id, const std::string& name); bool operator==(const LLUUIDAndName& rhs) const; bool operator<(const LLUUIDAndName& rhs) const; @@ -2575,6 +2605,7 @@ bool LLUUIDAndName::operator>(const LLUUIDAndName& rhs) const bool LLInventoryModel::loadFromFile(const std::string& filename, LLInventoryModel::cat_array_t& categories, LLInventoryModel::item_array_t& items, + LLInventoryModel::changed_items_t& cats_to_update, bool &is_cache_obsolete) { if(filename.empty()) @@ -2597,7 +2628,7 @@ bool LLInventoryModel::loadFromFile(const std::string& filename, while(!feof(file) && fgets(buffer, MAX_STRING, file)) { sscanf(buffer, " %126s %126s", keyword, value); /* Flawfinder: ignore */ - if (0 == strcmp("inv_cache_version", keyword)) + if(0 == strcmp("inv_cache_version", keyword)) { S32 version; int succ = sscanf(value,"%d",&version); @@ -2649,7 +2680,14 @@ bool LLInventoryModel::loadFromFile(const std::string& filename, } else { - items.push_back(inv_item); + if (inv_item->getType() == LLAssetType::AT_UNKNOWN) + { + cats_to_update.insert(inv_item->getParentUUID()); + } + else + { + items.push_back(inv_item); + } } } else @@ -2688,8 +2726,7 @@ bool LLInventoryModel::saveToFile(const std::string& filename, return false; } - fprintf(file, "\tinv_cache_version\t%d\n", sCurrentInvCacheVersion); - + fprintf(file, "\tinv_cache_version\t%d\n",sCurrentInvCacheVersion); S32 count = categories.size(); S32 i; for(i = 0; i < count; ++i) @@ -2797,7 +2834,6 @@ bool LLInventoryModel::messageUpdateCore(LLMessageSystem* msg, bool account, U32 item_array_t items; update_map_t update; S32 count = msg->getNumberOfBlocksFast(_PREHASH_InventoryData); - LLUUID folder_id; // Does this loop ever execute more than once? for(S32 i = 0; i < count; ++i) { @@ -2824,10 +2860,6 @@ bool LLInventoryModel::messageUpdateCore(LLMessageSystem* msg, bool account, U32 { ++update[titem->getParentUUID()]; } - if (folder_id.isNull()) - { - folder_id = titem->getParentUUID(); - } } if(account) { @@ -2840,9 +2872,9 @@ bool LLInventoryModel::messageUpdateCore(LLMessageSystem* msg, bool account, U32 mask |= LLInventoryObserver::CREATE; } //as above, this loop never seems to loop more than once per call - for (item_array_t::iterator it = items.begin(); it != items.end(); ++it) + for (auto& item : items) { - changes |= gInventory.updateItem(*it, mask); + changes |= gInventory.updateItem(item, mask); } gInventory.notifyObservers(); gViewerWindow->getWindow()->decBusyCount(); @@ -2874,10 +2906,10 @@ void LLInventoryModel::removeInventoryItem(LLUUID agent_id, LLMessageSystem* msg } } gInventory.accountForUpdate(update); - for(uuid_vec_t::iterator it = item_ids.begin(); it != item_ids.end(); ++it) + for (auto& item_id : item_ids) { - LL_DEBUGS(LOG_INV) << "Calling deleteObject " << *it << LL_ENDL; - gInventory.deleteObject(*it); + LL_DEBUGS(LOG_INV) << "Calling deleteObject " << item_id << LL_ENDL; + gInventory.deleteObject(item_id); } } @@ -2885,7 +2917,7 @@ void LLInventoryModel::removeInventoryItem(LLUUID agent_id, LLMessageSystem* msg void LLInventoryModel::processRemoveInventoryItem(LLMessageSystem* msg, void**) { LL_DEBUGS(LOG_INV) << "LLInventoryModel::processRemoveInventoryItem()" << LL_ENDL; - LLUUID agent_id, item_id; + LLUUID agent_id; msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); if(agent_id != gAgent.getID()) { @@ -2902,7 +2934,7 @@ void LLInventoryModel::processUpdateInventoryFolder(LLMessageSystem* msg, void**) { LL_DEBUGS(LOG_INV) << "LLInventoryModel::processUpdateInventoryFolder()" << LL_ENDL; - LLUUID agent_id, folder_id, parent_id; + LLUUID agent_id; //char name[DB_INV_ITEM_NAME_BUF_SIZE]; msg->getUUIDFast(_PREHASH_FolderData, _PREHASH_AgentID, agent_id); if(agent_id != gAgent.getID()) @@ -2943,9 +2975,9 @@ void LLInventoryModel::processUpdateInventoryFolder(LLMessageSystem* msg, } } gInventory.accountForUpdate(update); - for (cat_array_t::iterator it = folders.begin(); it != folders.end(); ++it) + for (auto& folder : folders) { - gInventory.updateCategory(*it); + gInventory.updateCategory(folder); } gInventory.notifyObservers(); @@ -2958,8 +2990,7 @@ void LLInventoryModel::processUpdateInventoryFolder(LLMessageSystem* msg, } // static -void LLInventoryModel::removeInventoryFolder(LLUUID agent_id, - LLMessageSystem* msg) +void LLInventoryModel::removeInventoryFolder(LLUUID agent_id, LLMessageSystem* msg) { LLUUID folder_id; uuid_vec_t folder_ids; @@ -2976,15 +3007,14 @@ void LLInventoryModel::removeInventoryFolder(LLUUID agent_id, } } gInventory.accountForUpdate(update); - for(uuid_vec_t::iterator it = folder_ids.begin(); it != folder_ids.end(); ++it) + for (auto& folder_id : folder_ids) { - gInventory.deleteObject(*it); + gInventory.deleteObject(folder_id); } } // static -void LLInventoryModel::processRemoveInventoryFolder(LLMessageSystem* msg, - void**) +void LLInventoryModel::processRemoveInventoryFolder(LLMessageSystem* msg, void**) { LL_DEBUGS() << "LLInventoryModel::processRemoveInventoryFolder()" << LL_ENDL; LLUUID agent_id, session_id; @@ -3001,8 +3031,7 @@ void LLInventoryModel::processRemoveInventoryFolder(LLMessageSystem* msg, } // static -void LLInventoryModel::processRemoveInventoryObjects(LLMessageSystem* msg, - void**) +void LLInventoryModel::processRemoveInventoryObjects(LLMessageSystem* msg, void**) { LL_DEBUGS() << "LLInventoryModel::processRemoveInventoryObjects()" << LL_ENDL; LLUUID agent_id, session_id; @@ -3020,8 +3049,7 @@ void LLInventoryModel::processRemoveInventoryObjects(LLMessageSystem* msg, } // static -void LLInventoryModel::processSaveAssetIntoInventory(LLMessageSystem* msg, - void**) +void LLInventoryModel::processSaveAssetIntoInventory(LLMessageSystem* msg, void**) { LLUUID agent_id; msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); @@ -3093,9 +3121,8 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**) update_map_t update; cat_array_t folders; - S32 count; S32 i; - count = msg->getNumberOfBlocksFast(_PREHASH_FolderData); + S32 count = msg->getNumberOfBlocksFast(_PREHASH_FolderData); for(i = 0; i < count; ++i) { LLPointer tfolder = new LLViewerInventoryCategory(gAgent.getID()); @@ -3174,7 +3201,7 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**) if(titem->getUUID().notNull() ) // && callback_id.notNull() ) { items.push_back(titem); - cblist.push_back(InventoryCallbackInfo(callback_id, titem->getUUID())); + cblist.emplace_back(callback_id, titem->getUUID()); if (titem->getInventoryType() == LLInventoryType::IT_WEARABLE) { wearable_ids.push_back(titem->getUUID()); @@ -3204,18 +3231,18 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**) } else { - cblist.push_back(InventoryCallbackInfo(callback_id, LLUUID::null)); + cblist.emplace_back(callback_id, LLUUID::null); } } gInventory.accountForUpdate(update); - for (cat_array_t::iterator cit = folders.begin(); cit != folders.end(); ++cit) + for (auto& folder : folders) { - gInventory.updateCategory(*cit); + gInventory.updateCategory(folder); } - for (item_array_t::iterator iit = items.begin(); iit != items.end(); ++iit) + for (auto& item : items) { - gInventory.updateItem(*iit); + gInventory.updateItem(item); } gInventory.notifyObservers(); @@ -3233,23 +3260,21 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**) count = wearable_ids.size(); for (i = 0; i < count; ++i) { - LLViewerInventoryItem* wearable_item; - wearable_item = gInventory.getItem(wearable_ids[i]); + LLViewerInventoryItem * wearable_item = gInventory.getItem(wearable_ids[i]); LLAppearanceMgr::instance().wearItemOnAvatar(wearable_item->getUUID(), true, true); } } - std::list::iterator inv_it; - for (inv_it = cblist.begin(); inv_it != cblist.end(); ++inv_it) + for (auto& inv_it : cblist) { - InventoryCallbackInfo cbinfo = (*inv_it); + InventoryCallbackInfo cbinfo = inv_it; gInventoryCallbacks.fire(cbinfo.mCallback, cbinfo.mInvID); } //gInventory.validate(); // Don't show the inventory. We used to call showAgentInventory here. - //LLPanelMainInventory* view = LLPanelMainInventory::getActiveInventory(); + //LLFloaterInventory* view = LLFloaterInventory::getActiveInventory(); //if(view) //{ // const BOOL take_keyboard_focus = FALSE; @@ -3259,10 +3284,10 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**) // // HACK to open inventory offers that are accepted. This information // // really needs to flow through the instant messages and inventory // // transfer/update messages. - // if (LLPanelMainInventory::sOpenNextNewItem) + // if (LLFloaterInventory::sOpenNextNewItem) // { // view->openSelected(); - // LLPanelMainInventory::sOpenNextNewItem = FALSE; + // LLFloaterInventory::sOpenNextNewItem = FALSE; // } // // // restore keyboard focus @@ -3393,7 +3418,7 @@ bool LLInventoryModel::callbackEmptyFolderType(const LLSD& notification, const L if (option == 0) // YES { const LLUUID folder_id = findCategoryUUIDForType(preferred_type); - purge_descendents_of(folder_id, NULL); + purge_descendents_of(folder_id, nullptr); } return false; } @@ -3408,7 +3433,7 @@ void LLInventoryModel::emptyFolderType(const std::string notification, LLFolderT else { const LLUUID folder_id = findCategoryUUIDForType(preferred_type); - purge_descendents_of(folder_id, NULL); + purge_descendents_of(folder_id, nullptr); } } @@ -3470,6 +3495,11 @@ void LLInventoryModel::removeCategory(const LLUUID& category_id) void LLInventoryModel::removeObject(const LLUUID& object_id) { + if(object_id.isNull()) + { + return; + } + LLInventoryObject* obj = getObject(object_id); if (dynamic_cast(obj)) { @@ -3664,9 +3694,9 @@ void LLInventoryModel::dumpInventory() const { LL_INFOS() << "\nBegin Inventory Dump\n**********************:" << LL_ENDL; LL_INFOS() << "mCategory[] contains " << mCategoryMap.size() << " items." << LL_ENDL; - for(cat_map_t::const_iterator cit = mCategoryMap.begin(); cit != mCategoryMap.end(); ++cit) + for (const auto& cit : mCategoryMap) { - const LLViewerInventoryCategory* cat = cit->second; + const LLViewerInventoryCategory* cat = cit.second; if(cat) { LL_INFOS() << " " << cat->getUUID() << " '" << cat->getName() << "' " @@ -3680,9 +3710,9 @@ void LLInventoryModel::dumpInventory() const } } LL_INFOS() << "mItemMap[] contains " << mItemMap.size() << " items." << LL_ENDL; - for(item_map_t::const_iterator iit = mItemMap.begin(); iit != mItemMap.end(); ++iit) + for (const auto& iit : mItemMap) { - const LLViewerInventoryItem* item = iit->second; + const LLViewerInventoryItem* item = iit.second; if(item) { LL_INFOS() << " " << item->getUUID() << " " @@ -3724,10 +3754,10 @@ bool LLInventoryModel::validate() const S32 item_lock = 0; S32 desc_unknown_count = 0; S32 version_unknown_count = 0; - for(cat_map_t::const_iterator cit = mCategoryMap.begin(); cit != mCategoryMap.end(); ++cit) + for (const auto& cit : mCategoryMap) { - const LLUUID& cat_id = cit->first; - const LLViewerInventoryCategory *cat = cit->second; + const LLUUID& cat_id = cit.first; + const LLViewerInventoryCategory *cat = cit.second; if (!cat) { LL_WARNS() << "invalid cat" << LL_ENDL; @@ -3861,9 +3891,9 @@ bool LLInventoryModel::validate() const else { bool found = false; - for (U32 i = 0; isize(); i++) + for (auto& i : *cats) { - LLViewerInventoryCategory *kid_cat = cats->at(i); + LLViewerInventoryCategory *kid_cat = i; if (kid_cat == cat) { found = true; @@ -3879,10 +3909,10 @@ bool LLInventoryModel::validate() const } } - for(item_map_t::const_iterator iit = mItemMap.begin(); iit != mItemMap.end(); ++iit) + for (const auto& iit : mItemMap) { - const LLUUID& item_id = iit->first; - LLViewerInventoryItem *item = iit->second; + const LLUUID& item_id = iit.first; + LLViewerInventoryItem *item = iit.second; if (item->getUUID() != item_id) { LL_WARNS() << "item_id " << item_id << " does not match " << item->getUUID() << LL_ENDL; @@ -3907,9 +3937,9 @@ bool LLInventoryModel::validate() const else { bool found = false; - for (U32 i=0; isize(); ++i) + for (auto& i : *items) { - if (items->at(i) == item) + if (i == item) { found = true; break; @@ -4010,7 +4040,7 @@ BOOL decompress_file(const char* src_filename, const char* dst_filename) S32 bytes = 0; const S32 DECOMPRESS_BUFFER_SIZE = 32000; - // open the files +// open the files #if LL_WINDOWS src = gzopen_w(utf8str_to_utf16str(src_filename).c_str(), "rb"); #else @@ -4020,7 +4050,7 @@ BOOL decompress_file(const char* src_filename, const char* dst_filename) dst = LLFile::fopen(dst_filename, "wb"); if(!dst) goto err_decompress; - // decompress. +// decompress. buffer = new U8[DECOMPRESS_BUFFER_SIZE + 1]; do @@ -4034,7 +4064,7 @@ BOOL decompress_file(const char* src_filename, const char* dst_filename) fwrite(buffer, bytes, 1, dst); } while(gzeof(src) == 0); - // success +// success rv = TRUE; err_decompress: @@ -4082,7 +4112,7 @@ void LLInventoryModel::FetchItemHttpHandler::httpSuccess() if (itemp) { - if(titem->getParentUUID() == itemp->getParentUUID()) + if (titem->getParentUUID() == itemp->getParentUUID()) { update[titem->getParentUUID()]; } @@ -4105,9 +4135,9 @@ void LLInventoryModel::FetchItemHttpHandler::httpSuccess() // as above, this loop never seems to loop more than once per call U32 changes(0U); - for (LLInventoryModel::item_array_t::iterator it = items.begin(); it != items.end(); ++it) + for (auto& item : items) { - changes |= gInventory.updateItem(*it); + changes |= gInventory.updateItem(item); } // *HUH: Have computed 'changes', nothing uses it. diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index f8c5e81f3..d81fe7b97 100644 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -192,14 +192,14 @@ private: **/ //-------------------------------------------------------------------- - // Descendents + // Descendants //-------------------------------------------------------------------- public: - // Make sure we have the descendents in the structure. Returns true + // Make sure we have the descendants in the structure. Returns true // if a fetch was performed. bool fetchDescendentsOf(const LLUUID& folder_id) const; - // Return the direct descendents of the id provided.Set passed + // Return the direct descendants of the id provided.Set passed // in values to NULL if the call fails. // NOTE: The array provided points straight into the guts of // this object, and should only be used for read operations, since @@ -211,10 +211,10 @@ public: void getDirectDescendentsOf(const LLUUID& cat_id, cat_array_t*& categories) const; - // Compute a hash of direct descendent names (for detecting child name changes) + // Compute a hash of direct descendant names (for detecting child name changes) LLMD5 hashDirectDescendentNames(const LLUUID& cat_id) const; - // Starting with the object specified, add its descendents to the + // Starting with the object specified, add its descendants to the // array provided, but do not add the inventory object specified // by id. There is no guaranteed order. // NOTE: Neither array will be erased before adding objects to it. @@ -340,7 +340,7 @@ public: U32 updateItem(const LLViewerInventoryItem* item, U32 mask = 0); // Change an existing item with the matching id or add - // the category. No notifcation will be sent to observers. This + // the category. No notification will be sent to observers. This // method will only generate network traffic if the item had to be // reparented. // NOTE: In usage, you will want to perform cache accounting @@ -378,7 +378,7 @@ public: bool update_parent_version = true, bool do_notify_observers = true); - // Update model after all descendents removed from server. + // Update model after all descendants removed from server. void onDescendentsPurgedFromServer(const LLUUID& object_id, bool fix_broken_links = true); // Update model after an existing item gets updated on server. @@ -499,10 +499,12 @@ public: // Call to explicitly update everyone on a new state. void notifyObservers(); + // Allows outsiders to tell the inventory if something has // been changed 'under the hood', but outside the control of the // inventory. The next notify will include that notification. void addChangedMask(U32 mask, const LLUUID& referent); + const changed_items_t& getChangedIDs() const { return mChangedItemIDs; } const changed_items_t& getAddedIDs() const { return mAddedItemIDs; } protected: @@ -556,6 +558,7 @@ protected: static bool loadFromFile(const std::string& filename, cat_array_t& categories, item_array_t& items, + changed_items_t& cats_to_update, bool& is_cache_obsolete); static bool saveToFile(const std::string& filename, const cat_array_t& categories, diff --git a/indra/newview/lllandmarkactions.cpp b/indra/newview/lllandmarkactions.cpp index ba1ba95b5..7652164d9 100644 --- a/indra/newview/lllandmarkactions.cpp +++ b/indra/newview/lllandmarkactions.cpp @@ -289,6 +289,7 @@ LLVector3d getRegionPosFromGlobalPos(const LLVector3d& global_pos, const LLSimIn LLVector3d local_pos; local_pos[0] = fmod(global_pos[0], siminfo ? siminfo->getSizeX() : 256); local_pos[1] = fmod(global_pos[1], siminfo ? siminfo->getSizeY() : 256); + local_pos[2] = global_pos[2]; return local_pos; } diff --git a/indra/newview/llmarketplacefunctions.cpp b/indra/newview/llmarketplacefunctions.cpp index a42e19c48..5234efbac 100644 --- a/indra/newview/llmarketplacefunctions.cpp +++ b/indra/newview/llmarketplacefunctions.cpp @@ -281,8 +281,12 @@ public: std::string body; decode_raw_body(channels, buffer, body); - auto json = nlohmann::json::parse(body); - LLSD result = LlsdFromJson(json);; + LLSD result = LlsdFromJsonString(body); + if (result.isUndefined()) + { + log_SLM_warning("Get /listings", getStatus(), getReason(), LLStringUtil::null, "Empty or Invalid JSON Response"); + return; + } if (!isGoodStatus(mStatus)) { @@ -342,8 +346,12 @@ public: std::string body; decode_raw_body(channels, buffer, body); - auto json = nlohmann::json::parse(body); - LLSD result = LlsdFromJson(json);; + LLSD result = LlsdFromJsonString(body); + if (result.isUndefined()) + { + log_SLM_warning("Post /listings", getStatus(), getReason(), LLStringUtil::null, "Empty or Invalid JSON Response"); + return; + } if (!isGoodStatus(mStatus)) { @@ -396,8 +404,12 @@ public: std::string body; decode_raw_body(channels, buffer, body); - auto json = nlohmann::json::parse(body); - LLSD result = LlsdFromJson(json); + LLSD result = LlsdFromJsonString(body); + if (result.isUndefined()) + { + log_SLM_warning("Get /listing", getStatus(), getReason(), LLStringUtil::null, "Empty or Invalid JSON Response"); + return; + } if (!isGoodStatus(mStatus)) { @@ -469,8 +481,12 @@ public: std::string body; decode_raw_body(channels, buffer, body); - auto json = nlohmann::json::parse(body); - LLSD result = LlsdFromJson(json); + LLSD result = LlsdFromJsonString(body); + if (result.isUndefined()) + { + log_SLM_warning("Put /listing", getStatus(), getReason(), LLStringUtil::null, "Empty or Invalid JSON Response"); + return; + } if (!isGoodStatus(mStatus)) { @@ -543,8 +559,12 @@ public: std::string body; decode_raw_body(channels, buffer, body); - auto json = nlohmann::json::parse(body); - LLSD result = LlsdFromJson(json); + LLSD result = LlsdFromJsonString(body); + if (result.isUndefined()) + { + log_SLM_warning("Put /associate_inventory", getStatus(), getReason(), LLStringUtil::null, "Empty or Invalid JSON Response"); + return; + } if (!isGoodStatus(mStatus)) { @@ -612,8 +632,12 @@ public: std::string body; decode_raw_body(channels, buffer, body); - auto json = nlohmann::json::parse(body); - LLSD result = LlsdFromJson(json); + LLSD result = LlsdFromJsonString(body); + if (result.isUndefined()) + { + log_SLM_warning("Delete /listing", getStatus(), getReason(), LLStringUtil::null, "Empty or Invalid JSON Response"); + return; + } if (!isGoodStatus(mStatus)) { @@ -1245,7 +1269,7 @@ void LLMarketplaceData::initializeSLM(const status_updated_signal_t::slot_type& } log_SLM_infos("LLHTTPClient::get", url, LLStringUtil::null); - LLHTTPClient::get(url, LLSD(), new LLSLMGetMerchantResponder); + LLHTTPClient::get(url, new LLSLMGetMerchantResponder); } void LLMarketplaceData::setDataFetchedSignal(const status_updated_signal_t::slot_type& cb) diff --git a/indra/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp index df5c51194..fe5b50253 100644 --- a/indra/newview/llmediactrl.cpp +++ b/indra/newview/llmediactrl.cpp @@ -207,7 +207,10 @@ BOOL LLMediaCtrl::handleScrollWheel( S32 x, S32 y, S32 clicks ) { if (LLPanel::handleScrollWheel(x, y, clicks)) return TRUE; if (mMediaSource && mMediaSource->hasMedia()) - mMediaSource->getMediaPlugin()->scrollEvent(0, clicks, gKeyboard->currentMask(TRUE)); + { + convertInputCoords(x, y); + mMediaSource->scrollWheel(x, y, 0, clicks, gKeyboard->currentMask(TRUE)); + } return TRUE; } diff --git a/indra/newview/llmenucommands.cpp b/indra/newview/llmenucommands.cpp index ae140fa2f..b572062a8 100644 --- a/indra/newview/llmenucommands.cpp +++ b/indra/newview/llmenucommands.cpp @@ -64,6 +64,7 @@ #include "llfloaterdisplayname.h" #include "llfloatereditui.h" #include "llfloaterenvsettings.h" +#include "llfloaterexperiences.h" #include "llfloaterexploreanimations.h" #include "llfloaterexploresounds.h" #include "llfloaterfonttest.h" @@ -119,6 +120,7 @@ void handle_debug_avatar_textures(void*); template void handle_singleton_toggle(void*); void show_outfit_dialog() { new LLMakeOutfitDialog(false); } +class LLFloaterExperiencePicker* show_xp_picker(const LLSD& key); void toggle_build() { LLToolMgr::getInstance()->toggleBuildMode(); } void toggle_control(const std::string& name) { if (LLControlVariable* control = gSavedSettings.getControl(name)) control->set(!control->get()); } void toggle_search_floater(); @@ -126,7 +128,7 @@ void toggle_always_run() { gAgent.getAlwaysRun() ? gAgent.clearAlwaysRun() : gAg void toggle_sit(); void toggle_mouselook() { gAgentCamera.cameraMouselook() ? gAgentCamera.changeCameraToDefault() : gAgentCamera.changeCameraToMouselook(); } -bool is_visible_view(boost::function get) +bool is_visible_view(std::function get) { if (LLView* v = get()) return v->getVisible(); @@ -146,7 +148,7 @@ struct CommWrapper struct MenuFloaterDict : public LLSingleton { - typedef std::map, boost::function > > menu_floater_map_t; + typedef std::map, std::function > > menu_floater_map_t; menu_floater_map_t mEntries; MenuFloaterDict() @@ -162,7 +164,7 @@ struct MenuFloaterDict : public LLSingleton registerConsole("texture size console", gTextureSizeView); } registerConsole("velocity", gVelocityBar); - registerFloater("about", boost::bind(&LLFloaterAbout::show,(void*)NULL)); + registerFloater("about", boost::bind(&LLFloaterAbout::show,nullptr)); registerFloater("always run", boost::bind(toggle_always_run), boost::bind(&LLAgent::getAlwaysRun, &gAgent)); registerFloater("anims_explorer", boost::bind(LLFloaterExploreAnimations::show)); registerFloater("appearance", boost::bind(LLFloaterCustomize::show)); @@ -172,37 +174,38 @@ struct MenuFloaterDict : public LLSingleton registerFloater("buy land", boost::bind(&LLViewerParcelMgr::startBuyLand, boost::bind(LLViewerParcelMgr::getInstance), false)); registerFloater("complaint reporter", boost::bind(LLFloaterReporter::showFromMenu, COMPLAINT_REPORT)); registerFloater("DayCycle", boost::bind(LLFloaterDayCycle::show), boost::bind(LLFloaterDayCycle::isOpen)); - registerFloater("debug avatar", boost::bind(handle_debug_avatar_textures, (void*)NULL)); - registerFloater("debug settings", boost::bind(handle_singleton_toggle, (void*)NULL)); - registerFloater("edit ui", boost::bind(LLFloaterEditUI::show, (void*)NULL)); + registerFloater("debug avatar", boost::bind(handle_debug_avatar_textures, nullptr)); + registerFloater("debug settings", boost::bind(handle_singleton_toggle, nullptr)); + registerFloater("edit ui", boost::bind(LLFloaterEditUI::show, nullptr)); registerFloater("EnvSettings", boost::bind(LLFloaterEnvSettings::show), boost::bind(LLFloaterEnvSettings::isOpen)); + registerFloater("experience_search", boost::bind(show_xp_picker, LLSD())); registerFloater("fly", boost::bind(LLAgent::toggleFlying)); - registerFloater("font test", boost::bind(LLFloaterFontTest::show, (void*)NULL)); - registerFloater("god tools", boost::bind(LLFloaterGodTools::show, (void*)NULL)); - registerFloater("grid options", boost::bind(LLFloaterBuildOptions::show, (void*)NULL)); + registerFloater("font test", boost::bind(LLFloaterFontTest::show, nullptr)); + registerFloater("god tools", boost::bind(LLFloaterGodTools::show, nullptr)); + registerFloater("grid options", boost::bind(LLFloaterBuildOptions::show, nullptr)); registerFloater("group titles", boost::bind(HBFloaterGroupTitles::toggle)); //Singu TODO: Re-implement f1 help. //registerFloater("help f1", boost::bind(/*gViewerHtmlHelp.show*/)); registerFloater("help tutorial", boost::bind(LLFloaterHUD::showHUD)); - registerFloater("inventory", boost::bind(LLPanelMainInventory::toggleVisibility, (void*)NULL), boost::bind(is_visible_view, static_cast >(LLPanelMainInventory::getActiveInventory))); + registerFloater("inventory", boost::bind(LLPanelMainInventory::toggleVisibility, nullptr), boost::bind(is_visible_view, static_cast >(LLPanelMainInventory::getActiveInventory))); registerFloater("local assets", boost::bind(FloaterLocalAssetBrowser::show, (void*)0)); - registerFloater("mean events", boost::bind(LLFloaterBump::show, (void*)NULL)); - registerFloater("media ticker", boost::bind(handle_ticker_toggle, (void*)NULL), boost::bind(SHFloaterMediaTicker::instanceExists)); - registerFloater("memleak", boost::bind(LLFloaterMemLeak::show, (void*)NULL)); + registerFloater("mean events", boost::bind(LLFloaterBump::show, nullptr)); + registerFloater("media ticker", boost::bind(handle_ticker_toggle, nullptr), boost::bind(SHFloaterMediaTicker::instanceExists)); + registerFloater("memleak", boost::bind(LLFloaterMemLeak::show, nullptr)); registerFloater("messagelog", boost::bind(LLFloaterMessageLog::show)); registerFloater("mouselook", boost::bind(toggle_mouselook)); - registerFloater("my land", boost::bind(LLFloaterLandHoldings::show, (void*)NULL)); + registerFloater("my land", boost::bind(LLFloaterLandHoldings::show, nullptr)); registerFloater("outfit", boost::bind(show_outfit_dialog)); - registerFloater("preferences", boost::bind(LLFloaterPreference::show, (void*)NULL)); + registerFloater("preferences", boost::bind(LLFloaterPreference::show, nullptr)); registerFloater("quit", boost::bind(&LLAppViewer::userQuit, LLAppViewer::instance())); - registerFloater("RegionDebugConsole", boost::bind(handle_singleton_toggle, (void*)NULL), boost::bind(LLFloaterRegionDebugConsole::instanceExists)); + registerFloater("RegionDebugConsole", boost::bind(handle_singleton_toggle, nullptr), boost::bind(LLFloaterRegionDebugConsole::instanceExists)); registerFloater("script errors", boost::bind(LLFloaterScriptDebug::show, LLUUID::null)); registerFloater("search", boost::bind(toggle_search_floater)); registerFloater("show inspect", boost::bind(LLFloaterInspect::showInstance, LLSD())); registerFloater("sit", boost::bind(toggle_sit)); - registerFloater("snapshot", boost::bind(LLFloaterSnapshot::show, (void*)NULL)); + registerFloater("snapshot", boost::bind(LLFloaterSnapshot::show, nullptr)); registerFloater("sound_explorer", boost::bind(LLFloaterExploreSounds::toggle), boost::bind(LLFloaterExploreSounds::visible)); - registerFloater("test", boost::bind(LLFloaterTest::show, (void*)NULL)); + registerFloater("test", boost::bind(LLFloaterTest::show, nullptr)); // Phoenix: Wolfspirit: Enabled Show Floater out of viewer menu registerFloater("WaterSettings", boost::bind(LLFloaterWater::show), boost::bind(LLFloaterWater::isOpen)); registerFloater("Windlight", boost::bind(LLFloaterWindLight::show), boost::bind(LLFloaterWindLight::isOpen)); @@ -220,6 +223,7 @@ struct MenuFloaterDict : public LLSingleton registerFloater ("communicate"); registerFloater ("destinations"); registerFloater ("displayname"); + registerFloater ("experiences"); registerFloater ("friends", 0); registerFloater ("gestures"); registerFloater ("groups", 1); @@ -248,12 +252,13 @@ struct MenuFloaterDict : public LLSingleton registerFloater("rlv strings"); // [/RLVa:LF] } +public: template void registerConsole(const std::string& name, T* console) { registerFloater(name, boost::bind(&T::setVisible, console, !boost::bind(&T::getVisible, console)), boost::bind(&T::getVisible, console)); } - void registerFloater(const std::string& name, boost::function show, boost::function visible = NULL) + void registerFloater(const std::string& name, std::function show, std::function visible = nullptr) { mEntries.insert( std::make_pair( name, std::make_pair( show, visible ) ) ); } diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 55901ea85..f621f3b6b 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -1916,7 +1916,7 @@ S32 LLMeshRepository::getActualMeshLOD(LLSD& header, S32 lod) { lod = llclamp(lod, 0, 3); - S32 version = header["version"]; + S32 version = header["version"].asInteger(); if (header.has("404") || version > MAX_MESH_VERSION) { diff --git a/indra/newview/llnamebox.cpp b/indra/newview/llnamebox.cpp index 28a465a57..d20e5429f 100644 --- a/indra/newview/llnamebox.cpp +++ b/indra/newview/llnamebox.cpp @@ -37,11 +37,22 @@ static LLRegisterWidget r("name_box"); -LLNameBox::LLNameBox(const std::string& name) -: LLNameUI() +LLNameBox::LLNameBox(const std::string& name, + const LLUUID& name_id, + const Type& type, + const std::string& loading, + bool rlv_sensitive, + const std::string& name_system, + bool click_for_profile) +: LLNameUI(loading, rlv_sensitive, name_id, type, name_system, click_for_profile) , LLTextBox(name, LLRect(), LLStringUtil::null, nullptr, TRUE) { setClickedCallback(boost::bind(&LLNameUI::showProfile, this)); + if (!name_id.isNull()) + { + setNameID(name_id, type); + } + else setText(mInitialValue); } void LLNameBox::displayAsLink(bool link) @@ -57,10 +68,9 @@ BOOL LLNameBox::handleRightMouseDown(S32 x, S32 y, MASK mask) auto handled = LLTextBox::handleRightMouseDown(x, y, mask); if (mAllowInteract && !handled) { - // Singu TODO: Generic menus for groups - if (!mIsGroup && mNameID.notNull()) + if (mNameID.notNull()) { - showMenu(this, sMenus[0], x, y); + showMenu(this, sMenus[getSelectedType()], x, y); handled = true; } } @@ -71,7 +81,7 @@ BOOL LLNameBox::handleRightMouseDown(S32 x, S32 y, MASK mask) BOOL LLNameBox::handleHover(S32 x, S32 y, MASK mask) { auto handled = LLTextBox::handleHover(x, y, mask); - if (mAllowInteract) + if (mClickForProfile && mAllowInteract) { getWindow()->setCursor(UI_CURSOR_HAND); handled = true; @@ -80,19 +90,36 @@ BOOL LLNameBox::handleHover(S32 x, S32 y, MASK mask) } // virtual -void LLNameBox::initFromXML(LLXMLNodePtr node, LLView* parent) +LLXMLNodePtr LLNameBox::getXML(bool save_children) const { - LLTextBox::initFromXML(node, parent); - node->getAttributeString("initial_value", mInitialValue); - setText(mInitialValue); - node->getAttribute_bool("rlv_sensitive", mRLVSensitive); - node->getAttribute_bool("is_group", mIsGroup); + LLXMLNodePtr node = LLTextBox::getXML(); + + node->setName("name_box"); + node->createChild("initial_value", TRUE)->setStringValue(mInitialValue); + node->createChild("rlv_sensitive", TRUE)->setBoolValue(mRLVSensitive); + node->createChild("click_for_profile", TRUE)->setBoolValue(mClickForProfile); + node->createChild("name_system", TRUE)->setStringValue(mNameSystem); + + return node; } // static LLView* LLNameBox::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) { - LLNameBox* name_box = new LLNameBox("name_box"); + S8 type = AVATAR; + node->getAttributeS8("id_type", type); + LLUUID id; + node->getAttributeUUID("id", id); + std::string loading; + node->getAttributeString("initial_value", loading); + bool rlv_sensitive = false; + node->getAttribute_bool("rlv_sensitive", rlv_sensitive); + std::string name_system; + node->getAttributeString("name_system", name_system); + bool click_for_profile = true; + node->getAttribute_bool("click_for_profile", click_for_profile); + LLNameBox* name_box = new LLNameBox("name_box", id, (Type)type, loading, rlv_sensitive, name_system, click_for_profile); name_box->initFromXML(node,parent); + return name_box; } diff --git a/indra/newview/llnamebox.h b/indra/newview/llnamebox.h index 52992d0eb..f27d6bbff 100644 --- a/indra/newview/llnamebox.h +++ b/indra/newview/llnamebox.h @@ -36,12 +36,12 @@ #include "llnameui.h" #include "lltextbox.h" -class LLNameBox +class LLNameBox final : public LLTextBox , public LLNameUI { public: - virtual void initFromXML(LLXMLNodePtr node, LLView* parent); + LLXMLNodePtr getXML(bool save_children = true) const override final; static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); void displayAsLink(bool link) override final; @@ -49,13 +49,18 @@ public: void setValue(const LLSD& value) override final { LLNameUI::setValue(value); } LLSD getValue() const override final { return LLNameUI::getValue(); } + BOOL handleMouseDown(S32 x, S32 y, MASK mask) override final { return mClickForProfile && mAllowInteract && LLTextBox::handleMouseDown(x, y, mask); } + BOOL handleMouseUp(S32 x, S32 y, MASK mask) override final { return mClickForProfile && mAllowInteract && LLTextBox::handleMouseUp(x, y, mask); } BOOL handleRightMouseDown(S32 x, S32 y, MASK mask) override final; BOOL handleHover(S32 x, S32 y, MASK mask) override final; -protected: - LLNameBox(const std::string& name); - - friend class LLUICtrlFactory; + LLNameBox(const std::string& name, + const LLUUID& name_id = LLUUID::null, + const Type& type = AVATAR, + const std::string& loading = LLStringUtil::null, + bool rlv_sensitive = false, + const std::string& name_system = LLStringUtil::null, + bool click_for_profile = false); }; #endif diff --git a/indra/newview/llnameeditor.cpp b/indra/newview/llnameeditor.cpp index e69161cbe..7a10ae3ff 100644 --- a/indra/newview/llnameeditor.cpp +++ b/indra/newview/llnameeditor.cpp @@ -42,19 +42,19 @@ static LLRegisterWidget r("name_editor"); LLNameEditor::LLNameEditor(const std::string& name, const LLRect& rect, const LLUUID& name_id, - bool is_group, + const Type& type, const std::string& loading, bool rlv_sensitive, + const std::string& name_system, bool click_for_profile, const LLFontGL* glfont, S32 max_text_length) -: LLNameUI(loading, rlv_sensitive, name_id, is_group) +: LLNameUI(loading, rlv_sensitive, name_id, type, name_system, click_for_profile) , LLLineEditor(name, rect, LLStringUtil::null, glfont, max_text_length) -, mClickForProfile(click_for_profile) { if (!name_id.isNull()) { - setNameID(name_id, is_group); + setNameID(name_id, type); } else setText(mInitialValue); } @@ -75,18 +75,17 @@ BOOL LLNameEditor::handleRightMouseDown(S32 x, S32 y, MASK mask) { bool simple_menu = mContextMenuHandle.get()->getName() == "rclickmenu"; std::string new_menu; - // Singu TODO: Generic menus for groups - bool needs_simple = mIsGroup || !mAllowInteract || mNameID.isNull(); // Need simple if no ID or blocking interaction + bool needs_simple = !mAllowInteract || mNameID.isNull(); // Need simple if no ID or blocking interaction if (!simple_menu && needs_simple) // Switch to simple menu { new_menu = "menu_texteditor.xml"; } - else if (!needs_simple && simple_menu) + else // TODO: This is lazy, but I cannot recall a name editor that switches between group and avatar, so logic is not needed yet. { - new_menu = "menu_nameeditor_avatar.xml"; + new_menu = mType == GROUP ? "menu_nameeditor_group.xml" : "menu_nameeditor_avatar.xml"; } if (!new_menu.empty()) setContextMenu(LLUICtrlFactory::instance().buildMenu(new_menu, LLMenuGL::sMenuContainer)); - sActive = this; + setActive(); return LLLineEditor::handleRightMouseDown(x, y, mask); } @@ -124,6 +123,7 @@ LLXMLNodePtr LLNameEditor::getXML(bool save_children) const node->createChild("label", TRUE)->setStringValue(mInitialValue); node->createChild("rlv_sensitive", TRUE)->setBoolValue(mRLVSensitive); node->createChild("click_for_profile", TRUE)->setBoolValue(mClickForProfile); + node->createChild("name_system", TRUE)->setStringValue(mNameSystem); return node; } @@ -135,8 +135,8 @@ LLView* LLNameEditor::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory S32 max_text_length = 1024; node->getAttributeS32("max_length", max_text_length); - bool is_group = false; - node->getAttribute_bool("is_group", is_group); + S8 type = AVATAR; + node->getAttributeS8("id_type", type); LLUUID id; node->getAttributeUUID("id", id); std::string loading; @@ -145,10 +145,12 @@ LLView* LLNameEditor::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory node->getAttribute_bool("rlv_sensitive", rlv_sensitive); bool click_for_profile = true; node->getAttribute_bool("click_for_profile", click_for_profile); + std::string name_system; + node->getAttributeString("name_system", name_system); LLNameEditor* line_editor = new LLNameEditor("name_editor", rect, - id, is_group, loading, rlv_sensitive, + id, (Type)type, loading, rlv_sensitive, name_system, click_for_profile, LLView::selectFont(node), max_text_length); diff --git a/indra/newview/llnameeditor.h b/indra/newview/llnameeditor.h index 3453906c2..aa6133612 100644 --- a/indra/newview/llnameeditor.h +++ b/indra/newview/llnameeditor.h @@ -36,17 +36,17 @@ #include "lllineeditor.h" #include "llnameui.h" -class LLNameEditor +class LLNameEditor final : public LLLineEditor , public LLNameUI { - bool mClickForProfile; public: LLNameEditor(const std::string& name, const LLRect& rect, const LLUUID& name_id = LLUUID::null, - bool is_group = false, + const Type& type = AVATAR, const std::string& loading = LLStringUtil::null, bool rlv_sensitive = false, + const std::string& name_system = LLStringUtil::null, bool click_for_profile = true, const LLFontGL* glfont = nullptr, S32 max_text_length = 254); diff --git a/indra/newview/llnamelistctrl.cpp b/indra/newview/llnamelistctrl.cpp index cf9e47390..f19520b01 100644 --- a/indra/newview/llnamelistctrl.cpp +++ b/indra/newview/llnamelistctrl.cpp @@ -34,9 +34,11 @@ #include "llcachename.h" #include "llagent.h" #include "llavataractions.h" +#include "llfloaterexperienceprofile.h" #include "llgroupactions.h" #include "llinventory.h" #include "llscrolllistitem.h" +#include "llscrolllistcell.h" #include "llscrolllistcolumn.h" #include "llsdparam.h" #include "lltrans.h" @@ -49,6 +51,7 @@ void LLNameListItem::NameTypeNames::declareValues() declare("INDIVIDUAL", INDIVIDUAL); declare("GROUP", GROUP); declare("SPECIAL", SPECIAL); + declare("EXPERIENCE", EXPERIENCE); } LLNameListCtrl::LLNameListCtrl(const std::string& name, const LLRect& rect, BOOL allow_multiple_selection, BOOL draw_border, bool draw_heading, S32 name_column_index, const std::string& name_system, const std::string& tooltip) @@ -134,6 +137,7 @@ BOOL LLNameListCtrl::handleDoubleClick(S32 x, S32 y, MASK mask) { case LLNameListItem::INDIVIDUAL: LLAvatarActions::showProfile(item->getValue()); break; case LLNameListItem::GROUP: LLGroupActions::show(item->getValue()); break; + case LLNameListItem::EXPERIENCE: LLFloaterExperienceProfile::showInstance(item->getValue()); break; default: return false; } handled = true; @@ -142,6 +146,33 @@ BOOL LLNameListCtrl::handleDoubleClick(S32 x, S32 y, MASK mask) return handled; } +#define CONVERT_TO_RETTYPE(nametype, rettype) \ +nametype: \ +{ \ + if (ret == NONE) \ + ret = rettype; \ + else if (ret != rettype) \ + return MULTIPLE; \ + break; \ +} + +LFIDBearer::Type LLNameListCtrl::getSelectedType() const +{ + auto ret = NONE; + for (const auto& item : getAllSelected()) + { + switch (static_cast(item)->getNameType()) + { + CONVERT_TO_RETTYPE(case LLNameListItem::INDIVIDUAL, AVATAR) + CONVERT_TO_RETTYPE(case LLNameListItem::GROUP, GROUP) + CONVERT_TO_RETTYPE(case LLNameListItem::EXPERIENCE, EXPERIENCE) + CONVERT_TO_RETTYPE(default, COUNT) // Invalid, but just use count instead + } + } + return ret; +} +#undef CONVERT_TO_RETTYPE + // public void LLNameListCtrl::addGroupNameItem(const LLUUID& group_id, EAddPosition pos, BOOL enabled) @@ -186,7 +217,7 @@ LLScrollListItem* LLNameListCtrl::addNameItemRow( LLUUID id = name_item.value().asUUID(); LLNameListItem* item = new LLNameListItem(name_item); - if (!item) return NULL; + if (!item) return nullptr; LLScrollListCtrl::addRow(item, name_item, pos); @@ -251,6 +282,8 @@ LLScrollListItem* LLNameListCtrl::addNameItemRow( } break; } + case LLNameListItem::EXPERIENCE: + // just use supplied name default: break; } @@ -435,13 +468,13 @@ LLView* LLNameListCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFacto LLRect rect; createRect(node, rect, parent, LLRect()); - BOOL multi_select = FALSE; + BOOL multi_select = false; node->getAttributeBOOL("multi_select", multi_select); - BOOL draw_border = TRUE; + BOOL draw_border = true; node->getAttributeBOOL("draw_border", draw_border); - BOOL draw_heading = FALSE; + BOOL draw_heading = false; node->getAttributeBOOL("draw_heading", draw_heading); S32 name_column_index = 0; @@ -468,108 +501,5 @@ LLView* LLNameListCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFacto name_list->initFromXML(node, parent); - LLSD columns; - S32 index = 0; - LLXMLNodePtr child; - for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling()) - { - if (child->hasName("column")) - { - std::string labelname(""); - child->getAttributeString("label", labelname); - - std::string columnname(labelname); - child->getAttributeString("name", columnname); - - std::string sortname(columnname); - child->getAttributeString("sort", sortname); - - if (child->hasAttribute("relative_width")) - { - F32 columnrelwidth = 0.f; - child->getAttributeF32("relative_width", columnrelwidth); - columns[index]["relative_width"] = columnrelwidth; - } - else if (child->hasAttribute("relwidth")) - { - F32 columnrelwidth = 0.f; - child->getAttributeF32("relwidth", columnrelwidth); - columns[index]["relative_width"] = columnrelwidth; - } - else if (child->hasAttribute("dynamic_width")) - { - BOOL columndynamicwidth = FALSE; - child->getAttributeBOOL("dynamic_width", columndynamicwidth); - columns[index]["dynamic_width"] = columndynamicwidth; - } - else if (child->hasAttribute("dynamicwidth")) - { - BOOL columndynamicwidth = FALSE; - child->getAttributeBOOL("dynamicwidth", columndynamicwidth); - columns[index]["dynamic_width"] = columndynamicwidth; - } - else - { - S32 columnwidth = -1; - child->getAttributeS32("width", columnwidth); - columns[index]["width"] = columnwidth; - } - - LLFontGL::HAlign h_align = LLFontGL::LEFT; - h_align = LLView::selectFontHAlign(child); - - columns[index]["name"] = columnname; - columns[index]["label"] = labelname; - columns[index]["halign"] = (S32)h_align; - columns[index]["sort"] = sortname; - - index++; - } - } - name_list->setColumnHeadings(columns); - - - for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling()) - { - if (child->hasName("row")) - { - LLUUID id; - child->getAttributeUUID("id", id); - - LLSD row; - - row["id"] = id; - - S32 column_idx = 0; - LLXMLNodePtr row_child; - for (row_child = node->getFirstChild(); row_child.notNull(); row_child = row_child->getNextSibling()) - { - if (row_child->hasName("column")) - { - std::string value = row_child->getTextContents(); - - std::string columnname(""); - row_child->getAttributeString("name", columnname); - - std::string font(""); - row_child->getAttributeString("font", font); - - std::string font_style(""); - row_child->getAttributeString("font-style", font_style); - - row["columns"][column_idx]["column"] = columnname; - row["columns"][column_idx]["value"] = value; - row["columns"][column_idx]["font"] = font; - row["columns"][column_idx]["font-style"] = font_style; - column_idx++; - } - } - name_list->addElement(row); - } - } - - std::string contents = node->getTextContents(); - name_list->setCommentText(contents); - return name_list; } diff --git a/indra/newview/llnamelistctrl.h b/indra/newview/llnamelistctrl.h index 4a2bf209a..b1dd64da5 100644 --- a/indra/newview/llnamelistctrl.h +++ b/indra/newview/llnamelistctrl.h @@ -39,14 +39,15 @@ class LLAvatarName; * We don't use LLScrollListItem to be able to override getUUID(), which is needed * because the name list item value is not simply an UUID but a map (uuid, is_group). */ -class LLNameListItem : public LLScrollListItem, public LLHandleProvider +class LLNameListItem final : public LLScrollListItem, public LLHandleProvider { public: enum ENameType { INDIVIDUAL, GROUP, - SPECIAL + SPECIAL, + EXPERIENCE }; // provide names for enums @@ -86,7 +87,7 @@ private: }; -class LLNameListCtrl +class LLNameListCtrl final : public LLScrollListCtrl, public LLInstanceTracker { public: @@ -98,8 +99,8 @@ public: Alternative column_index; Alternative column_name; NameColumn() - : column_name("name_column"), - column_index("name_column_index", 0) + : column_index("name_column_index", 0), + column_name("name_column") {} }; @@ -118,7 +119,7 @@ protected: } friend class LLUICtrlFactory; public: - virtual LLXMLNodePtr getXML(bool save_children = true) const; + virtual LLXMLNodePtr getXML(bool save_children = true) const override; static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); // Add a user to the list by name. It will be added, the name @@ -127,7 +128,7 @@ public: BOOL enabled = TRUE, const std::string& suffix = LLStringUtil::null, const std::string& prefix = LLStringUtil::null); LLScrollListItem* addNameItem(NameItem& item, EAddPosition pos = ADD_BOTTOM); - /*virtual*/ LLScrollListItem* addElement(const LLSD& element, EAddPosition pos = ADD_BOTTOM, void* userdata = NULL); + /*virtual*/ LLScrollListItem* addElement(const LLSD& element, EAddPosition pos = ADD_BOTTOM, void* userdata = NULL) override; LLScrollListItem* addNameItemRow(const NameItem& value, EAddPosition pos = ADD_BOTTOM, const std::string& suffix = LLStringUtil::null, const std::string& prefix = LLStringUtil::null); @@ -146,9 +147,11 @@ public: /*virtual*/ BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, void *cargo_data, EAcceptance *accept, - std::string& tooltip_msg); + std::string& tooltip_msg) override; BOOL handleDoubleClick(S32 x, S32 y, MASK mask) override; + Type getSelectedType() const override final; + void setAllowCallingCardDrop(BOOL b) { mAllowCallingCardDrop = b; } void sortByName(BOOL ascending); @@ -158,8 +161,9 @@ private: private: S32 mNameColumnIndex; + //std::string mNameColumn; BOOL mAllowCallingCardDrop; - const LLCachedControl mNameSystem; + const LLCachedControl mNameSystem; // Singu Note: Instead of mShortNames typedef std::map avatar_name_cache_connection_map_t; avatar_name_cache_connection_map_t mAvatarNameCacheConnections; @@ -167,7 +171,7 @@ private: namelist_complete_signal_t mNameListCompleteSignal; public: - boost::signals2::connection setOnNameListCompleteCallback(boost::function onNameListCompleteCallback) + boost::signals2::connection setOnNameListCompleteCallback(std::function onNameListCompleteCallback) { return mNameListCompleteSignal.connect(onNameListCompleteCallback); } diff --git a/indra/newview/llnameui.cpp b/indra/newview/llnameui.cpp index 3c3a50a14..5699684cd 100644 --- a/indra/newview/llnameui.cpp +++ b/indra/newview/llnameui.cpp @@ -37,34 +37,49 @@ #include "llagentdata.h" #include "llavataractions.h" #include "llavatarnamecache.h" +#include "llexperiencecache.h" +#include "llfloaterexperienceprofile.h" #include "llgroupactions.h" #include "lltrans.h" -#include "rlvhandler.h" +#include "rlvactions.h" +#include "rlvcommon.h" // statics std::set LLNameUI::sInstances; -LLNameUI::LLNameUI(const std::string& loading, bool rlv_sensitive, const LLUUID& id, bool is_group) -: mNameID(id), mRLVSensitive(rlv_sensitive), mIsGroup(is_group), mAllowInteract(false) -, mInitialValue(!loading.empty() ? loading : LLTrans::getString("LoadingData")) +LLNameUI::LLNameUI(const std::string& loading, bool rlv_sensitive, const LLUUID& id, const Type& type, const std::string& name_system, bool click_for_profile) +: mNameID(id), mRLVSensitive(rlv_sensitive), mType(NONE), mAllowInteract(false) +, mNameSystem(name_system.empty() ? "PhoenixNameSystem" : name_system), mInitialValue(!loading.empty() ? loading : LLTrans::getString("LoadingData")) +, mClickForProfile(click_for_profile) { - if (mIsGroup) sInstances.insert(this); + setType(type); } -void LLNameUI::setNameID(const LLUUID& name_id, bool is_group) +void LLNameUI::setType(const Type& type) { - mNameID = name_id; - mConnection.disconnect(); + // Disconnect active connections if needed + for (auto& connection : mConnections) + connection.disconnect(); - if (mIsGroup != is_group) + if (mType != type) { - if (is_group) + if (type == GROUP) sInstances.insert(this); else + { sInstances.erase(this); + if (type == AVATAR) + mConnections[1] = gSavedSettings.getControl(mNameSystem)->getCommitSignal()->connect(boost::bind(&LLNameUI::setNameText, this)); + } + mType = type; } - mIsGroup = is_group; +} + +void LLNameUI::setNameID(const LLUUID& name_id, const Type& type) +{ + mNameID = name_id; + setType(type); if (mAllowInteract = mNameID.notNull()) { @@ -72,7 +87,8 @@ void LLNameUI::setNameID(const LLUUID& name_id, bool is_group) } else { - setText(LLTrans::getString(mIsGroup ? "GroupNameNone" : "AvatarNameNobody")); + setText(LLTrans::getString(mType == GROUP ? "GroupNameNone" : + mType == AVATAR ? "AvatarNameNobody" : "ExperienceNameNull")); displayAsLink(false); } } @@ -82,22 +98,31 @@ void LLNameUI::setNameText() std::string name; bool got_name = false; - if (mIsGroup) + if (mType == GROUP) { got_name = gCacheName->getGroupName(mNameID, name); } + else if (mType == EXPERIENCE) + { + auto& cache = LLExperienceCache::instance(); + const auto& exp = cache.get(mNameID); + if (got_name = exp.isMap()) + name = exp.has(LLExperienceCache::MISSING) && exp[LLExperienceCache::MISSING] ? LLTrans::getString("ExperienceNameNull") : exp[LLExperienceCache::NAME].asString(); + else + cache.get(mNameID, boost::bind(&LLNameUI::setNameText, this)); + } else { LLAvatarName av_name; if (got_name = LLAvatarNameCache::get(mNameID, &av_name)) - name = mShowCompleteName ? av_name.getCompleteName() : av_name.getNSName(); + name = mNameSystem.empty() ? av_name.getNSName() : av_name.getNSName(gSavedSettings.getS32(mNameSystem)); else - mConnection = LLAvatarNameCache::get(mNameID, boost::bind(&LLNameUI::setNameText, this)); + mConnections[0] = LLAvatarNameCache::get(mNameID, boost::bind(&LLNameUI::setNameText, this)); } - if (!mIsGroup && got_name && mRLVSensitive) // Filter if needed + if (mType == AVATAR && got_name && mRLVSensitive) // Filter if needed { - if ((gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES) || gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS)) + if ((RlvActions::hasBehaviour(RLV_BHVR_SHOWNAMES) || RlvActions::hasBehaviour(RLV_BHVR_SHOWNAMETAGS)) && mNameID != gAgentID && RlvUtil::isNearbyAgent(mNameID)) { mAllowInteract = false; @@ -113,7 +138,7 @@ void LLNameUI::setNameText() setText(got_name ? name : mInitialValue); } -void LLNameUI::refresh(const LLUUID& id, const std::string& full_name, bool is_group) +void LLNameUI::refresh(const LLUUID& id, const std::string& full_name) { if (id == mNameID) { @@ -121,12 +146,11 @@ void LLNameUI::refresh(const LLUUID& id, const std::string& full_name, bool is_g } } -void LLNameUI::refreshAll(const LLUUID& id, const std::string& full_name, bool is_group) +void LLNameUI::refreshAll(const LLUUID& id, const std::string& full_name) { - if (!is_group) return; for (auto box : sInstances) { - box->refresh(id, full_name, is_group); + box->refresh(id, full_name); } } @@ -134,8 +158,11 @@ void LLNameUI::showProfile() { if (!mAllowInteract) return; - if (mIsGroup) - LLGroupActions::show(mNameID); - else - LLAvatarActions::showProfile(mNameID); -} \ No newline at end of file + switch (mType) + { + case LFIDBearer::GROUP: LLGroupActions::show(mNameID); break; + case LFIDBearer::AVATAR: LLAvatarActions::showProfile(mNameID); break; + case LFIDBearer::EXPERIENCE: LLFloaterExperienceProfile::showInstance(mNameID); break; + default: break; + } +} diff --git a/indra/newview/llnameui.h b/indra/newview/llnameui.h index 3d392675c..bade1a1cf 100644 --- a/indra/newview/llnameui.h +++ b/indra/newview/llnameui.h @@ -38,25 +38,23 @@ struct LLNameUI : public LFIDBearer { - LLNameUI(const std::string& loading = LLStringUtil::null, bool rlv_sensitive = false, const LLUUID& id = LLUUID::null, bool is_group = false); + LLNameUI(const std::string& loading = LLStringUtil::null, bool rlv_sensitive = false, const LLUUID& id = LLUUID::null, const Type& type = AVATAR, const std::string& name_system = LLStringUtil::null, bool click_for_profile = true); virtual ~LLNameUI() { - if (mIsGroup) - sInstances.erase(this); - else - mConnection.disconnect(); + if (mType == GROUP) sInstances.erase(this); + for (auto& connection : mConnections) + connection.disconnect(); } LLUUID getStringUUIDSelectedItem() const override final { return mNameID; } - uuid_vec_t getSelectedIDs() const override final { return { mNameID }; } - S32 getNumSelected() const override final { return 1; } + Type getSelectedType() const override final { return mType; } - void setNameID(const LLUUID& name_id, bool is_group); + void setType(const Type& type); + void setNameID(const LLUUID& name_id, const Type& type); void setNameText(); // Sets the name to whatever the name cache has at the moment - void refresh(const LLUUID& id, const std::string& full_name, bool is_group); - static void refreshAll(const LLUUID& id, const std::string& full_name, bool is_group); + void refresh(const LLUUID& id, const std::string& name); + static void refreshAll(const LLUUID& id, const std::string& name); - void setShowCompleteName(bool show) { mShowCompleteName = show; } void showProfile(); virtual void displayAsLink(bool link) = 0; // Override to make the name display as a link @@ -66,22 +64,23 @@ struct LLNameUI : public LFIDBearer virtual void setValue(const LLSD& value) { if (value.has("id")) - setNameID(value["id"].asUUID(), value["group"].asBoolean()); + setNameID(value["id"].asUUID(), (Type)value["type"].asInteger()); else - setNameID(value.asUUID(), mIsGroup); + setNameID(value.asUUID(), mType); } // Return agent UUIDs virtual LLSD getValue() const { return LLSD(mNameID); } private: static std::set sInstances; - boost::signals2::connection mConnection; - bool mShowCompleteName = false; + std::array mConnections; protected: LLUUID mNameID; bool mRLVSensitive; // Whether or not we're doing RLV filtering - bool mIsGroup; + Type mType; bool mAllowInteract; std::string mInitialValue; -}; \ No newline at end of file + std::string mNameSystem; + bool mClickForProfile; +}; diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp index 53463dea8..727597f24 100644 --- a/indra/newview/llnetmap.cpp +++ b/indra/newview/llnetmap.cpp @@ -53,6 +53,7 @@ #include "llavatarnamecache.h" #include "llcallingcard.h" #include "llcolorscheme.h" +#include "llfloatermap.h" #include "llfloaterworldmap.h" #include "llframetimer.h" // [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-06-20 (Catznip-3.3.0) @@ -84,6 +85,82 @@ // [/RLVa:KB] using namespace LLOldEvents; +typedef LLMemberListener view_listener_t; + +class LLScaleMap : public view_listener_t +{ +public: + /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata) override final; +}; + +class LLChatRings : public view_listener_t +{ +public: + /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata) override final; +}; + +class LLCheckChatRings : public view_listener_t +{ +public: + /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata) override final; +}; + +class LLStopTracking : public view_listener_t +{ +public: + /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata) override final; +}; + +class LLIsTracking : public view_listener_t +{ +public: + /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata) override final; +}; + +//moymod - Custom minimap markers :o +class mmsetred : public view_listener_t //moymod +{ +public: + /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata) override final; +}; +class mmsetgreen : public view_listener_t //moymod +{ +public: + /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata) override final; +}; +class mmsetblue : public view_listener_t //moymod +{ +public: + /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata) override final; +}; +class mmsetyellow : public view_listener_t //moymod +{ +public: + /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata) override final; +}; +class mmsetcustom : public view_listener_t //moymod +{ +public: + /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata) override final; +}; +class mmsetunmark : public view_listener_t //moymod +{ +public: + /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata) override final; +}; +class mmenableunmark : public view_listener_t //moymod +{ +public: + /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata) override final; +}; + +// [SL:KB] - Patch: World-MiniMap | Checked: 2012-07-08 (Catznip-3.3.0) +class OverlayToggle : public view_listener_t +{ +public: + /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata) override final; +}; +// [/SL:KB] const F32 LLNetMap::MAP_SCALE_MIN = 32; const F32 LLNetMap::MAP_SCALE_MID = 256; @@ -103,7 +180,7 @@ const S32 CIRCLE_STEPS = 100; const F64 COARSEUPDATE_MAX_Z = 1020.0f; std::map LLNetMap::mClosestAgentsToCursor; // -static std::map mClosestAgentsAtLastClick; // +uuid_vec_t LLNetMap::mClosestAgentsAtLastClick; // LLNetMap::LLNetMap(const std::string& name) : LLPanel(name), @@ -144,26 +221,29 @@ LLNetMap::~LLNetMap() BOOL LLNetMap::postBuild() { + mELabel = getChild("e_label"); + mNLabel = getChild("n_label"); + mWLabel = getChild("w_label"); + mSLabel = getChild("s_label"); + mNELabel = getChild("ne_label"); + mNWLabel = getChild("nw_label"); + mSWLabel = getChild("sw_label"); + mSELabel = getChild("se_label"); + // Register event listeners for popup menu - (new LLScaleMap())->registerListener(this, "MiniMap.ZoomLevel"); - (new LLCenterMap())->registerListener(this, "MiniMap.Center"); - (new LLCheckCenterMap())->registerListener(this, "MiniMap.CheckCenter"); - (new LLChatRings())->registerListener(this, "MiniMap.ChatRings"); - (new LLCheckChatRings())->registerListener(this, "MiniMap.CheckChatRings"); - (new LLStopTracking())->registerListener(this, "MiniMap.StopTracking"); - (new LLEnableTracking())->registerListener(this, "MiniMap.EnableTracking"); - (new LLShowAgentProfile())->registerListener(this, "MiniMap.ShowProfile"); - (new LLEnableProfile())->registerListener(this, "MiniMap.EnableProfile"); - (new LLCamFollow())->registerListener(this, "MiniMap.CamFollow"); //moymod - add cam follow crap thingie - (new mmsetred())->registerListener(this, "MiniMap.setred"); - (new mmsetgreen())->registerListener(this, "MiniMap.setgreen"); - (new mmsetblue())->registerListener(this, "MiniMap.setblue"); - (new mmsetyellow())->registerListener(this, "MiniMap.setyellow"); - (new mmsetcustom())->registerListener(this, "MiniMap.setcustom"); - (new mmsetunmark())->registerListener(this, "MiniMap.setunmark"); - (new mmenableunmark())->registerListener(this, "MiniMap.enableunmark"); - (new LLToggleControl())->registerListener(this, "MiniMap.ToggleControl"); - (new OverlayToggle())->registerListener(this, "Minimap.ToggleOverlay"); + (new LLScaleMap())->registerListener(gMenuHolder, "MiniMap.ZoomLevel"); + (new LLChatRings())->registerListener(gMenuHolder, "MiniMap.ChatRings"); + (new LLCheckChatRings())->registerListener(gMenuHolder, "MiniMap.CheckChatRings"); + (new LLStopTracking())->registerListener(gMenuHolder, "StopTracking"); + (new LLIsTracking())->registerListener(gMenuHolder, "IsTracking"); + (new mmsetred())->registerListener(gMenuHolder, "MiniMap.setred"); + (new mmsetgreen())->registerListener(gMenuHolder, "MiniMap.setgreen"); + (new mmsetblue())->registerListener(gMenuHolder, "MiniMap.setblue"); + (new mmsetyellow())->registerListener(gMenuHolder, "MiniMap.setyellow"); + (new mmsetcustom())->registerListener(gMenuHolder, "MiniMap.setcustom"); + (new mmsetunmark())->registerListener(gMenuHolder, "MiniMap.setunmark"); + (new mmenableunmark())->registerListener(gMenuHolder, "MiniMap.enableunmark"); + (new OverlayToggle())->registerListener(gMenuHolder, "Minimap.ToggleOverlay"); // [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-06-20 (Catznip-3.3.0) LLViewerParcelMgr::instance().setCollisionUpdateCallback(boost::bind(&LLNetMap::refreshParcelOverlay, this)); @@ -172,7 +252,7 @@ BOOL LLNetMap::postBuild() updateMinorDirections(); - mPopupMenu = LLUICtrlFactory::getInstance()->buildMenu("menu_mini_map.xml", this); + mPopupMenu = LLUICtrlFactory::getInstance()->buildMenu("menu_mini_map.xml", gMenuHolder); if (!mPopupMenu) mPopupMenu = new LLMenuGL(LLStringUtil::null); mPopupMenu->setVisible(FALSE); return TRUE; @@ -216,15 +296,31 @@ std::size_t hash_value(const LLUUID& uuid) return (std::size_t)uuid.getCRC32(); } boost::unordered_map mm_MarkerColors; +const LLColor4* mm_getMarkerColor(const LLUUID& id, bool mark_only) +{ + if (!mark_only) // They're trying to get the color and they're not the minimap or the radar mark + { + static const LLCachedControl use_marked_color("LiruUseMarkedColor"); + if (!use_marked_color) return nullptr; + } + auto it = mm_MarkerColors.find(id); + return it == mm_MarkerColors.end() ? nullptr : &it->second; +} +const LLColor4* mm_getMarkerColor(const LLUUID& id) { return mm_getMarkerColor(id, false); } + bool mm_getMarkerColor(const LLUUID& id, LLColor4& color) { - boost::unordered_map::const_iterator it = mm_MarkerColors.find(id); - if (it == mm_MarkerColors.end()) return false; - color = it->second; - return true; + auto c = mm_getMarkerColor(id); + if (c) color = *c; + return c; } -void LLNetMap::mm_setcolor(LLUUID key,LLColor4 col) +void mm_clearMark(const LLUUID& id) +{ + mm_MarkerColors.erase(id); +} + +void mm_setcolor(LLUUID key,LLColor4 col) { mm_MarkerColors[key] = col; } @@ -257,8 +353,8 @@ void LLNetMap::draw() } // [/SL:KB] - static LLUICachedControl center("MiniMapCenter"); - if (center != MAP_CENTER_NONE) + static const LLUICachedControl center("MiniMapCenter"); + if (center) { mCurPan = lerp(mCurPan, mTargetPan, LLSmoothInterpolation::getInterpolant(0.1f)); } @@ -558,14 +654,14 @@ void LLNetMap::draw() gmSelected = LLFloaterAvatarList::instance().getSelectedIDs(); // Draw avatars - for(LLWorld::pos_map_t::const_iterator iter = positions.cbegin(), iter_end = positions.cend(); iter != iter_end; ++iter) + for(const auto& pair : positions) { - const LLUUID& uuid = iter->first; + const LLUUID& uuid = pair.first; static const LLCachedControl standard_color("MapAvatar",LLColor4(0.f,1.f,0.f,1.f)); LLColor4 color = standard_color; // TODO: it'd be very cool to draw these in sorted order from lowest Z to highest. // just be careful to sort the avatar IDs along with the positions. -MG - const LLVector3d& position = iter->second; + const LLVector3d& position = pair.second; pos_map = globalPosToView(position); if (position.mdV[VZ] == 0.f || position.mdV[VZ] == COARSEUPDATE_MAX_Z) { @@ -578,10 +674,14 @@ void LLNetMap::draw() static const LLCachedControl map_avatar_rollover_color(gSavedSettings, "ExodusMapRolloverColor", LLColor4::cyan); color = map_avatar_rollover_color; } + else if (auto mark_color = mm_getMarkerColor(uuid, true)) + { + color = *mark_color; + } else { - bool getCustomColorRLV(const LLUUID&, LLColor4&, LLViewerRegion*, bool name_restricted); - getCustomColorRLV(uuid, color, LLWorld::getInstance()->getRegionFromPosGlobal(position), !show_friends); + bool getColorFor(const LLUUID & id, LLViewerRegion * parent_estate, LLColor4 & color, bool name_restricted = false); + getColorFor(uuid, LLWorld::getInstance()->getRegionFromPosGlobal(position), color, !show_friends); } LLWorldMapView::drawAvatar( @@ -732,15 +832,15 @@ void LLNetMap::draw() gGL.popUIMatrix(); // Rotation of 0 means that North is up - setDirectionPos( getChild("e_label"), rotation); - setDirectionPos( getChild("n_label"), rotation + F_PI_BY_TWO); - setDirectionPos( getChild("w_label"), rotation + F_PI); - setDirectionPos( getChild("s_label"), rotation + F_PI + F_PI_BY_TWO); + setDirectionPos(mELabel, rotation); + setDirectionPos(mNLabel, rotation + F_PI_BY_TWO); + setDirectionPos(mWLabel, rotation + F_PI); + setDirectionPos(mSLabel, rotation + F_PI + F_PI_BY_TWO); - setDirectionPos( getChild("ne_label"), rotation + F_PI_BY_TWO / 2); - setDirectionPos( getChild("nw_label"), rotation + F_PI_BY_TWO + F_PI_BY_TWO / 2); - setDirectionPos( getChild("sw_label"), rotation + F_PI + F_PI_BY_TWO / 2); - setDirectionPos( getChild("se_label"), rotation + F_PI + F_PI_BY_TWO + F_PI_BY_TWO / 2); + setDirectionPos(mNELabel, rotation + F_PI_BY_TWO / 2); + setDirectionPos(mNWLabel, rotation + F_PI_BY_TWO + F_PI_BY_TWO / 2); + setDirectionPos(mSWLabel, rotation + F_PI + F_PI_BY_TWO / 2); + setDirectionPos(mSELabel, rotation + F_PI + F_PI_BY_TWO + F_PI_BY_TWO / 2); LLUICtrl::draw(); } @@ -858,8 +958,8 @@ BOOL LLNetMap::handleScrollWheel(S32 x, S32 y, S32 clicks) setScale(new_scale); - static LLUICachedControl center("MiniMapCenter"); - if (center == MAP_CENTER_NONE) + static const LLUICachedControl center("MiniMapCenter"); + if (!center) { // Adjust pan to center the zoom on the mouse pointer LLVector2 zoom_offset; @@ -888,7 +988,7 @@ BOOL LLNetMap::handleToolTip( S32 x, S32 y, std::string& tool_tip, LLRect* stick sticky_rect.mRight = sticky_rect.mLeft + 2 * SLOP; sticky_rect.mTop = sticky_rect.mBottom + 2 * SLOP; - tool_tip.assign(""); + tool_tip.clear(); if (region->mMapAvatarIDs.size()) { @@ -900,12 +1000,10 @@ BOOL LLNetMap::handleToolTip( S32 x, S32 y, std::string& tool_tip, LLRect* stick LLVector3d myPosition = gAgent.getPositionGlobal(); - std::map::iterator current = mClosestAgentsToCursor.begin(); - std::map::iterator end = mClosestAgentsToCursor.end(); - for (; current != end; ++current) + for (const auto& target : mClosestAgentsToCursor) { - LLUUID targetUUID = (*current).first; - LLVector3d targetPosition = (*current).second; + const auto& targetUUID = target.first; + auto targetPosition = target.second; std::string fullName; if (targetUUID.notNull() && LLAvatarNameCache::getNSName(targetUUID, fullName)) @@ -927,12 +1025,12 @@ BOOL LLNetMap::handleToolTip( S32 x, S32 y, std::string& tool_tip, LLRect* stick LLVector3d delta = targetPosition - myPosition; F32 distance = (F32)delta.magVec(); if (single_agent) - tool_tip.append( llformat("\n\n(Distance: %.02fm)\n",distance) ); + tool_tip.append( llformat("\n(Distance: %.02fm)\n",distance) ); else tool_tip.append(llformat(" (%.02fm)\n", distance)); } } - tool_tip.append("\n"); + tool_tip += '\n'; } } // [RLVa:KB] - Version: 1.23.4 | Checked: 2009-07-04 (RLVa-1.0.0a) | Modified: RLVa-0.2.0b @@ -940,9 +1038,9 @@ BOOL LLNetMap::handleToolTip( S32 x, S32 y, std::string& tool_tip, LLRect* stick // [/RLVa:KB] //tool_tip.append("\n\n" + region->getName()); - tool_tip.append("\n" + region->getHost().getHostName()); - tool_tip.append("\n" + region->getHost().getString()); - tool_tip.append("\n" + getToolTip()); + tool_tip.append('\n' + region->getHost().getHostName()); + tool_tip.append('\n' + region->getHost().getString()); + tool_tip.append('\n' + getToolTip()); } else { @@ -971,19 +1069,16 @@ void LLNetMap::setDirectionPos( LLTextBox* text_box, F32 rotation ) void LLNetMap::updateMinorDirections() { - if (getChild("ne_label", TRUE, FALSE) == NULL) - { - return; - } + if (!mNELabel) return; // Hide minor directions if they cover too much of the map - bool show_minors = getChild("ne_label")->getRect().getHeight() < MAP_MINOR_DIR_THRESHOLD * + bool show_minors = mNELabel->getRect().getHeight() < MAP_MINOR_DIR_THRESHOLD * llmin(getRect().getWidth(), getRect().getHeight()); - getChild("ne_label")->setVisible(show_minors); - getChild("nw_label")->setVisible(show_minors); - getChild("sw_label")->setVisible(show_minors); - getChild("se_label")->setVisible(show_minors); + mNELabel->setVisible(show_minors); + mNWLabel->setVisible(show_minors); + mSWLabel->setVisible(show_minors); + mSELabel->setVisible(show_minors); } void LLNetMap::renderScaledPointGlobal( const LLVector3d& pos, const LLColor4U &color, F32 radius_meters ) @@ -1283,29 +1378,29 @@ BOOL LLNetMap::handleMouseUp( S32 x, S32 y, MASK mask ) } // [SL:KB] - Patch: World-MiniMap | Checked: 2012-07-08 (Catznip-3.3.0) -bool LLNetMap::OverlayToggle::handleEvent(LLPointer event, const LLSD& sdParam) +bool OverlayToggle::handleEvent(LLPointer event, const LLSD& sdParam) { - // Toggle the setting - const std::string strControl = sdParam.asString(); - BOOL fCurValue = gSavedSettings.getBOOL(strControl); - gSavedSettings.setBOOL(strControl, !fCurValue); - // Force an overlay update - mPtr->mUpdateParcelImage = true; + LLFloaterMap::findInstance()->mPanelMap->mUpdateParcelImage = true; return true; } // [/SL:KB] BOOL LLNetMap::handleRightMouseDown(S32 x, S32 y, MASK mask) { - mClosestAgentsAtLastClick = mClosestAgentsToCursor; + mClosestAgentsAtLastClick.clear(); + mClosestAgentsAtLastClick.reserve(mClosestAgentsToCursor.size()); + for (const auto& pair : mClosestAgentsToCursor) + mClosestAgentsAtLastClick.push_back(pair.first); mClosestAgentAtLastRightClick = mClosestAgentToCursor; if (mPopupMenu) { - // Singu TODO: It'd be spectacular to address multiple avatars from here. - mPopupMenu->buildDrawLabels(); - mPopupMenu->updateParent(LLMenuGL::sMenuContainer); - LLMenuGL::showPopup(this, mPopupMenu, x, y); + showMenu(this, mPopupMenu, x, y); + mPopupMenu->getChildView("avs_menu")->setVisible(!mClosestAgentsAtLastClick.empty() && ! +// [RLVa:LF] - 2019 + gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES) +// [/RLVa:LF] + ); } return TRUE; } @@ -1396,22 +1491,22 @@ BOOL LLNetMap::handleHover( S32 x, S32 y, MASK mask ) } // static -bool LLNetMap::LLScaleMap::handleEvent(LLPointer event, const LLSD& userdata) +bool LLScaleMap::handleEvent(LLPointer event, const LLSD& userdata) { - LLNetMap *self = mPtr; + auto self = LLFloaterMap::findInstance()->mPanelMap; S32 level = userdata.asInteger(); switch(level) { case 0: - self->setScale(MAP_SCALE_MIN); + self->setScale(LLNetMap::MAP_SCALE_MIN); break; case 1: - self->setScale(MAP_SCALE_MID); + self->setScale(LLNetMap::MAP_SCALE_MID); break; case 2: - self->setScale(MAP_SCALE_MAX); + self->setScale(LLNetMap::MAP_SCALE_MAX); break; default: break; @@ -1423,149 +1518,94 @@ bool LLNetMap::LLScaleMap::handleEvent(LLPointer event, const LLSD& use //moymod - minimap color shit void markMassAgents(const LLColor4& color) { - std::map::iterator current = mClosestAgentsAtLastClick.begin(); - std::map::iterator end = mClosestAgentsAtLastClick.end(); - for(; current != end; ++current) LLNetMap::mm_setcolor((*current).first, color); + auto radar = LLFloaterAvatarList::getInstance(); + for (const auto& id : LFIDBearer::getActiveSelectedIDs()) + { + mm_setcolor(id, color); + if (auto entry = radar ? radar->getAvatarEntry(id) : nullptr) + entry->setMarked(true); + } } -bool LLNetMap::mmsetred::handleEvent(LLPointer, const LLSD&) +bool mmsetred::handleEvent(LLPointer, const LLSD&) { - markMassAgents(LLColor4::red); return true; -} -bool LLNetMap::mmsetgreen::handleEvent(LLPointer, const LLSD&) -{ - markMassAgents(LLColor4::green); return true; -} -bool LLNetMap::mmsetblue::handleEvent(LLPointer, const LLSD&) -{ - markMassAgents(LLColor4::blue); return true; -} -bool LLNetMap::mmsetyellow::handleEvent(LLPointer, const LLSD&) -{ - markMassAgents(LLColor4::yellow); return true; -} -bool LLNetMap::mmsetcustom::handleEvent(LLPointer, const LLSD&) -{ - markMassAgents(gSavedSettings.getColor4("MoyMiniMapCustomColor")); return true; -} -bool LLNetMap::mmsetunmark::handleEvent(LLPointer, const LLSD&) -{ - std::map::iterator it = mClosestAgentsAtLastClick.begin(); - std::map::iterator end = mClosestAgentsAtLastClick.end(); - for(; it!= end; ++it) mm_MarkerColors.erase((*it).first); + markMassAgents(LLColor4::red); return true; } -bool LLNetMap::mmenableunmark::handleEvent(LLPointer, const LLSD& userdata) +bool mmsetgreen::handleEvent(LLPointer, const LLSD&) +{ + markMassAgents(LLColor4::green); + return true; +} +bool mmsetblue::handleEvent(LLPointer, const LLSD&) +{ + markMassAgents(LLColor4::blue); + return true; +} +bool mmsetyellow::handleEvent(LLPointer, const LLSD&) +{ + markMassAgents(LLColor4::yellow); + return true; +} +bool mmsetcustom::handleEvent(LLPointer, const LLSD&) +{ + markMassAgents(gSavedSettings.getColor4("MoyMiniMapCustomColor")); + return true; +} +bool mmsetunmark::handleEvent(LLPointer, const LLSD&) +{ + auto radar = LLFloaterAvatarList::getInstance(); + for (const auto& id : LFIDBearer::getActiveSelectedIDs()) + { + mm_clearMark(id); + if (auto entry = radar ? radar->getAvatarEntry(id) : nullptr) + entry->setMarked(false); + } + return true; +} +bool mmenableunmark::handleEvent(LLPointer, const LLSD& userdata) { bool enabled(false); - std::map::iterator it = mClosestAgentsAtLastClick.begin(); - std::map::iterator end = mClosestAgentsAtLastClick.end(); - for(; it != end && !enabled; ++it) enabled = mm_MarkerColors.find((*it).first) != mm_MarkerColors.end(); + for (const auto& id : LFIDBearer::getActiveSelectedIDs()) + if (enabled = mm_MarkerColors.find(id) != mm_MarkerColors.end()) + break; mPtr->findControl(userdata["control"].asString())->setValue(enabled); return true; } -bool LLNetMap::LLCenterMap::handleEvent(LLPointer event, const LLSD& userdata) +bool LLChatRings::handleEvent(LLPointer event, const LLSD& userdata) { - EMiniMapCenter center = (EMiniMapCenter)userdata.asInteger(); + auto whisper = gSavedSettings.getControl("MiniMapWhisperRing"); + auto chat = gSavedSettings.getControl("MiniMapChatRing"); + auto shout = gSavedSettings.getControl("MiniMapShoutRing"); + bool all_enabled = whisper->get() && chat->get() && shout->get(); - if (gSavedSettings.getS32("MiniMapCenter") == center) - { - gSavedSettings.setS32("MiniMapCenter", MAP_CENTER_NONE); - } - else - { - gSavedSettings.setS32("MiniMapCenter", userdata.asInteger()); - } + whisper->set(!all_enabled); + chat->set(!all_enabled); + shout->set(!all_enabled); return true; } -bool LLNetMap::LLCheckCenterMap::handleEvent(LLPointer event, const LLSD& userdata) +bool LLCheckChatRings::handleEvent(LLPointer event, const LLSD& userdata) { - LLNetMap *self = mPtr; - EMiniMapCenter center = (EMiniMapCenter)userdata["data"].asInteger(); - BOOL enabled = (gSavedSettings.getS32("MiniMapCenter") == center); + bool all_enabled = gSavedSettings.getBOOL("MiniMapWhisperRing") + && gSavedSettings.getBOOL("MiniMapChatRing") + && gSavedSettings.getBOOL("MiniMapShoutRing"); - self->findControl(userdata["control"].asString())->setValue(enabled); + mPtr->findControl(userdata["control"].asString())->setValue(all_enabled); return true; } -bool LLNetMap::LLChatRings::handleEvent(LLPointer event, const LLSD& userdata) -{ - BOOL whisper_enabled = gSavedSettings.getBOOL("MiniMapWhisperRing"); - BOOL chat_enabled = gSavedSettings.getBOOL("MiniMapChatRing"); - BOOL shout_enabled = gSavedSettings.getBOOL("MiniMapShoutRing"); - BOOL all_enabled = whisper_enabled && chat_enabled && shout_enabled; - - gSavedSettings.setBOOL("MiniMapWhisperRing", !all_enabled); - gSavedSettings.setBOOL("MiniMapChatRing", !all_enabled); - gSavedSettings.setBOOL("MiniMapShoutRing", !all_enabled); - - return true; -} - -bool LLNetMap::LLCheckChatRings::handleEvent(LLPointer event, const LLSD& userdata) -{ - BOOL whisper_enabled = gSavedSettings.getBOOL("MiniMapWhisperRing"); - BOOL chat_enabled = gSavedSettings.getBOOL("MiniMapChatRing"); - BOOL shout_enabled = gSavedSettings.getBOOL("MiniMapShoutRing"); - BOOL all_enabled = whisper_enabled && chat_enabled && shout_enabled; - - LLNetMap *self = mPtr; - self->findControl(userdata["control"].asString())->setValue(all_enabled); - return true; -} - -bool LLNetMap::LLStopTracking::handleEvent(LLPointer event, const LLSD& userdata) +bool LLStopTracking::handleEvent(LLPointer event, const LLSD& userdata) { LLTracker::stopTracking(false); return true; } -bool LLNetMap::LLEnableTracking::handleEvent(LLPointer event, const LLSD& userdata) +bool LLIsTracking::handleEvent(LLPointer event, const LLSD& userdata) { - LLNetMap *self = mPtr; - self->findControl(userdata["control"].asString())->setValue(LLTracker::isTracking()); + mPtr->findControl(userdata["control"].asString())->setValue(LLTracker::isTracking()); return true; } - -bool LLNetMap::LLCamFollow::handleEvent(LLPointer event, const LLSD& userdata) -{ - LLNetMap *self = mPtr; - LLFloaterAvatarList::lookAtAvatar(self->mClosestAgentAtLastRightClick); - return true; -} - - -bool LLNetMap::LLShowAgentProfile::handleEvent(LLPointer event, const LLSD& userdata) -{ - LLNetMap *self = mPtr; -// [RLVa:KB] - Version: 1.23.4 | Checked: 2009-07-08 (RLVa-1.0.0e) | Modified: RLVa-0.2.0b - if (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) - { - LLAvatarActions::showProfile(self->mClosestAgentAtLastRightClick); - } -// [/RLVa:KB] - //LLAvatarActions::showProfile(self->mClosestAgentAtLastRightClick); - return true; -} - -bool LLNetMap::LLEnableProfile::handleEvent(LLPointer event, const LLSD& userdata) -{ - LLNetMap *self = mPtr; -// [RLVa:KB] - Version: 1.23.4 | Checked: 2009-07-08 (RLVa-1.0.0e) | Modified: RLVa-0.2.0b - self->findControl(userdata["control"].asString())->setValue( - (self->isAgentUnderCursor()) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) ); -// [/RLVa:KB] - //self->findControl(userdata["control"].asString())->setValue(self->isAgentUnderCursor()); - return true; -} - -bool LLNetMap::LLToggleControl::handleEvent(LLPointer event, const LLSD& userdata) -{ - std::string control_name = userdata.asString(); - gSavedSettings.setBOOL(control_name, !gSavedSettings.getBOOL(control_name)); - return true; -} diff --git a/indra/newview/llnetmap.h b/indra/newview/llnetmap.h index 0b291b5bc..67eb3d4be 100644 --- a/indra/newview/llnetmap.h +++ b/indra/newview/llnetmap.h @@ -33,33 +33,20 @@ #ifndef LL_LLNETMAP_H #define LL_LLNETMAP_H -#include "llmath.h" +#include "lfidbearer.h" #include "llpanel.h" -#include "llmemberlistener.h" -#include "v3math.h" -#include "v3dmath.h" -#include "v4color.h" -#include "llpointer.h" -#include "llcoord.h" class LLTextBox; class LLImageRaw; class LLViewerTexture; class LLFloaterMap; -class LLMenuGL; // [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-06-20 (Catznip-3.3.0) class LLViewerRegion; class LLAvatarName; // [/SL:KB] -enum EMiniMapCenter -{ - MAP_CENTER_NONE = 0, - MAP_CENTER_CAMERA = 1 -}; - -class LLNetMap : public LLPanel +class LLNetMap final : public LLPanel, public LFIDBearer { public: LLNetMap(const std::string& name); @@ -81,8 +68,8 @@ public: /*virtual*/ BOOL handleRightMouseDown( S32 x, S32 y, MASK mask ); /*virtual*/ BOOL handleDoubleClick( S32 x, S32 y, MASK mask ); - static void mm_setcolor(LLUUID key,LLColor4 col); //moymod - + LLUUID getStringUUIDSelectedItem() const override final { return mClosestAgentAtLastRightClick; } + uuid_vec_t getSelectedIDs() const override final { return mClosestAgentsAtLastClick; } // [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-06-20 (Catznip-3.3.0) void refreshParcelOverlay() { mUpdateParcelImage = true; } @@ -127,6 +114,15 @@ protected: private: // [/SL:KB] + LLTextBox *mELabel = nullptr, + *mNLabel = nullptr, + *mWLabel = nullptr, + *mSLabel = nullptr, + *mNELabel = nullptr, + *mNWLabel = nullptr, + *mSWLabel = nullptr, + *mSELabel = nullptr; + F32 mScale; // Size of a region in pixels F32 mPixelsPerMeter; // world meters to map pixels F32 mObjectMapTPM; // texels per meter on map @@ -152,125 +148,12 @@ private: // [/SL:KB] static std::map mClosestAgentsToCursor; // + static uuid_vec_t mClosestAgentsAtLastClick; // LLUUID mClosestAgentToCursor; LLUUID mClosestAgentAtLastRightClick; - static void showAgentProfile(void*); - BOOL isAgentUnderCursor() { return mClosestAgentToCursor.notNull(); } - - class LLScaleMap : public LLMemberListener - { - public: - /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata); - }; - - class LLCenterMap : public LLMemberListener - { - public: - /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata); - }; - - class LLCheckCenterMap : public LLMemberListener - { - public: - /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata); - }; - - class LLChatRings : public LLMemberListener - { - public: - /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata); - }; - - class LLCheckChatRings : public LLMemberListener - { - public: - /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata); - }; - - class LLStopTracking : public LLMemberListener - { - public: - /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata); - }; - - class LLEnableTracking : public LLMemberListener - { - public: - /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata); - }; - - class LLShowAgentProfile : public LLMemberListener - { - public: - /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata); - }; - - class LLCamFollow : public LLMemberListener //moymod - { - public: - /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata); - }; - - //moymod - Custom minimap markers :o - class mmsetred : public LLMemberListener //moymod - { - public: - /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata); - }; - class mmsetgreen : public LLMemberListener //moymod - { - public: - /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata); - }; - class mmsetblue : public LLMemberListener //moymod - { - public: - /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata); - }; - class mmsetyellow : public LLMemberListener //moymod - { - public: - /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata); - }; - class mmsetcustom : public LLMemberListener //moymod - { - public: - /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata); - }; - class mmsetunmark : public LLMemberListener //moymod - { - public: - /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata); - }; - class mmenableunmark : public LLMemberListener //moymod - { - public: - /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata); - }; - - - class LLEnableProfile : public LLMemberListener - { - public: - /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata); - }; - - class LLToggleControl : public LLMemberListener - { - public: - /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata); - }; - -// [SL:KB] - Patch: World-MiniMap | Checked: 2012-07-08 (Catznip-3.3.0) - class OverlayToggle : public LLMemberListener - { - public: - /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata); - }; -// [/SL:KB] - + BOOL isAgentUnderCursor() const { return mClosestAgentToCursor.notNull(); } LLMenuGL* mPopupMenu; }; diff --git a/indra/newview/llnotify.cpp b/indra/newview/llnotify.cpp index a223030b0..dfb65c3fb 100644 --- a/indra/newview/llnotify.cpp +++ b/indra/newview/llnotify.cpp @@ -35,22 +35,16 @@ #include "llnotify.h" #include "llchat.h" -#include "llfocusmgr.h" -#include "llrender.h" -#include "llbutton.h" -#include "llfocusmgr.h" -#include "llglheaders.h" #include "lliconctrl.h" +#include "llmenugl.h" #include "lltextbox.h" #include "lltexteditor.h" #include "lltrans.h" #include "lluiconstants.h" -#include "llui.h" -#include "llxmlnode.h" -#include "llviewercontrol.h" #include "llviewerdisplay.h" #include "llviewertexturelist.h" +#include "llviewerwindow.h" // for gViewerWindow #include "llfloaterchat.h" // for add_chat_history() #include "lloverlaybar.h" // for gOverlayBar #include "lluictrlfactory.h" @@ -234,23 +228,23 @@ LLNotifyBox::LLNotifyBox(LLNotificationPtr notification) const S32 MAX_LENGTH = 512 + 20 + DB_FIRST_NAME_BUF_SIZE + DB_LAST_NAME_BUF_SIZE + DB_INV_ITEM_NAME_BUF_SIZE; // For script dialogs: add space for title. - auto text = new LLTextEditor(std::string("box"), LLRect(x, y, getRect().getWidth()-2, mIsTip ? BOTTOM : BTN_TOP+16), MAX_LENGTH, LLStringUtil::null, sFont, FALSE, true); - text->setWordWrap(TRUE); - text->setMouseOpaque(TRUE); - text->setBorderVisible(FALSE); - text->setTakesNonScrollClicks(TRUE); - text->setHideScrollbarForShortDocs(TRUE); - text->setReadOnlyBgColor ( LLColor4::transparent ); // the background color of the box is manually + mText = new LLTextEditor(std::string("box"), LLRect(x, y, getRect().getWidth()-2, mIsTip ? BOTTOM : BTN_TOP+16), MAX_LENGTH, LLStringUtil::null, sFont, FALSE, true); + mText->setWordWrap(TRUE); + mText->setMouseOpaque(TRUE); + mText->setBorderVisible(FALSE); + mText->setTakesNonScrollClicks(TRUE); + mText->setHideScrollbarForShortDocs(TRUE); + mText->setReadOnlyBgColor ( LLColor4::transparent ); // the background color of the box is manually // rendered under the text box, therefore we want // the actual text box to be transparent auto text_color = gColors.getColor(mIsCaution && mIsTip ? "NotifyCautionWarnColor" : "NotifyTextColor"); - text->setReadOnlyFgColor(text_color); //sets caution text color for tip notifications + mText->setReadOnlyFgColor(text_color); //sets caution text color for tip notifications if (!mIsCaution) // We could do some extra color math here to determine if bg's too close to link color, but let's just cross with the link color instead - text->setLinkColor(new LLColor4(lerp(text_color, gSavedSettings.getColor4("HTMLLinkColor"), 0.4f))); - text->setTabStop(FALSE); // can't tab to it (may be a problem for scrolling via keyboard) - text->appendText(message,false,false,nullptr,!layout_script_dialog); // Now we can set the text, since colors have been set. - addChild(text); + mText->setLinkColor(new LLColor4(lerp(text_color, gSavedSettings.getColor4("HTMLLinkColor"), 0.4f))); + mText->setTabStop(FALSE); // can't tab to it (may be a problem for scrolling via keyboard) + mText->appendText(message,false,false,nullptr,!layout_script_dialog); // Now we can set the text, since colors have been set. + addChild(mText); } if (mIsTip) @@ -424,7 +418,8 @@ LLButton* LLNotifyBox::addButton(const std::string& name, const std::string& lab BOOL LLNotifyBox::handleMouseUp(S32 x, S32 y, MASK mask) { - if (mIsTip) + bool done = LLPanel::handleMouseUp(x, y, mask); + if (!done && mIsTip) { mNotification->respond(mNotification->getResponseTemplate(LLNotification::WITH_DEFAULT_BUTTON)); @@ -434,17 +429,34 @@ BOOL LLNotifyBox::handleMouseUp(S32 x, S32 y, MASK mask) setFocus(TRUE); - return LLPanel::handleMouseUp(x, y, mask); + return done; } // virtual BOOL LLNotifyBox::handleRightMouseDown(S32 x, S32 y, MASK mask) { - bool done = LLPanel::handleRightMouseDown(x, y, mask); - if (!done && !mIsTip) moveToBack(true); - return done || !mIsTip; + if (!LLPanel::handleRightMouseDown(x, y, mask)) // Allow Children to handle first + moveToBack(true); + return true; } +// virtual +BOOL LLNotifyBox::handleHover(S32 x, S32 y, MASK mask) +{ + if (mIsTip) mEventTimer.stop(); // Stop timer on hover so the user can interact + return LLPanel::handleHover(x, y, mask); +} + +bool LLNotifyBox::userIsInteracting() const +{ + // If the mouse is over us, the user may wish to interact + S32 local_x; + S32 local_y; + screenPointToLocal(gViewerWindow->getCurrentMouseX(), gViewerWindow->getCurrentMouseY(), &local_x, &local_y); + return pointInView(local_x, local_y) || // We're actively hovered + // our text is the target of an active menu that could be open (getVisibleMenu sucks because it contains a loop of two dynamic casts, so keep this at the end) + (mText && mText->getActive() == mText && LLMenuGL::sMenuContainer->getVisibleMenu()); +} // virtual void LLNotifyBox::draw() @@ -452,7 +464,7 @@ void LLNotifyBox::draw() // If we are teleporting, stop the timer and restart it when the teleporting completes if (gTeleportDisplay) mEventTimer.stop(); - else if (!mEventTimer.getStarted()) + else if (!mEventTimer.getStarted() && (!mIsTip || !userIsInteracting())) // If it's not a tip, we can resume instantly, otherwise the user may be interacting mEventTimer.start(); F32 display_time = mAnimateTimer.getElapsedTimeF32(); diff --git a/indra/newview/llnotify.h b/indra/newview/llnotify.h index fa85eb17e..4ea8ca9cb 100644 --- a/indra/newview/llnotify.h +++ b/indra/newview/llnotify.h @@ -43,7 +43,7 @@ class LLNotifyBoxTemplate; class LLTextEditor; // NotifyBox - for notifications that require a response from the user. -class LLNotifyBox : +class LLNotifyBox final : public LLPanel, public LLEventTimer, public LLInitClass, @@ -54,7 +54,7 @@ public: bool isTip() const { return mIsTip; } bool isCaution() const { return mIsCaution; } - /*virtual*/ void setVisible(BOOL visible); + /*virtual*/ void setVisible(BOOL visible) override; void stopAnimation() { mAnimating = false; } void close(); @@ -70,12 +70,14 @@ protected: LLButton* addButton(const std::string& name, const std::string& label, bool is_option, bool is_default, bool layout_script_dialog); - /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask) override; + /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask) override; + BOOL handleHover(S32 x, S32 y, MASK mask) override; + bool userIsInteracting() const; // Animate as sliding onto the screen. - /*virtual*/ void draw(); - /*virtual*/ BOOL tick(); + /*virtual*/ void draw() override; + /*virtual*/ BOOL tick() override; void moveToBack(bool getfocus = false); @@ -92,7 +94,7 @@ private: void drawBackground() const; protected: - LLTextEditor *mUserInputBox; + LLTextEditor *mUserInputBox = nullptr, *mText = nullptr; LLNotificationPtr mNotification; bool mIsTip; @@ -111,13 +113,13 @@ protected: bool mAddedDefaultBtn; }; -class LLNotifyBoxView : public LLUICtrl +class LLNotifyBoxView final : public LLUICtrl { public: LLNotifyBoxView(const std::string& name, const LLRect& rect, BOOL mouse_opaque, U32 follows=FOLLOWS_NONE); void showOnly(LLView* ctrl); LLNotifyBox* getFirstNontipBox() const; - /*virtual*/ void deleteAllChildren(); + /*virtual*/ void deleteAllChildren() override; struct Matcher { diff --git a/indra/newview/llpanelavatar.cpp b/indra/newview/llpanelavatar.cpp index 9fe61950d..d933b9a46 100644 --- a/indra/newview/llpanelavatar.cpp +++ b/indra/newview/llpanelavatar.cpp @@ -337,12 +337,21 @@ void LLPanelAvatarFirstLife::enableControls(BOOL self) void show_picture(const LLUUID& id, const std::string& name); static std::string profile_picture_title(const std::string& str) { return "Profile Picture: " + str; } static void show_partner_help() { LLNotificationsUtil::add("ClickPartnerHelpAvatar", LLSD(), LLSD(), boost::bind(LLPanelAvatarSecondLife::onClickPartnerHelpLoadURL, _1, _2)); } -void show_log_browser(const LLUUID& id) +void show_log_browser(const LLUUID& id, const LFIDBearer::Type& type) { void show_log_browser(const std::string& name, const std::string& id); - LLAvatarName av_name; - LLAvatarNameCache::get(id, &av_name); - show_log_browser(av_name.getLegacyName(), id.asString()); + std::string name; + if (type == LFIDBearer::AVATAR) + { + LLAvatarName av_name; + LLAvatarNameCache::get(id, &av_name); + name = av_name.getLegacyName(); + } + else // GROUP + { + gCacheName->getGroupName(id, name); + } + show_log_browser(name, id.asString()); } BOOL LLPanelAvatarSecondLife::postBuild() { @@ -368,7 +377,7 @@ BOOL LLPanelAvatarSecondLife::postBuild() getChild("GroupInvite_Button")->setCommitCallback(boost::bind(static_cast(LLAvatarActions::inviteToGroup), boost::bind(&LLPanelAvatar::getAvatarID, pa))); getChild("Add Friend...")->setCommitCallback(boost::bind(LLAvatarActions::requestFriendshipDialog, boost::bind(&LLPanelAvatar::getAvatarID, pa))); - getChild("Log")->setCommitCallback(boost::bind(show_log_browser, boost::bind(&LLPanelAvatar::getAvatarID, pa))); + getChild("Log")->setCommitCallback(boost::bind(show_log_browser, boost::bind(&LLPanelAvatar::getAvatarID, pa), LFIDBearer::AVATAR)); getChild("Pay...")->setCommitCallback(boost::bind(LLAvatarActions::pay, boost::bind(&LLPanelAvatar::getAvatarID, pa))); if (LLUICtrl* ctrl = findChild("Mute")) { @@ -1236,13 +1245,12 @@ void LLPanelAvatar::setOnlineStatus(EOnlineStatus online_status) void LLPanelAvatar::setAvatarID(const LLUUID &avatar_id) { - auto dnname = getChild("dnname"); if (avatar_id != mAvatarID) { if (mAvatarID.notNull()) LLAvatarPropertiesProcessor::getInstance()->removeObserver(mAvatarID, this); mAvatarID = avatar_id; - dnname->setNameID(avatar_id, false); + getChild("dnname")->setNameID(avatar_id, LFIDBearer::AVATAR); } if (avatar_id.isNull()) return; @@ -1271,8 +1279,6 @@ void LLPanelAvatar::setAvatarID(const LLUUID &avatar_id) if (LLDropTarget* drop_target = findChild("drop_target_rect")) drop_target->setEntityID(mAvatarID); - dnname->setShowCompleteName(gSavedSettings.getBOOL("SinguCompleteNameProfiles")); - if (auto key_edit = getChildView("avatar_key")) key_edit->setValue(mAvatarID.asString()); @@ -1331,8 +1337,6 @@ void LLPanelAvatar::setAvatarID(const LLUUID &avatar_id) view->setEnabled(false); getChildView("Log")->setVisible(!own_avatar); - getChild("avatar_key")->setText(avatar_id.asString()); - bool is_god = gAgent.isGodlike(); view = getChildView("Kick"); view->setVisible(is_god); @@ -1402,7 +1406,7 @@ void LLPanelAvatar::onClickCopy(const LLSD& val) } else { - void copy_profile_uri(const LLUUID& id, bool group = false); + void copy_profile_uri(const LLUUID& id, const LFIDBearer::Type& type = LFIDBearer::AVATAR); copy_profile_uri(mAvatarID); } } diff --git a/indra/newview/llpaneleditwearable.cpp b/indra/newview/llpaneleditwearable.cpp index 2cc567483..e179b971e 100644 --- a/indra/newview/llpaneleditwearable.cpp +++ b/indra/newview/llpaneleditwearable.cpp @@ -1680,7 +1680,7 @@ void LLPanelEditWearable::initPreviousAlphaTextures() initPreviousAlphaTextureEntry(TEX_UPPER_ALPHA); initPreviousAlphaTextureEntry(TEX_HEAD_ALPHA); initPreviousAlphaTextureEntry(TEX_EYES_ALPHA); - initPreviousAlphaTextureEntry(TEX_LOWER_ALPHA); + initPreviousAlphaTextureEntry(TEX_HAIR_ALPHA); } void LLPanelEditWearable::initPreviousAlphaTextureEntry(LLAvatarAppearanceDefines::ETextureIndex te) diff --git a/indra/newview/llpanelexperiencelisteditor.cpp b/indra/newview/llpanelexperiencelisteditor.cpp new file mode 100644 index 000000000..784fc9cfe --- /dev/null +++ b/indra/newview/llpanelexperiencelisteditor.cpp @@ -0,0 +1,280 @@ +/** + * @file llpanelexperiencelisteditor.cpp + * @brief Editor for building a list of experiences + * + * $LicenseInfo:firstyear=2014&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 "llpanelexperiencelisteditor.h" + +#include "llbutton.h" +#include "llexperiencecache.h" +#include "llfloaterexperiencepicker.h" +#include "llfloaterexperienceprofile.h" +//#include "llfloaterreg.h" +#include "llhandle.h" +#include "llnamelistctrl.h" +#include "llscrolllistctrl.h" +#include "llviewerregion.h" +#include "llagent.h" +#include "lltextbox.h" +#include "lltrans.h" + + +/* Singu Note: We do not have injectors, so we'll have to call this function instead +static LLPanelInjector t_panel_experience_list_editor("panel_experience_list_editor"); +*/ +void* create_xp_list_editor(void* data) +{ + return *reinterpret_cast(data) = new LLPanelExperienceListEditor; +} + + +LLPanelExperienceListEditor::LLPanelExperienceListEditor() + :mItems(nullptr) + ,mAdd(nullptr) + ,mRemove(nullptr) + ,mProfile(nullptr) + ,mAddedCallback() + ,mRemovedCallback() + ,mReadonly(false) + ,mMaxExperienceIDs(0) +{ +} + +BOOL LLPanelExperienceListEditor::postBuild() +{ + mItems = getChild("experience_list"); + mAdd = getChild("btn_add"); + mRemove = getChild("btn_remove"); + mProfile = getChild("btn_profile"); + + childSetAction("btn_add", boost::bind(&LLPanelExperienceListEditor::onAdd, this)); + childSetAction("btn_remove", boost::bind(&LLPanelExperienceListEditor::onRemove, this)); + childSetAction("btn_profile", boost::bind(&LLPanelExperienceListEditor::onProfile, this)); + + mItems->setCommitCallback(boost::bind(&LLPanelExperienceListEditor::checkButtonsEnabled, this)); + + checkButtonsEnabled(); + return TRUE; +} + +const uuid_list_t& LLPanelExperienceListEditor::getExperienceIds() const +{ + return mExperienceIds; +} + +void LLPanelExperienceListEditor::addExperienceIds( const uuid_vec_t& experience_ids ) +{ + // the commented out code in this function is handled by the callback and no longer necessary! + + //mExperienceIds.insert(experience_ids.begin(), experience_ids.end()); + //onItems(); + if(!mAddedCallback.empty()) + { + for(uuid_vec_t::const_iterator it = experience_ids.begin(); it != experience_ids.end(); ++it) + { + mAddedCallback(*it); + } + } +} + + +void LLPanelExperienceListEditor::setExperienceIds( const LLSD& experience_ids ) +{ + mExperienceIds.clear(); + for (const auto& id : experience_ids.array()) + { + // Using insert(range) doesn't work here because the conversion from + // LLSD to LLUUID is ambiguous: have to specify asUUID() for each entry. + mExperienceIds.insert(id.asUUID()); + } + onItems(); +} + +void LLPanelExperienceListEditor::addExperience( const LLUUID& id ) +{ + mExperienceIds.insert(id); + onItems(); +} +void LLPanelExperienceListEditor::onAdd() +{ + if(!mPicker.isDead()) + { + mPicker.markDead(); + } + + mKey.generateNewID(); + + LLFloaterExperiencePicker* picker = LLFloaterExperiencePicker::show(boost::bind(&LLPanelExperienceListEditor::addExperienceIds, this, _1), mKey, FALSE, TRUE, mFilters, mAdd); + mPicker = picker->getDerivedHandle(); +} + + +void LLPanelExperienceListEditor::onRemove() +{ + // the commented out code in this function is handled by the callback and no longer necessary! + + std::vector items= mItems->getAllSelected(); + std::vector::iterator it = items.begin(); + for(/**/; it != items.end(); ++it) + { + if((*it) != nullptr) + { + //mExperienceIds.erase((*it)->getValue()); + mRemovedCallback((*it)->getValue()); + } + } + mItems->selectFirstItem(); + checkButtonsEnabled(); + //onItems(); +} + +void LLPanelExperienceListEditor::onProfile() +{ + LLScrollListItem* item = mItems->getFirstSelected(); + if(item) + { + LLFloaterExperienceProfile::showInstance(item->getUUID()); + } +} + +void LLPanelExperienceListEditor::checkButtonsEnabled() +{ + mAdd->setEnabled(!mReadonly); + int selected = mItems->getNumSelected(); + + bool remove_enabled = !mReadonly && selected>0; + if(remove_enabled && mSticky) + { + std::vector items= mItems->getAllSelected(); + std::vector::iterator it = items.begin(); + for(/**/; it != items.end() && remove_enabled; ++it) + { + if((*it) != nullptr) + { + remove_enabled = !mSticky((*it)->getValue()); + } + } + + + } + mRemove->setEnabled(remove_enabled); + mProfile->setEnabled(selected==1); +} + +void LLPanelExperienceListEditor::onItems() +{ + mItems->deleteAllItems(); + + LLSD item; + uuid_list_t::iterator it = mExperienceIds.begin(); + for(/**/; it != mExperienceIds.end(); ++it) + { + const LLUUID& experience = *it; + item["id"]=experience; + item["target"] = LLNameListItem::EXPERIENCE; + LLSD& columns = item["columns"]; + columns[0]["column"] = "experience_name"; + columns[0]["value"] = getString("loading"); + mItems->addElement(item); + + LLExperienceCache::instance().get(experience, boost::bind(&LLPanelExperienceListEditor::experienceDetailsCallback, + getDerivedHandle(), _1)); + } + + + if(mItems->getItemCount() == 0) + { + mItems->setCommentText(getString("no_results")); + } + + + checkButtonsEnabled(); +} + +void LLPanelExperienceListEditor::experienceDetailsCallback( LLHandle panel, const LLSD& experience ) +{ + if(!panel.isDead()) + { + panel.get()->onExperienceDetails(experience); + } +} + +void LLPanelExperienceListEditor::onExperienceDetails( const LLSD& experience ) +{ + LLScrollListItem* item = mItems->getItem(experience[LLExperienceCache::EXPERIENCE_ID]); + if(!item) + return; + + std::string experience_name_string = experience[LLExperienceCache::NAME].asString(); + if (experience_name_string.empty()) + { + experience_name_string = LLTrans::getString("ExperienceNameUntitled"); + } + + item->getColumn(0)->setValue(experience_name_string); +} + +LLPanelExperienceListEditor::~LLPanelExperienceListEditor() +{ + if(!mPicker.isDead()) + { + mPicker.get()->close(); + } +} + +void LLPanelExperienceListEditor::loading() +{ + mItems->clear(); + mItems->setCommentText( getString("loading")); +} + +void LLPanelExperienceListEditor::setReadonly( bool val ) +{ + mReadonly = val; + checkButtonsEnabled(); +} + +void LLPanelExperienceListEditor::refreshExperienceCounter() +{ + if(mMaxExperienceIDs > 0) + { + LLStringUtil::format_map_t args; + args["[EXPERIENCES]"] = llformat("%d", mItems->getItemCount()); + args["[MAXEXPERIENCES]"] = llformat("%d", mMaxExperienceIDs); + getChild("text_count")->setText(LLTrans::getString("ExperiencesCounter", args)); + } +} + +boost::signals2::connection LLPanelExperienceListEditor::setAddedCallback( list_changed_signal_t::slot_type cb ) +{ + return mAddedCallback.connect(cb); +} + +boost::signals2::connection LLPanelExperienceListEditor::setRemovedCallback( list_changed_signal_t::slot_type cb ) +{ + return mRemovedCallback.connect(cb); +} + diff --git a/indra/newview/llpanelexperiencelisteditor.h b/indra/newview/llpanelexperiencelisteditor.h new file mode 100644 index 000000000..38b2c2179 --- /dev/null +++ b/indra/newview/llpanelexperiencelisteditor.h @@ -0,0 +1,102 @@ +/** +* @file llpanelexperiencelisteditor.cpp +* @brief Editor for building a list of experiences +* +* $LicenseInfo:firstyear=2014&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_LLPANELEXPERIENCELISTEDITOR_H +#define LL_LLPANELEXPERIENCELISTEDITOR_H + +#include "llpanel.h" +#include "lluuid.h" +#include + +class LLNameListCtrl; +class LLScrollListCtrl; +class LLButton; +class LLFloaterExperiencePicker; + +void* create_xp_list_editor(void* data); // +class LLPanelExperienceListEditor final : public LLPanel +{ +public: + + typedef boost::signals2::signal list_changed_signal_t; + // filter function for experiences, return true if the experience should be hidden. + typedef std::function experience_function; + typedef std::vector filter_list; + typedef LLHandle PickerHandle; + LLPanelExperienceListEditor(); + ~LLPanelExperienceListEditor(); + BOOL postBuild() override; + + void loading(); + + const uuid_list_t& getExperienceIds()const; + void setExperienceIds(const LLSD& experience_ids); + void addExperienceIds(const uuid_vec_t& experience_ids); + + void addExperience(const LLUUID& id); + + boost::signals2::connection setAddedCallback(list_changed_signal_t::slot_type cb ); + boost::signals2::connection setRemovedCallback(list_changed_signal_t::slot_type cb ); + + bool getReadonly() const { return mReadonly; } + void setReadonly(bool val); + + void refreshExperienceCounter(); + + void addFilter(experience_function func){mFilters.push_back(func);} + void setStickyFunction(experience_function func){mSticky = func;} + U32 getMaxExperienceIDs() const { return mMaxExperienceIDs; } + void setMaxExperienceIDs(U32 val) { mMaxExperienceIDs = val; } +private: + + void onItems(); + void onRemove(); + void onAdd(); + void onProfile(); + + void checkButtonsEnabled(); + static void experienceDetailsCallback( LLHandle panel, const LLSD& experience ); + void onExperienceDetails( const LLSD& experience ); + void processResponse( const LLSD& content ); + uuid_list_t mExperienceIds; + + + LLScrollListCtrl* mItems; + filter_list mFilters; + LLButton* mAdd; + LLButton* mRemove; + LLButton* mProfile; + PickerHandle mPicker; + list_changed_signal_t mAddedCallback; + list_changed_signal_t mRemovedCallback; + LLUUID mKey; + bool mReadonly; + experience_function mSticky; + U32 mMaxExperienceIDs; + +}; + +#endif //LL_LLPANELEXPERIENCELISTEDITOR_H diff --git a/indra/newview/llpanelexperiencelog.cpp b/indra/newview/llpanelexperiencelog.cpp new file mode 100644 index 000000000..fb866261a --- /dev/null +++ b/indra/newview/llpanelexperiencelog.cpp @@ -0,0 +1,270 @@ +/** + * @file llpanelexperiencelog.cpp + * @brief llpanelexperiencelog + * + * $LicenseInfo:firstyear=2014&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2014, 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 "llpanelexperiencelog.h" + +#include "llexperiencelog.h" +#include "llexperiencecache.h" +#include "llbutton.h" +#include "llscrolllistctrl.h" +#include "llcombobox.h" +#include "llspinctrl.h" +#include "llcheckboxctrl.h" +#include "llfloaterexperienceprofile.h" +//#include "llfloaterreg.h" +#include "lluictrlfactory.h" +#include "llfloaterreporter.h" +#include "llinventoryfunctions.h" + +#include + + +#define BTN_PROFILE_XP "btn_profile_xp" +#define BTN_REPORT_XP "btn_report_xp" + +/* Singu Note: We do not have injectors, so we'll have to call this function instead +static LLPanelInjector register_experiences_panel("experience_log"); +*/ +void* create_xp_log(void* data) { return new LLPanelExperienceLog(false); } + + +LLPanelExperienceLog::LLPanelExperienceLog(bool build) + : mEventList(nullptr) + , mPageSize(25) + , mCurrentPage(0) +{ + //buildFromFile("panel_experience_log.xml"); + if (build) LLUICtrlFactory::getInstance()->buildPanel(this, "panel_experience_log.xml"); // Singu Note: Use filename in xml +} + +BOOL LLPanelExperienceLog::postBuild( void ) +{ + LLExperienceLog* log = LLExperienceLog::getInstance(); + mEventList = getChild("experience_log_list"); + mEventList->setCommitCallback(boost::bind(&LLPanelExperienceLog::onSelectionChanged, this)); + mEventList->setDoubleClickCallback( boost::bind(&LLPanelExperienceLog::onProfileExperience, this)); + + getChild("btn_clear")->setCommitCallback(boost::bind(&LLExperienceLog::clear, log)); + getChild("btn_clear")->setCommitCallback(boost::bind(&LLPanelExperienceLog::refresh, this)); + + getChild(BTN_PROFILE_XP)->setCommitCallback(boost::bind(&LLPanelExperienceLog::onProfileExperience, this)); + getChild(BTN_REPORT_XP )->setCommitCallback(boost::bind(&LLPanelExperienceLog::onReportExperience, this)); + getChild("btn_notify" )->setCommitCallback(boost::bind(&LLPanelExperienceLog::onNotify, this)); + getChild("btn_next" )->setCommitCallback(boost::bind(&LLPanelExperienceLog::onNext, this)); + getChild("btn_prev" )->setCommitCallback(boost::bind(&LLPanelExperienceLog::onPrev, this)); + + LLCheckBoxCtrl* check = getChild("notify_all"); + check->set(log->getNotifyNewEvent()); + check->setCommitCallback(boost::bind(&LLPanelExperienceLog::notifyChanged, this)); + + + LLSpinCtrl* spin = getChild("logsizespinner"); + spin->set(log->getMaxDays()); + spin->setCommitCallback(boost::bind(&LLPanelExperienceLog::logSizeChanged, this)); + + mPageSize = log->getPageSize(); + refresh(); + mNewEvent = LLExperienceLog::instance().addUpdateSignal(boost::bind(&LLPanelExperienceLog::refresh, this)); + return TRUE; +} + +LLPanelExperienceLog* LLPanelExperienceLog::create() +{ + return new LLPanelExperienceLog(); +} + +void LLPanelExperienceLog::refresh() +{ + S32 selected = mEventList->getFirstSelectedIndex(); + mEventList->deleteAllItems(); + const LLSD events = LLExperienceLog::instance().getEvents(); + + if(events.size() == 0) + { + mEventList->setCommentText(getString("no_events")); + return; + } + + setAllChildrenEnabled(FALSE); + + LLSD item; + bool waiting = false; + LLUUID waiting_id; + + U32 itemsToSkip = mPageSize*mCurrentPage; + U32 items = 0; + bool moreItems = false; + + if (!events.emptyMap()) + { + for (const auto& day : boost::adaptors::reverse(events.map())) + { + const std::string& date = day.first; + if (LLExperienceLog::instance().isExpired(date)) + { + continue; + } + const LLSD& dayArray = day.second; + U32 size = dayArray.size(); + if(itemsToSkip > size) + { + itemsToSkip -= size; + continue; + } + if(items >= mPageSize && size > 0) + { + moreItems = true; + break; + } + for(int i = dayArray.size() - itemsToSkip - 1; i >= 0; i--) + { + if (items >= mPageSize) + { + moreItems = true; + break; + } + const LLSD event = dayArray[i]; + LLUUID id = event[LLExperienceCache::EXPERIENCE_ID].asUUID(); + const LLSD& experience = LLExperienceCache::instance().get(id); + if(experience.isUndefined()){ + waiting = true; + waiting_id = id; + } + if(!waiting) + { + item["id"] = event; + + LLSD& columns = item["columns"]; + columns[0]["column"] = "time"; + columns[0]["value"] = day.first+event["Time"].asString(); + columns[1]["column"] = "event"; + columns[1]["value"] = LLExperienceLog::getPermissionString(event, "ExperiencePermissionShort"); + columns[2]["column"] = "experience_name"; + columns[2]["value"] = experience[LLExperienceCache::NAME].asString(); + columns[3]["column"] = "object_name"; + columns[3]["value"] = event["ObjectName"].asString(); + mEventList->addElement(item); + } + ++items; + } + } + } + if (waiting) + { + mEventList->deleteAllItems(); + mEventList->setCommentText(getString("loading")); + LLExperienceCache::instance().get(waiting_id, boost::bind(&LLPanelExperienceLog::refresh, this)); + } + else + { + setAllChildrenEnabled(TRUE); + + mEventList->setEnabled(TRUE); + getChild("btn_next")->setEnabled(moreItems); + getChild("btn_prev")->setEnabled(mCurrentPage>0); + getChild("btn_clear")->setEnabled(mEventList->getItemCount()>0); + if (selected < 0) + { + selected = 0; + } + mEventList->selectNthItem(selected); + onSelectionChanged(); + } +} + +void LLPanelExperienceLog::onProfileExperience() +{ + LLSD event = getSelectedEvent(); + if (event.isDefined()) + { + LLFloaterExperienceProfile::showInstance(event[LLExperienceCache::EXPERIENCE_ID].asUUID()); + } +} + +void LLPanelExperienceLog::onReportExperience() +{ + LLSD event = getSelectedEvent(); + if (event.isDefined()) + { + LLFloaterReporter::showFromExperience(event[LLExperienceCache::EXPERIENCE_ID].asUUID()); + } +} + +void LLPanelExperienceLog::onNotify() +{ + LLSD event = getSelectedEvent(); + if (event.isDefined()) + { + LLExperienceLog::instance().notify(event); + } +} + +void LLPanelExperienceLog::onNext() +{ + mCurrentPage++; + refresh(); +} + +void LLPanelExperienceLog::onPrev() +{ + if(mCurrentPage>0) + { + mCurrentPage--; + refresh(); + } +} + +void LLPanelExperienceLog::notifyChanged() +{ + LLExperienceLog::instance().setNotifyNewEvent(getChild("notify_all")->get()); +} + +void LLPanelExperienceLog::logSizeChanged() +{ + int value = (int)(getChild("logsizespinner")->get()); + LLExperienceLog::instance().setMaxDays(value); + refresh(); +} + +void LLPanelExperienceLog::onSelectionChanged() +{ + bool enabled = (1 == mEventList->getNumSelected()); + getChild(BTN_REPORT_XP)->setEnabled(enabled); + getChild(BTN_PROFILE_XP)->setEnabled(enabled); + getChild("btn_notify")->setEnabled(enabled); +} + +LLSD LLPanelExperienceLog::getSelectedEvent() +{ + LLScrollListItem* item = mEventList->getFirstSelected(); + if(item) + { + return item->getValue(); + } + return LLSD(); +} diff --git a/indra/newview/llpanelexperiencelog.h b/indra/newview/llpanelexperiencelog.h new file mode 100644 index 000000000..03e50a604 --- /dev/null +++ b/indra/newview/llpanelexperiencelog.h @@ -0,0 +1,65 @@ +/** + * @file llpanelexperiencelog.h + * @brief llpanelexperiencelog and related class definitions + * + * $LicenseInfo:firstyear=2014&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2014, 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_LLPANELEXPERIENCELOG_H +#define LL_LLPANELEXPERIENCELOG_H + +#include "llpanel.h" +class LLScrollListCtrl; + +void* create_xp_log(void* data); +class LLPanelExperienceLog final + : public LLPanel +{ +public: + + LLPanelExperienceLog(bool build = true); + + static LLPanelExperienceLog* create(); + + /*virtual*/ BOOL postBuild(void) override; + + void refresh() override; +protected: + void logSizeChanged(); + void notifyChanged(); + void onNext(); + void onNotify(); + void onPrev(); + void onProfileExperience(); + void onReportExperience(); + void onSelectionChanged(); + + LLSD getSelectedEvent(); +private: + LLScrollListCtrl* mEventList; + U32 mPageSize; + U32 mCurrentPage; + boost::signals2::scoped_connection mNewEvent; +}; + +#endif // LL_LLPANELEXPERIENCELOG_H diff --git a/indra/newview/llpanelexperiencepicker.cpp b/indra/newview/llpanelexperiencepicker.cpp new file mode 100644 index 000000000..00993d1ec --- /dev/null +++ b/indra/newview/llpanelexperiencepicker.cpp @@ -0,0 +1,453 @@ +/** +* @file llpanelexperiencepicker.cpp +* @brief Implementation of llpanelexperiencepicker +* @author dolphin@lindenlab.com +* +* $LicenseInfo:firstyear=2014&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2014, 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 "llpanelexperiencepicker.h" + + +#include "lllineeditor.h" +#include "llfloaterexperienceprofile.h" +//#include "llfloaterreg.h" +#include "lluictrlfactory.h" +#include "llscrolllistctrl.h" +#include "llviewerregion.h" +#include "llagent.h" +#include "llexperiencecache.h" +#include "llslurl.h" +#include "llavatarnamecache.h" +#include "llcombobox.h" +#include "llviewercontrol.h" +#include "llfloater.h" +#include "lltrans.h" +#include + +#define BTN_FIND "find" +#define BTN_OK "ok_btn" +#define BTN_CANCEL "cancel_btn" +#define BTN_PROFILE "profile_btn" +#define BTN_LEFT "left_btn" +#define BTN_RIGHT "right_btn" +#define TEXT_EDIT "edit" +#define TEXT_MATURITY "maturity" +#define LIST_RESULTS "search_results" +#define PANEL_SEARCH "search_panel" + +const static std::string columnSpace = " "; + +/* Singu Note: We do not have injectors, so we'll have to call this function instead +static LLPanelInjector t_panel_status("llpanelexperiencepicker"); +*/ +void* create_xp_picker(void* data) { return new LLPanelExperiencePicker(false); } + +LLPanelExperiencePicker::LLPanelExperiencePicker(bool build) + :LLPanel() +{ + //buildFromFile("panel_experience_search.xml"); + if (build) LLUICtrlFactory::getInstance()->buildPanel(this, "panel_experience_search.xml"); // Singu Note: Use filename in xml + setDefaultFilters(); +} + +LLPanelExperiencePicker::~LLPanelExperiencePicker() +{ +} + +BOOL LLPanelExperiencePicker::postBuild() +{ + getChild(TEXT_EDIT)->setKeystrokeCallback(boost::bind(&LLPanelExperiencePicker::editKeystroke, this, _1)); + + childSetAction(BTN_FIND, boost::bind(&LLPanelExperiencePicker::onBtnFind, this)); + getChildView(BTN_FIND)->setEnabled(TRUE); + + LLScrollListCtrl* searchresults = getChild(LIST_RESULTS); + searchresults->setDoubleClickCallback( boost::bind(&LLPanelExperiencePicker::onBtnSelect, this)); + searchresults->setCommitCallback(boost::bind(&LLPanelExperiencePicker::onList, this)); + getChildView(LIST_RESULTS)->setEnabled(FALSE); + getChild(LIST_RESULTS)->setCommentText(getString("no_results")); + + childSetAction(BTN_OK, boost::bind(&LLPanelExperiencePicker::onBtnSelect, this)); + getChildView(BTN_OK)->setEnabled(FALSE); + childSetAction(BTN_CANCEL, boost::bind(&LLPanelExperiencePicker::onBtnClose, this)); + childSetAction(BTN_PROFILE, boost::bind(&LLPanelExperiencePicker::onBtnProfile, this)); + getChildView(BTN_PROFILE)->setEnabled(FALSE); + + getChild(TEXT_MATURITY)->setCurrentByIndex(2); + getChild(TEXT_MATURITY)->setCommitCallback(boost::bind(&LLPanelExperiencePicker::onMaturity, this)); + getChild(TEXT_EDIT)->setFocus(TRUE); + + childSetAction(BTN_LEFT, boost::bind(&LLPanelExperiencePicker::onPage, this, -1)); + childSetAction(BTN_RIGHT, boost::bind(&LLPanelExperiencePicker::onPage, this, 1)); + + LLPanel* search_panel = getChild(PANEL_SEARCH); + if (search_panel) + { + // Start searching when Return is pressed in the line editor. + search_panel->setDefaultBtn(BTN_FIND); + } + return TRUE; +} + +void LLPanelExperiencePicker::editKeystroke(class LLLineEditor* caller) +{ + getChildView(BTN_FIND)->setEnabled(!caller->getText().empty()); +} + +void LLPanelExperiencePicker::onBtnFind() +{ + mCurrentPage=1; + boost::cmatch what; + std::string text = getChild(TEXT_EDIT)->getValue().asString(); + // *TODO: this should be part of LLUrlEntry + static const boost::regex expression("secondlife:///app/experience/[\\da-f-]+/profile"); + if (boost::regex_match(text.c_str(), what, expression)) + { + LLURI uri(text); + LLSD path_array = uri.pathArray(); + if (path_array.size() == 4) + { + std::string exp_id = path_array.get(2).asString(); + LLUUID experience_id(exp_id); + if (!experience_id.isNull()) + { + const LLSD& experience_details = LLExperienceCache::instance().get(experience_id); + if(!experience_details.isUndefined()) + { + std::string experience_name_string = experience_details[LLExperienceCache::NAME].asString(); + if(!experience_name_string.empty()) + { + getChild(TEXT_EDIT)->setValue(experience_name_string); + } + } + else + { + getChild(LIST_RESULTS)->deleteAllItems(); + getChild(LIST_RESULTS)->setCommentText(getString("searching")); + + getChildView(BTN_OK)->setEnabled(FALSE); + getChildView(BTN_PROFILE)->setEnabled(FALSE); + + getChildView(BTN_RIGHT)->setEnabled(FALSE); + getChildView(BTN_LEFT)->setEnabled(FALSE); + LLExperienceCache::instance().get(experience_id, boost::bind(&LLPanelExperiencePicker::onBtnFind, this)); + return; + } + } + } + } + + + find(); +} + +void LLPanelExperiencePicker::onList() +{ + bool enabled = isSelectButtonEnabled(); + getChildView(BTN_OK)->setEnabled(enabled); + + enabled = enabled && getChild(LIST_RESULTS)->getNumSelected() == 1; + getChildView(BTN_PROFILE)->setEnabled(enabled); +} + +void LLPanelExperiencePicker::find() +{ + std::string text = getChild(TEXT_EDIT)->getValue().asString(); + mQueryID.generate(); + + LLExperienceCache::instance().findExperienceByName(text, mCurrentPage, + boost::bind(&LLPanelExperiencePicker::findResults, getDerivedHandle(), mQueryID, _1)); + + getChild(LIST_RESULTS)->deleteAllItems(); + getChild(LIST_RESULTS)->setCommentText(getString("searching")); + + getChildView(BTN_OK)->setEnabled(FALSE); + getChildView(BTN_PROFILE)->setEnabled(FALSE); + + getChildView(BTN_RIGHT)->setEnabled(FALSE); + getChildView(BTN_LEFT)->setEnabled(FALSE); +} + +/*static*/ +void LLPanelExperiencePicker::findResults(LLHandle hparent, LLUUID queryId, LLSD foundResult) +{ + if (hparent.isDead()) + return; + + LLPanelExperiencePicker* panel = hparent.get(); + if (panel) + { + panel->processResponse(queryId, foundResult); + } +} + +bool LLPanelExperiencePicker::isSelectButtonEnabled() +{ + LLScrollListCtrl* list=getChild(LIST_RESULTS); + return list->getFirstSelectedIndex() >=0; +} + +void LLPanelExperiencePicker::getSelectedExperienceIds( const LLScrollListCtrl* results, uuid_vec_t &experience_ids ) +{ + std::vector items = results->getAllSelected(); + for(std::vector::iterator it = items.begin(); it != items.end(); ++it) + { + LLScrollListItem* item = *it; + if (item->getUUID().notNull()) + { + experience_ids.push_back(item->getUUID()); + } + } +} + +void LLPanelExperiencePicker::setAllowMultiple( bool allow_multiple ) +{ + getChild(LIST_RESULTS)->setAllowMultipleSelection(allow_multiple); +} + + +void name_callback(const LLHandle& floater, const LLUUID& experience_id, const LLUUID& agent_id, const LLAvatarName& av_name) +{ + if (floater.isDead()) + return; + LLPanelExperiencePicker* picker = floater.get(); + LLScrollListCtrl* search_results = picker->getChild(LIST_RESULTS); + + LLScrollListItem* item = search_results->getItem(experience_id); + if (!item) + return; + + item->getColumn(2)->setValue(columnSpace+av_name.getNSName()); + +} + +void LLPanelExperiencePicker::processResponse( const LLUUID& query_id, const LLSD& content ) +{ + if (query_id != mQueryID) + { + return; + } + + mResponse = content; + + getChildView(BTN_RIGHT)->setEnabled(content.has("next_page_url")); + getChildView(BTN_LEFT)->setEnabled(content.has("previous_page_url")); + + filterContent(); + +} + +void LLPanelExperiencePicker::onBtnSelect() +{ + if (!isSelectButtonEnabled()) + { + return; + } + + if(mSelectionCallback != nullptr) + { + const LLScrollListCtrl* results = getChild(LIST_RESULTS); + uuid_vec_t experience_ids; + + getSelectedExperienceIds(results, experience_ids); + mSelectionCallback(experience_ids); + getChild(LIST_RESULTS)->deselectAllItems(TRUE); + if (mCloseOnSelect) + { + mCloseOnSelect = FALSE; + onBtnClose(); + } + } + else + { + onBtnProfile(); + } +} + +void LLPanelExperiencePicker::onBtnClose() +{ + LLFloater* floater = static_cast(getParent()); + if (floater) + { + floater->close(); + } +} + +void LLPanelExperiencePicker::onBtnProfile() +{ + LLScrollListItem* item = getChild(LIST_RESULTS)->getFirstSelected(); + if (item) + { + LLFloaterExperienceProfile::showInstance(item->getUUID()); + } +} + +std::string LLPanelExperiencePicker::getMaturityString(int maturity) +{ + if (maturity <= SIM_ACCESS_PG) + { + return getString("maturity_icon_general"); + } + else if (maturity <= SIM_ACCESS_MATURE) + { + return getString("maturity_icon_moderate"); + } + return getString("maturity_icon_adult"); +} + +void LLPanelExperiencePicker::filterContent() +{ + LLScrollListCtrl* search_results = getChild(LIST_RESULTS); + + const LLSD& experiences=mResponse["experience_keys"]; + + search_results->deleteAllItems(); + + LLSD item; + for (const auto& experience : experiences.array()) + { + if (isExperienceHidden(experience)) + continue; + + std::string experience_name_string = experience[LLExperienceCache::NAME].asString(); + if (experience_name_string.empty()) + { + experience_name_string = LLTrans::getString("ExperienceNameUntitled"); + } + + item["id"]=experience[LLExperienceCache::EXPERIENCE_ID]; + LLSD& columns = item["columns"]; + columns[0]["column"] = "maturity"; + columns[0]["value"] = getMaturityString(experience[LLExperienceCache::MATURITY].asInteger()); + columns[0]["type"]="icon"; + columns[0]["halign"]="right"; + columns[1]["column"] = "experience_name"; + columns[1]["value"] = columnSpace+experience_name_string; + columns[2]["column"] = "owner"; + columns[2]["value"] = columnSpace+getString("loading"); + search_results->addElement(item); + LLAvatarNameCache::get(experience[LLExperienceCache::AGENT_ID], boost::bind(name_callback, getDerivedHandle(), experience[LLExperienceCache::EXPERIENCE_ID], _1, _2)); + } + + if (search_results->isEmpty()) + { + LLStringUtil::format_map_t map; + std::string search_text = getChild(TEXT_EDIT)->getValue().asString(); + map["[TEXT]"] = search_text; + if (search_text.empty()) + { + getChild(LIST_RESULTS)->setCommentText(getString("no_results")); + } + else + { + getChild(LIST_RESULTS)->setCommentText(getString("not_found", map)); + } + search_results->setEnabled(false); + getChildView(BTN_OK)->setEnabled(false); + getChildView(BTN_PROFILE)->setEnabled(false); + } + else + { + getChildView(BTN_OK)->setEnabled(true); + search_results->setEnabled(true); + search_results->sortByColumnIndex(1, TRUE); + std::string text = getChild(TEXT_EDIT)->getValue().asString(); + if (!search_results->selectItemByLabel(text, TRUE)) + { + search_results->selectFirstItem(); + } + onList(); + search_results->setFocus(TRUE); + } +} + +void LLPanelExperiencePicker::onMaturity() +{ + if (mResponse.has("experience_keys") && mResponse["experience_keys"].beginArray() != mResponse["experience_keys"].endArray()) + { + filterContent(); + } +} + +bool LLPanelExperiencePicker::isExperienceHidden( const LLSD& experience) const +{ + bool hide=false; + filter_list::const_iterator it = mFilters.begin(); + for(/**/;it != mFilters.end(); ++it) + { + if ((*it)(experience)){ + return true; + } + } + + return hide; +} + +bool LLPanelExperiencePicker::FilterOverRating( const LLSD& experience ) +{ + int maturity = getChild(TEXT_MATURITY)->getSelectedValue().asInteger(); + return experience[LLExperienceCache::MATURITY].asInteger() > maturity; +} + +bool LLPanelExperiencePicker::FilterWithProperty( const LLSD& experience, S32 prop) +{ + return (experience[LLExperienceCache::PROPERTIES].asInteger() & prop) != 0; +} + +bool LLPanelExperiencePicker::FilterWithoutProperties( const LLSD& experience, S32 prop) +{ + return ((experience[LLExperienceCache::PROPERTIES].asInteger() & prop) == prop); +} + +bool LLPanelExperiencePicker::FilterWithoutProperty( const LLSD& experience, S32 prop ) +{ + return (experience[LLExperienceCache::PROPERTIES].asInteger() & prop) == 0; +} + +void LLPanelExperiencePicker::setDefaultFilters() +{ + mFilters.clear(); + addFilter(boost::bind(&LLPanelExperiencePicker::FilterOverRating, this, _1)); +} + +bool LLPanelExperiencePicker::FilterMatching( const LLSD& experience, const LLUUID& id ) +{ + if (experience.isUUID()) + { + return experience.asUUID() == id; + } + return experience[LLExperienceCache::EXPERIENCE_ID].asUUID() == id; +} + +void LLPanelExperiencePicker::onPage( S32 direction ) +{ + mCurrentPage += direction; + if (mCurrentPage < 1) + { + mCurrentPage = 1; + } + find(); +} + diff --git a/indra/newview/llpanelexperiencepicker.h b/indra/newview/llpanelexperiencepicker.h new file mode 100644 index 000000000..ba3e5d299 --- /dev/null +++ b/indra/newview/llpanelexperiencepicker.h @@ -0,0 +1,96 @@ +/** +* @file llpanelexperiencepicker.h +* @brief Header file for llpanelexperiencepicker +* @author dolphin@lindenlab.com +* +* $LicenseInfo:firstyear=2014&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2014, 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_LLPANELEXPERIENCEPICKER_H +#define LL_LLPANELEXPERIENCEPICKER_H + +#include "llpanel.h" + +class LLScrollListCtrl; +class LLLineEditor; + +void* create_xp_picker(void* data); +class LLPanelExperiencePicker final : public LLPanel +{ +public: + friend class LLExperienceSearchResponder; + friend class LLFloaterExperiencePicker; + + typedef std::function select_callback_t; + // filter function for experiences, return true if the experience should be hidden. + typedef std::function filter_function; + typedef std::vector filter_list; + + LLPanelExperiencePicker(bool build = true); + virtual ~LLPanelExperiencePicker(); + + BOOL postBuild() override; + + void addFilter(filter_function func){mFilters.push_back(func);} + template + void addFilters(IT begin, IT end){mFilters.insert(mFilters.end(), begin, end);} + void setDefaultFilters(); + + static bool FilterWithProperty(const LLSD& experience, S32 prop); + static bool FilterWithoutProperties(const LLSD& experience, S32 prop); + static bool FilterWithoutProperty(const LLSD& experience, S32 prop); + static bool FilterMatching(const LLSD& experience, const LLUUID& id); + bool FilterOverRating(const LLSD& experience); + +private: + void editKeystroke(LLLineEditor* caller); + + void onBtnFind(); + void onBtnSelect(); + void onBtnClose(); + void onBtnProfile(); + void onList(); + void onMaturity(); + void onPage(S32 direction); + + void getSelectedExperienceIds( const LLScrollListCtrl* results, uuid_vec_t &experience_ids ); + void setAllowMultiple(bool allow_multiple); + + void find(); + static void findResults(LLHandle hparent, LLUUID queryId, LLSD foundResult); + + bool isSelectButtonEnabled(); + void processResponse( const LLUUID& query_id, const LLSD& content ); + + void filterContent(); + bool isExperienceHidden(const LLSD& experience) const ; + std::string getMaturityString(int maturity); + + + select_callback_t mSelectionCallback; + filter_list mFilters; + LLUUID mQueryID; + LLSD mResponse; + bool mCloseOnSelect; + S32 mCurrentPage; +}; + +#endif // LL_LLPANELEXPERIENCEPICKER_H diff --git a/indra/newview/llpanelexperiences.cpp b/indra/newview/llpanelexperiences.cpp new file mode 100644 index 000000000..97473a006 --- /dev/null +++ b/indra/newview/llpanelexperiences.cpp @@ -0,0 +1,152 @@ +/** + * @file llpanelexperiences.cpp + * @brief LLPanelExperiences class implementation + * + * $LicenseInfo:firstyear=2013&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2013, 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 "lluictrlfactory.h" +#include "llexperiencecache.h" +#include "llagent.h" + +#include "llfloaterexperienceprofile.h" +#include "llpanelexperiences.h" +#include "lllayoutstack.h" +#include "llnamelistctrl.h" + +//static LLPanelInjector register_experiences_panel("experiences_panel"); + +LLPanelExperiences::LLPanelExperiences() + : mExperiencesList(nullptr) +{ + //buildFromFile("panel_experiences.xml"); + LLUICtrlFactory::getInstance()->buildPanel(this, "panel_experiences.xml"); +} + +BOOL LLPanelExperiences::postBuild( void ) +{ + mExperiencesList = getChild("experiences_list"); + if (hasString("loading_experiences")) + { + mExperiencesList->setCommentText(getString("loading_experiences")); + } + else if (hasString("no_experiences")) + { + mExperiencesList->setCommentText(getString("no_experiences")); + } + + return TRUE; +} + +void addExperienceToList(const LLSD& experience, LLNameListCtrl* list) +{ + // Don't add missing experiences, that seems wrong + if (experience.has(LLExperienceCache::MISSING) && experience[LLExperienceCache::MISSING].asBoolean()) + return; + + const auto& id = experience[LLExperienceCache::EXPERIENCE_ID]; + list->removeNameItem(id); // Don't add the same item twice, this can happen + auto item = LLNameListCtrl::NameItem() + .name(experience[LLExperienceCache::NAME].asString()) + .target(LLNameListItem::EXPERIENCE); + item.value(id) + .columns.add(LLScrollListCell::Params()); // Dummy column for names + list->addNameItemRow(item); +} + +void LLPanelExperiences::setExperienceList( const LLSD& experiences ) +{ + mExperiencesList->setSortEnabled(false); + + if (hasString("no_experiences")) + { + mExperiencesList->setCommentText(getString("no_experiences")); + } + mExperiencesList->clear(); + + auto& cache = LLExperienceCache::instance(); + for(const auto& exp : experiences.array()) + { + LLUUID public_key = exp.asUUID(); + if (public_key.notNull()) + cache.get(public_key, boost::bind(addExperienceToList, _1, mExperiencesList)); + } + + mExperiencesList->setSortEnabled(true); +} + +void LLPanelExperiences::getExperienceIdsList(uuid_vec_t& result) +{ + result = mExperiencesList->getAllIDs(); +} + +LLPanelExperiences* LLPanelExperiences::create(const std::string& name) +{ + LLPanelExperiences* panel= new LLPanelExperiences(); + panel->setName(name); + return panel; +} + +void LLPanelExperiences::removeExperiences( const LLSD& ids ) +{ + for (const auto& id : ids.array()) + { + removeExperience(id.asUUID()); + } +} + +void LLPanelExperiences::removeExperience( const LLUUID& id ) +{ + mExperiencesList->removeNameItem(id); +} + +void LLPanelExperiences::addExperience( const LLUUID& id ) +{ + if (!mExperiencesList->getItem(id)) + { + LLExperienceCache::instance().get(id, boost::bind(addExperienceToList, _1, mExperiencesList)); + } +} + +void LLPanelExperiences::setButtonAction(const std::string& label, const commit_signal_t::slot_type& cb ) +{ + if(label.empty()) + { + getChild("button_panel")->setVisible(false); + } + else + { + getChild("button_panel")->setVisible(true); + LLButton* child = getChild("btn_action"); + child->setCommitCallback(cb); + child->setLabel(getString(label)); + } +} + +void LLPanelExperiences::enableButton( bool enable ) +{ + getChild("btn_action")->setEnabled(enable); +} diff --git a/indra/newview/llpanelexperiences.h b/indra/newview/llpanelexperiences.h new file mode 100644 index 000000000..31e9d1a00 --- /dev/null +++ b/indra/newview/llpanelexperiences.h @@ -0,0 +1,54 @@ +/** + * @file llpanelexperiences.h + * @brief LLPanelExperiences class definition + * + * $LicenseInfo:firstyear=2013&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2013, 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_LLPANELEXPERIENCES_H +#define LL_LLPANELEXPERIENCES_H + +#include "llpanel.h" + +class LLPanelExperiences final + : public LLPanel +{ +public: + LLPanelExperiences(); + + static LLPanelExperiences* create(const std::string& name); + + /*virtual*/ BOOL postBuild(void) override; + + void setExperienceList(const LLSD& experiences); + void getExperienceIdsList(uuid_vec_t& result); + + void removeExperiences( const LLSD& ids ); + void removeExperience( const LLUUID& id); + void addExperience( const LLUUID& id); + void setButtonAction(const std::string& label, const commit_signal_t::slot_type& cb); + void enableButton(bool enable); + +private: + class LLNameListCtrl* mExperiencesList; +}; +#endif // LL_LLPANELEXPERIENCES_H diff --git a/indra/newview/llpanelgroup.cpp b/indra/newview/llpanelgroup.cpp index 4e65628bb..56e61a559 100644 --- a/indra/newview/llpanelgroup.cpp +++ b/indra/newview/llpanelgroup.cpp @@ -34,6 +34,7 @@ #include "llpanelgroup.h" // Library includes +#include "lfidbearer.h" #include "llbutton.h" #include "lltabcontainer.h" #include "lltextbox.h" @@ -53,6 +54,9 @@ #include "llpanelgrouproles.h" #include "llpanelgroupvoting.h" #include "llpanelgrouplandmoney.h" +#include "llpanelgroupexperiences.h" + +#include "hippogridmanager.h" // static void* LLPanelGroupTab::createTab(void* data) @@ -129,7 +133,7 @@ void LLPanelGroupTab::handleClickHelp() } } -void copy_profile_uri(const LLUUID& id, bool group); +void copy_profile_uri(const LLUUID& id, const LFIDBearer::Type& type); LLPanelGroup::LLPanelGroup(const LLUUID& group_id) : LLPanel("PanelGroup", LLRect(), FALSE), @@ -153,6 +157,8 @@ LLPanelGroup::LLPanelGroup(const LLUUID& group_id) &mID); mFactoryMap["land_money_tab"]= LLCallbackMap(LLPanelGroupLandMoney::createTab, &mID); + mFactoryMap["experiences_tab"] = LLCallbackMap(LLPanelGroupExperiences::createTab, + &mID); // Roles sub tabs mFactoryMap["members_sub_tab"] = LLCallbackMap(LLPanelGroupMembersSubTab::createTab, &mID); mFactoryMap["roles_sub_tab"] = LLCallbackMap(LLPanelGroupRolesSubTab::createTab, &mID); @@ -161,7 +167,7 @@ LLPanelGroup::LLPanelGroup(const LLUUID& group_id) LLGroupMgr::getInstance()->addObserver(this); - mCommitCallbackRegistrar.add("Group.CopyURI", boost::bind(copy_profile_uri, boost::ref(mID), true)); + mCommitCallbackRegistrar.add("Group.CopyURI", boost::bind(copy_profile_uri, boost::ref(mID), LFIDBearer::GROUP)); // Pass on construction of this panel to the control factory. LLUICtrlFactory::getInstance()->buildPanel(this, "panel_group.xml", &getFactoryMap()); } @@ -208,6 +214,14 @@ BOOL LLPanelGroup::postBuild() if (mTabContainer) { + // Group Voting no longer exists on SecondLife, hide it + if (gHippoGridManager->getConnectedGrid()->isSecondLife()) + { + auto panel = mTabContainer->getPanelByName("voting_tab"); + mTabContainer->removeTabPanel(panel); + delete panel; + } + //our initial tab selection was invalid, just select the //first tab then or default to selecting the initial //selected tab specified in the layout file diff --git a/indra/newview/llpanelgroupexperiences.cpp b/indra/newview/llpanelgroupexperiences.cpp new file mode 100644 index 000000000..76553b433 --- /dev/null +++ b/indra/newview/llpanelgroupexperiences.cpp @@ -0,0 +1,130 @@ +/** + * @file llpanelgroupexperiences.cpp + * @brief List of experiences owned by a group. + * + * $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 "llpanelgroupexperiences.h" + +#include "lluictrlfactory.h" +#include "llappviewer.h" +#include "llexperiencecache.h" +#include "llnamelistctrl.h" + +void addExperienceToList(const LLSD& experience, LLNameListCtrl* list); + +//static LLPanelInjector t_panel_group_experiences("panel_group_experiences"); +//static +void* LLPanelGroupExperiences::createTab(void* data) +{ + LLUUID* group_id = static_cast(data); + return new LLPanelGroupExperiences("panel group experiences", *group_id); +} + + +LLPanelGroupExperiences::LLPanelGroupExperiences(const std::string& name, const LLUUID& id) +: LLPanelGroupTab(name, id), mExperiencesList(nullptr) +{ +} + +LLPanelGroupExperiences::~LLPanelGroupExperiences() +{ +} + +BOOL LLPanelGroupExperiences::isVisibleByAgent(LLAgent* agentp) +{ + //default to being visible + return TRUE; +} + +BOOL LLPanelGroupExperiences::postBuild() +{ + mExperiencesList = getChild("experiences_list"); + if (hasString("loading_experiences")) + { + mExperiencesList->setCommentText(getString("loading_experiences")); + } + else if (hasString("no_experiences")) + { + mExperiencesList->setCommentText(getString("no_experiences")); + } + + return LLPanelGroupTab::postBuild(); +} + +void LLPanelGroupExperiences::activate() +{ + if ((getGroupID() == LLUUID::null) || gDisconnected) + { + return; + } + + LLExperienceCache::instance().getGroupExperiences(getGroupID(), + boost::bind(&LLPanelGroupExperiences::groupExperiencesResults, getDerivedHandle(), _1)); +} + +void LLPanelGroupExperiences::setGroupID(const LLUUID& id) +{ + LLPanelGroupTab::setGroupID(id); + + if (id == LLUUID::null) + { + return; + } + + activate(); +} + +void LLPanelGroupExperiences::setExperienceList(const LLSD& experiences) +{ + if (hasString("no_experiences")) + { + mExperiencesList->setCommentText(getString("no_experiences")); + } + mExperiencesList->clear(); + + auto& cache = LLExperienceCache::instance(); + for (const auto& exp : experiences.array()) + { + LLUUID public_key = exp.asUUID(); + if (public_key.notNull()) + cache.get(public_key, boost::bind(addExperienceToList, _1, mExperiencesList)); + } +} + +/*static*/ +void LLPanelGroupExperiences::groupExperiencesResults(LLHandle handle, const LLSD &experiences) +{ + if (handle.isDead()) + { + return; + } + + LLPanelGroupExperiences* panel = handle.get(); + if (panel) + { + panel->setExperienceList(experiences); + } +} diff --git a/indra/newview/llpanelgroupexperiences.h b/indra/newview/llpanelgroupexperiences.h new file mode 100644 index 000000000..e16cd98ad --- /dev/null +++ b/indra/newview/llpanelgroupexperiences.h @@ -0,0 +1,56 @@ +/** + * @file llpanelgroupexperiences.h + * @brief List of experiences owned by a group. + * + * $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_LLPANELGROUPEXPERIENCES_H +#define LL_LLPANELGROUPEXPERIENCES_H + +#include "llpanelgroup.h" + +class LLPanelGroupExperiences final : public LLPanelGroupTab +{ +public: + static void* createTab(void* data); + LLPanelGroupExperiences(const std::string& name, const LLUUID& id); + virtual ~LLPanelGroupExperiences(); + + // LLPanelGroupTab + void activate() override; + BOOL isVisibleByAgent(LLAgent* agentp) override; + + BOOL postBuild() override; + + void setGroupID(const LLUUID& id) override; + + void setExperienceList(const LLSD& experiences); + +protected: + class LLNameListCtrl* mExperiencesList; + +private: + static void groupExperiencesResults(LLHandle, const LLSD &); +}; + +#endif diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index 5ab21d449..157fc2afb 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -237,6 +237,11 @@ LLPanelLogin::LLPanelLogin(const LLRect& rect) reshape(rect.getWidth(), rect.getHeight()); +#ifndef LL_FMODSTUDIO + getChildView("fmod_text")->setVisible(false); + getChildView("fmod_logo")->setVisible(false); +#endif + LLComboBox* username_combo(getChild("username_combo")); username_combo->setCommitCallback(boost::bind(LLPanelLogin::onSelectLoginEntry, _2)); username_combo->setFocusLostCallback(boost::bind(&LLPanelLogin::onLoginComboLostFocus, this, username_combo)); @@ -266,8 +271,8 @@ LLPanelLogin::LLPanelLogin(const LLRect& rect) location_combo->setFocusLostCallback( boost::bind(&LLPanelLogin::onLocationSLURL, this) ); LLComboBox* server_choice_combo = getChild("grids_combo"); - server_choice_combo->setCommitCallback(boost::bind(&LLPanelLogin::onSelectGrid, _1)); - server_choice_combo->setFocusLostCallback(boost::bind(&LLPanelLogin::onSelectGrid, server_choice_combo)); + server_choice_combo->setCommitCallback(boost::bind(&LLPanelLogin::onSelectGrid, this, _1)); + server_choice_combo->setFocusLostCallback(boost::bind(&LLPanelLogin::onSelectGrid, this, server_choice_combo)); // Load all of the grids, sorted, and then add a bar and the current grid at the top updateGridCombo(); @@ -1111,7 +1116,7 @@ void LLPanelLogin::onSelectGrid(LLUICtrl *ctrl) } gHippoGridManager->setCurrentGrid(grid); ctrl->setValue(grid); - sInstance->addFavoritesToStartLocation(); + addFavoritesToStartLocation(); /* * Determine whether or not the value in the start_location_combo makes sense @@ -1123,7 +1128,7 @@ void LLPanelLogin::onSelectGrid(LLUICtrl *ctrl) * https://grid.example.com/region/Party%20Town/20/30/5 specify a particular * grid; in those cases we want to clear the location. */ - auto location_combo = sInstance->getChild("start_location_combo"); + auto location_combo = getChild("start_location_combo"); S32 index = location_combo->getCurrentIndex(); switch (index) { diff --git a/indra/newview/llpanellogin.h b/indra/newview/llpanellogin.h index 88b4a4c37..478588aa4 100644 --- a/indra/newview/llpanellogin.h +++ b/indra/newview/llpanellogin.h @@ -114,7 +114,7 @@ private: static void onClickNewAccount(); static bool newAccountAlertCallback(const LLSD& notification, const LLSD& response); static void onClickGrids(); - static void onSelectGrid(LLUICtrl *ctrl); + void onSelectGrid(LLUICtrl *ctrl); static void onClickForgotPassword(); static void onPassKey(); static void onSelectLoginEntry(const LLSD& selected_entry); diff --git a/indra/newview/llpanelmediasettingspermissions.cpp b/indra/newview/llpanelmediasettingspermissions.cpp index d9e5d4ad2..2b0043372 100644 --- a/indra/newview/llpanelmediasettingspermissions.cpp +++ b/indra/newview/llpanelmediasettingspermissions.cpp @@ -101,15 +101,15 @@ void LLPanelMediaSettingsPermissions::draw() { if(mPermsGroupName) { - mPermsGroupName->setNameID(group_id, true); + mPermsGroupName->setNameID(group_id, LFIDBearer::GROUP); } } else { if(mPermsGroupName) { - mPermsGroupName->setNameID(LLUUID::null, TRUE); - mPermsGroupName->refresh(LLUUID::null, std::string(), true); + mPermsGroupName->setNameID(LLUUID::null, LFIDBearer::GROUP); + mPermsGroupName->refresh(LLUUID::null, std::string()); } } } diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp index 56d1ee0e6..09a6a77cd 100644 --- a/indra/newview/llpanelobjectinventory.cpp +++ b/indra/newview/llpanelobjectinventory.cpp @@ -1709,7 +1709,7 @@ void LLPanelObjectInventory::updateInventory() // We're still interested in this task's inventory. uuid_set_t selected_items; BOOL inventory_has_focus = FALSE; - if (mHaveInventory) + if (mHaveInventory && mFolders) { selected_items = mFolders->getSelectionList(); inventory_has_focus = gFocusMgr.childHasKeyboardFocus(mFolders); diff --git a/indra/newview/llpanelpermissions.cpp b/indra/newview/llpanelpermissions.cpp index fa040727d..9d82fb8d4 100644 --- a/indra/newview/llpanelpermissions.cpp +++ b/indra/newview/llpanelpermissions.cpp @@ -193,10 +193,10 @@ void LLPanelPermissions::disableAll() } getChildView("Group:")->setEnabled(FALSE); - if (auto view = getChildView("Group Name Proxy")) + if (mLabelGroupName) { - view->setValue(LLUUID::null); - view->setEnabled(FALSE); + mLabelGroupName->setNameID(LLUUID::null, LFIDBearer::GROUP); + mLabelGroupName->setEnabled(FALSE); } getChildView("button set group")->setEnabled(FALSE); @@ -390,7 +390,8 @@ void LLPanelPermissions::refresh() // Update last owner text field getChildView("Last Owner:")->setEnabled(TRUE); - std::string owner_app_link; + static const auto none_str = LLTrans::getString("GroupNameNone"); + std::string owner_app_link(none_str); if (auto view = getChild("Creator Name")) { if (LLSelectMgr::getInstance()->selectGetCreator(mCreatorID, owner_app_link)) @@ -405,6 +406,7 @@ void LLPanelPermissions::refresh() view->setEnabled(true); } + owner_app_link = none_str; const BOOL owners_identical = LLSelectMgr::getInstance()->selectGetOwner(mOwnerID, owner_app_link); if (auto view = getChild("Owner Name")) { @@ -422,6 +424,7 @@ void LLPanelPermissions::refresh() if (auto view = getChild("Last Owner Name")) { + owner_app_link = none_str; if (LLSelectMgr::getInstance()->selectGetLastOwner(mLastOwnerID, owner_app_link)) { view->setValue(mLastOwnerID); @@ -442,7 +445,7 @@ void LLPanelPermissions::refresh() { if(mLabelGroupName) { - mLabelGroupName->setNameID(group_id, TRUE); + mLabelGroupName->setNameID(group_id, LFIDBearer::GROUP); mLabelGroupName->setEnabled(TRUE); } } @@ -450,8 +453,8 @@ void LLPanelPermissions::refresh() { if(mLabelGroupName) { - mLabelGroupName->setNameID(LLUUID::null, TRUE); - mLabelGroupName->refresh(LLUUID::null, std::string(), true); + mLabelGroupName->setNameID(LLUUID::null, LFIDBearer::GROUP); + mLabelGroupName->setNameText(); mLabelGroupName->setEnabled(FALSE); } } @@ -1013,7 +1016,7 @@ void LLPanelPermissions::cbGroupID(LLUUID group_id) { if(mLabelGroupName) { - mLabelGroupName->setNameID(group_id, TRUE); + mLabelGroupName->setNameID(group_id, LFIDBearer::GROUP); } LLSelectMgr::getInstance()->sendGroup(group_id); } diff --git a/indra/newview/llpanelpick.cpp b/indra/newview/llpanelpick.cpp index ba1384797..99d5f0c91 100644 --- a/indra/newview/llpanelpick.cpp +++ b/indra/newview/llpanelpick.cpp @@ -66,7 +66,9 @@ void show_picture(const LLUUID& id, const std::string& name) S32 left, top; gFloaterView->getNewFloaterPosition(&left, &top); LLRect rect = gSavedSettings.getRect("PreviewTextureRect"); - (new LLPreviewTexture("preview texture", rect.translate(left - rect.mLeft, rect.mTop - top), name, id))->setFocus(true); + auto preview = new LLPreviewTexture("preview texture", rect.translate(left - rect.mLeft, rect.mTop - top), name, id); + preview->setFocus(true); + gFloaterView->adjustToFitScreen(preview, false); } //static diff --git a/indra/newview/llpanelprimmediacontrols.cpp b/indra/newview/llpanelprimmediacontrols.cpp index 84146235c..79237f806 100644 --- a/indra/newview/llpanelprimmediacontrols.cpp +++ b/indra/newview/llpanelprimmediacontrols.cpp @@ -84,12 +84,12 @@ const int LLPanelPrimMediaControls::kNumZoomLevels = 2; // LLPanelPrimMediaControls::LLPanelPrimMediaControls() : - mAlpha(1.f), - mCurrentURL(""), - mPreviousURL(""), mPauseFadeout(false), mUpdateSlider(true), mClearFaceOnFade(false), + mAlpha(1.f), + mCurrentURL(""), + mPreviousURL(""), mCurrentRate(0.0), mMovieDuration(0.0), mTargetObjectID(LLUUID::null), @@ -285,7 +285,7 @@ LLPluginClassMedia* LLPanelPrimMediaControls::getTargetMediaPlugin() return impl->getMediaPlugin(); } - return NULL; + return nullptr; } void LLPanelPrimMediaControls::updateShape() @@ -299,7 +299,7 @@ void LLPanelPrimMediaControls::updateShape() return; } - LLPluginClassMedia* media_plugin = NULL; + LLPluginClassMedia* media_plugin = nullptr; if(media_impl->hasMedia()) { media_plugin = media_impl->getMediaPlugin(); @@ -320,7 +320,7 @@ void LLPanelPrimMediaControls::updateShape() { bool mini_controls = false; LLMediaEntry *media_data = objectp->getTE(mTargetObjectFace)->getMediaData(); - LLVOVolume *vol = dynamic_cast(objectp); + LLVOVolume *vol = objectp ? objectp->asVolume() : nullptr; if (media_data && vol) { // Don't show the media controls if we do not have permissions @@ -354,11 +354,11 @@ void LLPanelPrimMediaControls::updateShape() mSecureLockIcon->setVisible(false); mCurrentURL = media_impl->getCurrentMediaURL(); - mBackCtrl->setEnabled((media_impl != NULL) && media_impl->canNavigateBack() && can_navigate); - mFwdCtrl->setEnabled((media_impl != NULL) && media_impl->canNavigateForward() && can_navigate); + mBackCtrl->setEnabled((media_impl != nullptr) && media_impl->canNavigateBack() && can_navigate); + mFwdCtrl->setEnabled((media_impl != nullptr) && media_impl->canNavigateForward() && can_navigate); mStopCtrl->setEnabled(has_focus && can_navigate); mHomeCtrl->setEnabled(has_focus && can_navigate); - LLPluginClassMediaOwner::EMediaStatus result = ((media_impl != NULL) && media_impl->hasMedia()) ? media_plugin->getStatus() : LLPluginClassMediaOwner::MEDIA_NONE; + LLPluginClassMediaOwner::EMediaStatus result = ((media_impl != nullptr) && media_impl->hasMedia()) ? media_plugin->getStatus() : LLPluginClassMediaOwner::MEDIA_NONE; mVolumeCtrl->setVisible(has_focus); mVolumeCtrl->setEnabled(has_focus); @@ -423,7 +423,7 @@ void LLPanelPrimMediaControls::updateShape() mMediaPlaySliderCtrl->setEnabled(true); } - // video vloume + // video volume if(volume <= 0.0) { mMuteBtn->setToggleState(true); @@ -552,21 +552,21 @@ void LLPanelPrimMediaControls::updateShape() switch (mScrollState) { case SCROLL_UP: - media_impl->scrollWheel(0, -1, MASK_NONE); + media_impl->scrollWheel(0, 0, 0, -1, MASK_NONE); break; case SCROLL_DOWN: - media_impl->scrollWheel(0, 1, MASK_NONE); + media_impl->scrollWheel(0, 0, 0, 1, MASK_NONE); break; case SCROLL_LEFT: - media_impl->scrollWheel(1, 0, MASK_NONE); + media_impl->scrollWheel(0, 0, 1, 0, MASK_NONE); // media_impl->handleKeyHere(KEY_LEFT, MASK_NONE); break; case SCROLL_RIGHT: - media_impl->scrollWheel(-1, 0, MASK_NONE); + media_impl->scrollWheel(0, 0, -1, 0, MASK_NONE); // media_impl->handleKeyHere(KEY_RIGHT, MASK_NONE); break; case SCROLL_NONE: - default: + default: break; } } @@ -1106,7 +1106,7 @@ void LLPanelPrimMediaControls::onScrollUp(void* user_data) if(impl) { - impl->scrollWheel(0, -1, MASK_NONE); + impl->scrollWheel(0, 0, 0, -1, MASK_NONE); } } void LLPanelPrimMediaControls::onScrollUpHeld(void* user_data) @@ -1123,7 +1123,7 @@ void LLPanelPrimMediaControls::onScrollRight(void* user_data) if(impl) { - impl->scrollWheel(-1, 0, MASK_NONE); + impl->scrollWheel(0, 0, -1, 0, MASK_NONE); // impl->handleKeyHere(KEY_RIGHT, MASK_NONE); } } @@ -1142,7 +1142,7 @@ void LLPanelPrimMediaControls::onScrollLeft(void* user_data) if(impl) { - impl->scrollWheel(1, 0, MASK_NONE); + impl->scrollWheel(0, 0, 1, 0, MASK_NONE); // impl->handleKeyHere(KEY_LEFT, MASK_NONE); } } @@ -1161,7 +1161,7 @@ void LLPanelPrimMediaControls::onScrollDown(void* user_data) if(impl) { - impl->scrollWheel(0, 1, MASK_NONE); + impl->scrollWheel(0, 0, 0, 1, MASK_NONE); } } void LLPanelPrimMediaControls::onScrollDownHeld(void* user_data) diff --git a/indra/newview/llpanelprofile.cpp b/indra/newview/llpanelprofile.cpp index e40747eee..6c2644440 100644 --- a/indra/newview/llpanelprofile.cpp +++ b/indra/newview/llpanelprofile.cpp @@ -41,7 +41,11 @@ #include "lltabcontainer.h" #include "llviewercontrol.h" #include "llviewernetwork.h" +#include "llmutelist.h" +#endif +#include "llfloatermute.h" +#ifdef AI_UNUSED static const std::string PANEL_PICKS = "panel_picks"; #endif // AI_UNUSED @@ -55,19 +59,19 @@ std::string getProfileURL(const std::string& agent_name) llassert(!url.empty()); LLSD subs; subs["AGENT_NAME"] = agent_name; - url = LLWeb::expandURLSubstitutions(url,subs); + url = LLWeb::expandURLSubstitutions(url, subs); LLStringUtil::toLower(url); return url; } -class LLProfileHandler : public LLCommandHandler +class LLProfileHandler final : public LLCommandHandler { public: // requires trusted browser to trigger LLProfileHandler() : LLCommandHandler("profile", UNTRUSTED_THROTTLE) { } bool handle(const LLSD& params, const LLSD& query_map, - LLMediaCtrl* web) + LLMediaCtrl* web) override { if (params.size() < 1) return false; std::string agent_name = params[0]; @@ -80,14 +84,14 @@ public: }; LLProfileHandler gProfileHandler; -class LLAgentHandler : public LLCommandHandler +class LLAgentHandler final : public LLCommandHandler { public: // requires trusted browser to trigger LLAgentHandler() : LLCommandHandler("agent", UNTRUSTED_THROTTLE) { } bool handle(const LLSD& params, const LLSD& query_map, - LLMediaCtrl* web) + LLMediaCtrl* web) override { if (params.size() < 2) return false; LLUUID avatar_id; @@ -144,6 +148,12 @@ public: return true; } + if (verb == "removefriend") + { + LLAvatarActions::removeFriendDialog(avatar_id); + return true; + } + if (verb == "mute") { if (! LLAvatarActions::isBlocked(avatar_id)) @@ -162,6 +172,28 @@ public: return true; } + if (verb == "block") + { + if (params.size() > 2) + { + const std::string object_name = LLURI::unescape(params[2].asString()); + LLMute mute(avatar_id, object_name, LLMute::OBJECT); + LLMuteList::getInstance()->add(mute); + LLFloaterMute::showInstance()->selectMute(mute.mID); + } + return true; + } + + if (verb == "unblock") + { + if (params.size() > 2) + { + const std::string object_name = params[2].asString(); + LLMute mute(avatar_id, object_name, LLMute::OBJECT); + LLMuteList::getInstance()->remove(mute); + } + return true; + } return false; } }; @@ -171,13 +203,13 @@ LLAgentHandler gAgentHandler; #ifdef AI_UNUSED //-- LLPanelProfile::ChildStack begins ---------------------------------------- LLPanelProfile::ChildStack::ChildStack() -: mParent(NULL) +: mParent(nullptr) { } LLPanelProfile::ChildStack::~ChildStack() { - while (mStack.size() != 0) + while (!mStack.empty()) { view_list_t& top = mStack.back(); for (view_list_t::const_iterator it = top.begin(); it != top.end(); ++it) @@ -217,7 +249,7 @@ bool LLPanelProfile::ChildStack::push() /// Restore saved children (adding them back to the child list). bool LLPanelProfile::ChildStack::pop() { - if (mStack.size() == 0) + if (mStack.empty()) { LL_WARNS() << "Empty stack" << LL_ENDL; llassert(mStack.size() == 0); @@ -240,7 +272,7 @@ bool LLPanelProfile::ChildStack::pop() void LLPanelProfile::ChildStack::preParentReshape() { mSavedStack = mStack; - while(mStack.size() > 0) + while(!mStack.empty()) { pop(); } @@ -255,9 +287,8 @@ void LLPanelProfile::ChildStack::postParentReshape() 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) + for (auto viewp : vlist) { - LLView* viewp = *list_it; LL_DEBUGS() << "removing " << viewp->getName() << LL_ENDL; mParent->removeChild(viewp); } @@ -273,9 +304,9 @@ void LLPanelProfile::ChildStack::dump() 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) + for (auto list_it : vlist) { - dbg_line << " " << (*list_it)->getName(); + dbg_line << " " << list_it->getName(); } LL_DEBUGS() << dbg_line.str() << LL_ENDL; } @@ -372,7 +403,7 @@ void LLPanelProfile::onOpen() void LLPanelProfile::onTabSelected(const LLSD& param) { std::string tab_name = param.asString(); - if (NULL != getTabContainer()[tab_name]) + if (nullptr != getTabContainer()[tab_name]) { getTabContainer()[tab_name]->onOpen(getAvatarId()); } @@ -416,7 +447,7 @@ void LLPanelProfile::closePanel(LLPanel* panel) // Prevent losing focus by the floater const child_list_t* child_list = getChildList(); - if (child_list->size() > 0) + if (!child_list->empty()) { child_list->front()->setFocus(TRUE); } diff --git a/indra/newview/llparticipantlist.cpp b/indra/newview/llparticipantlist.cpp index d4693dee8..872b90514 100644 --- a/indra/newview/llparticipantlist.cpp +++ b/indra/newview/llparticipantlist.cpp @@ -78,7 +78,7 @@ void LLParticipantList::setupContextMenu() static LLMenuGL* menu = LLUICtrlFactory::getInstance()->buildMenu("menu_local_avs.xml", gMenuHolder); mAvatarList->setContextMenu(menu); } - else mAvatarList->setContextMenu(0); + else mAvatarList->setContextMenu(LFIDBearer::AVATAR); } BOOL LLParticipantList::postBuild() diff --git a/indra/newview/llprefsim.cpp b/indra/newview/llprefsim.cpp index 2f7faca75..8023cd1a3 100644 --- a/indra/newview/llprefsim.cpp +++ b/indra/newview/llprefsim.cpp @@ -63,7 +63,7 @@ public: void apply(); void cancel(); - void setPersonalInfo(const std::string& visibility, bool im_via_email, const std::string& email); + void setPersonalInfo(const std::string& visibility, bool im_via_email, const std::string& email, bool is_verified); void enableHistory(); static void onClickLogPath(void* user_data); @@ -193,13 +193,6 @@ void LLPrefsIMImpl::apply() if((new_im_via_email != mOriginalIMViaEmail) ||(new_hide_online != mOriginalHideOnlineStatus)) { - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_UpdateUserInfo); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_UserData); - msg->addBOOLFast(_PREHASH_IMViaEMail, new_im_via_email); // This hack is because we are representing several different // possible strings with a single checkbox. Since most users // can only select between 2 values, we represent it as a @@ -212,8 +205,7 @@ void LLPrefsIMImpl::apply() //Update showonline value, otherwise multiple applys won't work mOriginalHideOnlineStatus = new_hide_online; } - msg->addString("DirectoryVisibility", mDirectoryVisibility); - gAgent.sendReliableMessage(); + gAgent.sendAgentUpdateUserInfo(new_im_via_email, mDirectoryVisibility); } } else @@ -227,7 +219,7 @@ void LLPrefsIMImpl::apply() } } -void LLPrefsIMImpl::setPersonalInfo(const std::string& visibility, bool im_via_email, const std::string& email) +void LLPrefsIMImpl::setPersonalInfo(const std::string& visibility, bool im_via_email, const std::string& email, bool is_verified) { mGotPersonalInfo = true; mOriginalIMViaEmail = im_via_email; @@ -254,8 +246,13 @@ void LLPrefsIMImpl::setPersonalInfo(const std::string& visibility, bool im_via_e childSetValue("online_visibility", mOriginalHideOnlineStatus); childSetLabelArg("online_visibility", "[DIR_VIS]", mDirectoryVisibility); - childEnable("send_im_to_email"); - childSetValue("send_im_to_email", im_via_email); + if (auto child = getChildView("send_im_to_email")) + { + child->setValue(im_via_email); + child->setEnabled(is_verified); + if (!is_verified) + child->setToolTip(getString("email_unverified_tooltip")); + } childEnable("log_instant_messages"); childEnable("log_chat"); childEnable("log_instant_messages_timestamp"); @@ -332,9 +329,9 @@ void LLPrefsIM::cancel() impl.cancel(); } -void LLPrefsIM::setPersonalInfo(const std::string& visibility, bool im_via_email, const std::string& email) +void LLPrefsIM::setPersonalInfo(const std::string& visibility, bool im_via_email, const std::string& email, bool is_verified) { - impl.setPersonalInfo(visibility, im_via_email, email); + impl.setPersonalInfo(visibility, im_via_email, email, is_verified); } LLPanel* LLPrefsIM::getPanel() diff --git a/indra/newview/llprefsim.h b/indra/newview/llprefsim.h index 90bf4656a..7b7b3cefc 100644 --- a/indra/newview/llprefsim.h +++ b/indra/newview/llprefsim.h @@ -45,7 +45,7 @@ public: void apply(); void cancel(); - void setPersonalInfo(const std::string& visibility, bool im_via_email, const std::string& email); + void setPersonalInfo(const std::string& visibility, bool im_via_email, const std::string& email, bool is_verified); LLPanel* getPanel(); diff --git a/indra/newview/llpreviewlandmark.cpp b/indra/newview/llpreviewlandmark.cpp index c67f7c13d..a73c1c3f4 100644 --- a/indra/newview/llpreviewlandmark.cpp +++ b/indra/newview/llpreviewlandmark.cpp @@ -63,10 +63,6 @@ //////////////////////////////////////////////////////////////////////////// // LLPreviewLandmark -// static -LLPreviewLandmarkList LLPreviewLandmark::sOrderedInstances; - - LLPreviewLandmark::LLPreviewLandmark(const std::string& name, const LLRect& rect, const std::string& title, @@ -112,18 +108,10 @@ LLPreviewLandmark::LLPreviewLandmark(const std::string& name, translate(rect.mLeft - curRect.mLeft, rect.mTop - curRect.mTop); } */ - LLPreviewLandmark::sOrderedInstances.push_back( this ); } LLPreviewLandmark::~LLPreviewLandmark() { - LLPreviewLandmarkList::iterator this_itr; - this_itr = std::find(LLPreviewLandmark::sOrderedInstances.begin(), - LLPreviewLandmark::sOrderedInstances.end(), this); - if (this_itr != LLPreviewLandmark::sOrderedInstances.end()) - { - LLPreviewLandmark::sOrderedInstances.erase(this_itr); - } } diff --git a/indra/newview/llpreviewlandmark.h b/indra/newview/llpreviewlandmark.h index 5957eb46d..82e358ed3 100644 --- a/indra/newview/llpreviewlandmark.h +++ b/indra/newview/llpreviewlandmark.h @@ -33,72 +33,43 @@ #ifndef LL_LLPREVIEWLANDMARK_H #define LL_LLPREVIEWLANDMARK_H -#include - -#include "lllandmark.h" - -#include "llfloater.h" -#include "llmap.h" -#include "llstring.h" -#include "lluuid.h" -#include "v3dmath.h" -#include "v4coloru.h" - -#include "llhudtext.h" #include "llpreview.h" class LLIconCtrl; -class LLInventoryItem; -class LLLandmarkList; -class LLLineEditor; -class LLMessageSystem; -class LLPreviewLandmark; class LLPanelPlace; +class LLLandmark; -const S32 PREVIEW_LANDMARK_NUM_COLORS = 6; - -typedef std::deque< LLPreviewLandmark* > LLPreviewLandmarkList; - -class LLPreviewLandmark : public LLPreview +class LLPreviewLandmark final : public LLPreview { public: LLPreviewLandmark(const std::string& name, const LLRect& rect, const std::string& title, const LLUUID& item_uuid, BOOL show_keep_discard = FALSE, - LLViewerInventoryItem* inv_item = NULL); + LLViewerInventoryItem* inv_item = nullptr); virtual ~LLPreviewLandmark(); - /*virtual*/ void draw(); + /*virtual*/ void draw() override; const std::string& getName() const; const LLColor4& getMarkerColor() const; LLVector3d getPositionGlobal() const; - //static S32 getNumInstances() { return LLPreviewLandmark::sOrderedInstances.getLength(); } - //static const LLPreviewLandmark* getFirst() { return LLPreviewLandmark::sOrderedInstances.getFirstData(); } - //static const LLPreviewLandmark* getNext() { return LLPreviewLandmark::sOrderedInstances.getNextData(); } - static void* createPlaceDetail(void* userdata); - /*virtual*/ void loadAsset(); - /*virtual*/ EAssetStatus getAssetStatus(); + /*virtual*/ void loadAsset() override; + /*virtual*/ EAssetStatus getAssetStatus() override; protected: void getDegreesAndDist(F32* degrees, F64* horiz_dist, F64* vert_dist) const; - virtual const char *getTitleName() const { return "Landmark"; } + const char *getTitleName() const override { return "Landmark"; } private: -// void renderBeacon(); -// LLPointer mBeaconText; - LLIconCtrl* mIconLandmark; LLPanelPlace* mPlacePanel; LLLandmark* mLandmark; LLColor4 mMarkerColor; - - static LLPreviewLandmarkList sOrderedInstances; }; #endif diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp index b8f714298..3cd30ce8e 100644 --- a/indra/newview/llpreviewscript.cpp +++ b/indra/newview/llpreviewscript.cpp @@ -39,6 +39,7 @@ #include "llbutton.h" #include "llcheckboxctrl.h" #include "llcombobox.h" +#include "llcororesponder.h" #include "lldir.h" #include "llexternaleditor.h" #include "statemachine/aifilepicker.h" @@ -80,6 +81,8 @@ #include "lluictrlfactory.h" #include "lltrans.h" #include "llappviewer.h" +#include "llexperiencecache.h" +#include "llfloaterexperienceprofile.h" #include "llsdserialize.h" @@ -139,13 +142,35 @@ static bool have_script_upload_cap(LLUUID& object_id) return object && (! object->getRegion()->getCapability("UpdateScriptTask").empty()); } + +class ExperienceResponder : public LLHTTPClient::ResponderWithResult +{ +public: + ExperienceResponder(const LLHandle& parent) : mParent(parent) + { + } + + LLHandle mParent; + + /*virtual*/ void httpSuccess() + { + LLLiveLSLEditor* parent = mParent.get(); + if (!parent) + return; + + parent->setExperienceIds(getContent()["experience_ids"]); + } + + /*virtual*/ char const* getName() const { return "ExperienceResponder"; } +}; + /// --------------------------------------------------------------------------- /// LLLiveLSLFile /// --------------------------------------------------------------------------- class LLLiveLSLFile : public LLLiveFile { public: - typedef boost::function change_callback_t; + typedef std::function change_callback_t; LLLiveLSLFile(std::string file_path, change_callback_t change_cb); ~LLLiveLSLFile(); @@ -153,16 +178,16 @@ public: void ignoreNextUpdate() { mIgnoreNextUpdate = true; } protected: - /*virtual*/ bool loadFile(); + /*virtual*/ bool loadFile() override; change_callback_t mOnChangeCallback; bool mIgnoreNextUpdate; }; LLLiveLSLFile::LLLiveLSLFile(std::string file_path, change_callback_t change_cb) - : mOnChangeCallback(change_cb) +: LLLiveFile(file_path, 1.0) +, mOnChangeCallback(change_cb) , mIgnoreNextUpdate(false) - , LLLiveFile(file_path, 1.0) { llassert(mOnChangeCallback); } @@ -183,6 +208,188 @@ bool LLLiveLSLFile::loadFile() return mOnChangeCallback(filename()); } +// +#if 0 +/// --------------------------------------------------------------------------- +/// LLFloaterScriptSearch +/// --------------------------------------------------------------------------- +class LLFloaterScriptSearch : public LLFloater +{ +public: + LLFloaterScriptSearch(LLScriptEdCore* editor_core); + ~LLFloaterScriptSearch(); + + /*virtual*/ BOOL postBuild(); + static void show(LLScriptEdCore* editor_core); + static void onBtnSearch(void* userdata); + void handleBtnSearch(); + + static void onBtnReplace(void* userdata); + void handleBtnReplace(); + + static void onBtnReplaceAll(void* userdata); + void handleBtnReplaceAll(); + + LLScriptEdCore* getEditorCore() { return mEditorCore; } + static LLFloaterScriptSearch* getInstance() { return sInstance; } + + virtual bool hasAccelerators() const; + virtual BOOL handleKeyHere(KEY key, MASK mask); + +private: + + LLScriptEdCore* mEditorCore; + static LLFloaterScriptSearch* sInstance; + +protected: + LLLineEditor* mSearchBox; + LLLineEditor* mReplaceBox; + void onSearchBoxCommit(); +}; + +LLFloaterScriptSearch* LLFloaterScriptSearch::sInstance = NULL; + +LLFloaterScriptSearch::LLFloaterScriptSearch(LLScriptEdCore* editor_core) +: LLFloater(LLSD()), + mSearchBox(NULL), + mReplaceBox(NULL), + mEditorCore(editor_core) +{ + buildFromFile("floater_script_search.xml"); + + sInstance = this; + + // find floater in which script panel is embedded + LLView* viewp = (LLView*)editor_core; + while(viewp) + { + LLFloater* floaterp = dynamic_cast(viewp); + if (floaterp) + { + floaterp->addDependentFloater(this); + break; + } + viewp = viewp->getParent(); + } +} + +BOOL LLFloaterScriptSearch::postBuild() +{ + mReplaceBox = getChild("replace_text"); + mSearchBox = getChild("search_text"); + mSearchBox->setCommitCallback(boost::bind(&LLFloaterScriptSearch::onSearchBoxCommit, this)); + mSearchBox->setCommitOnFocusLost(FALSE); + childSetAction("search_btn", onBtnSearch,this); + childSetAction("replace_btn", onBtnReplace,this); + childSetAction("replace_all_btn", onBtnReplaceAll,this); + + setDefaultBtn("search_btn"); + + return TRUE; +} + +//static +void LLFloaterScriptSearch::show(LLScriptEdCore* editor_core) +{ + LLSD::String search_text; + LLSD::String replace_text; + if (sInstance && sInstance->mEditorCore && sInstance->mEditorCore != editor_core) + { + search_text=sInstance->mSearchBox->getValue().asString(); + replace_text=sInstance->mReplaceBox->getValue().asString(); + sInstance->closeFloater(); + delete sInstance; + } + + if (!sInstance) + { + // sInstance will be assigned in the constructor. + new LLFloaterScriptSearch(editor_core); + sInstance->mSearchBox->setValue(search_text); + sInstance->mReplaceBox->setValue(replace_text); + } + + sInstance->openFloater(); +} + +LLFloaterScriptSearch::~LLFloaterScriptSearch() +{ + sInstance = NULL; +} + +// static +void LLFloaterScriptSearch::onBtnSearch(void *userdata) +{ + LLFloaterScriptSearch* self = (LLFloaterScriptSearch*)userdata; + self->handleBtnSearch(); +} + +void LLFloaterScriptSearch::handleBtnSearch() +{ + LLCheckBoxCtrl* caseChk = getChild("case_text"); + mEditorCore->mEditor->selectNext(mSearchBox->getValue().asString(), caseChk->get()); +} + +// static +void LLFloaterScriptSearch::onBtnReplace(void *userdata) +{ + LLFloaterScriptSearch* self = (LLFloaterScriptSearch*)userdata; + self->handleBtnReplace(); +} + +void LLFloaterScriptSearch::handleBtnReplace() +{ + LLCheckBoxCtrl* caseChk = getChild("case_text"); + mEditorCore->mEditor->replaceText(mSearchBox->getValue().asString(), mReplaceBox->getValue().asString(), caseChk->get()); +} + +// static +void LLFloaterScriptSearch::onBtnReplaceAll(void *userdata) +{ + LLFloaterScriptSearch* self = (LLFloaterScriptSearch*)userdata; + self->handleBtnReplaceAll(); +} + +void LLFloaterScriptSearch::handleBtnReplaceAll() +{ + LLCheckBoxCtrl* caseChk = getChild("case_text"); + mEditorCore->mEditor->replaceTextAll(mSearchBox->getValue().asString(), mReplaceBox->getValue().asString(), caseChk->get()); +} + +bool LLFloaterScriptSearch::hasAccelerators() const +{ + if (mEditorCore) + { + return mEditorCore->hasAccelerators(); + } + return FALSE; +} + +BOOL LLFloaterScriptSearch::handleKeyHere(KEY key, MASK mask) +{ + if (mEditorCore) + { + BOOL handled = mEditorCore->handleKeyHere(key, mask); + if (!handled) + { + LLFloater::handleKeyHere(key, mask); + } + } + + return FALSE; +} + +void LLFloaterScriptSearch::onSearchBoxCommit() +{ + if (mEditorCore && mEditorCore->mEditor) + { + LLCheckBoxCtrl* caseChk = getChild("case_text"); + mEditorCore->mEditor->selectNext(mSearchBox->getValue().asString(), caseChk->get()); + } +} +#endif +// + /// --------------------------------------------------------------------------- /// LLScriptEdCore /// --------------------------------------------------------------------------- @@ -244,9 +451,9 @@ LLScriptEdCore::LLScriptEdCore( mLastHelpToken(NULL), mLiveHelpHistorySize(0), mEnableSave(FALSE), + mHasScriptData(FALSE), mLiveFile(NULL), - mContainer(container), - mHasScriptData(FALSE) + mContainer(container) { setFollowsAll(); setBorderVisible(FALSE); @@ -259,9 +466,68 @@ LLScriptEdCore::~LLScriptEdCore() { deleteBridges(); + // If the search window is up for this editor, close it. +// [SL:KB] - Patch: UI-FloaterSearchReplace +// LLFloaterScriptSearch* script_search = LLFloaterScriptSearch::getInstance(); +// if (script_search && script_search->getEditorCore() == this) +// { +// script_search->closeFloater(); +// delete script_search; +// } +// [/SL:KB] + delete mLiveFile; } +void LLLiveLSLEditor::experienceChanged() +{ + if (mScriptEd->getAssociatedExperience() != mExperiences->getSelectedValue().asUUID()) + { + mScriptEd->enableSave(getIsModifiable()); + //getChildView("Save_btn")->setEnabled(TRUE); + mScriptEd->setAssociatedExperience(mExperiences->getSelectedValue().asUUID()); + updateExperiencePanel(); + } +} + +void LLLiveLSLEditor::onViewProfile(LLUICtrl* ui, void* userdata) +{ + LLLiveLSLEditor* self = (LLLiveLSLEditor*)userdata; + + LLUUID id; + if (self->mExperienceEnabled->get()) + { + id = self->mScriptEd->getAssociatedExperience(); + if (id.notNull()) + { + LLFloaterExperienceProfile::showInstance(id); + } + } + +} + +void LLLiveLSLEditor::onToggleExperience(LLUICtrl* ui, void* userdata) +{ + LLLiveLSLEditor* self = (LLLiveLSLEditor*)userdata; + + LLUUID id; + if (self->mExperienceEnabled->get()) + { + if (self->mScriptEd->getAssociatedExperience().isNull()) + { + id = self->mExperienceIds.beginArray()->asUUID(); + } + } + + if (id != self->mScriptEd->getAssociatedExperience()) + { + self->mScriptEd->enableSave(self->getIsModifiable()); + } + self->mScriptEd->setAssociatedExperience(id); + + self->updateExperiencePanel(); +} + BOOL LLScriptEdCore::postBuild() { mErrorList = getChild("lsl errors"); @@ -401,8 +667,12 @@ void LLScriptEdCore::initMenu() menuItem->setEnabledCallback(enableDeselectMenu); menuItem = getChild("Search / Replace..."); +// menuItem->setClickCallback(boost::bind(&LLFloaterScriptSearch::show, this)); menuItem->setMenuCallback(onSearchMenu, this); menuItem->setEnabledCallback(NULL); +// [/SL:KB] + + // Singu TODO: Merge LLFloaterGotoLine? menuItem = getChild("Help..."); menuItem->setMenuCallback(onBtnHelp, this); @@ -1192,6 +1462,153 @@ BOOL LLScriptEdCore::handleKeyHere(KEY key, MASK mask) return FALSE; } +LLUUID LLScriptEdCore::getAssociatedExperience() const +{ + return mAssociatedExperience; +} + +void LLLiveLSLEditor::setExperienceIds(const LLSD& experience_ids) +{ + mExperienceIds = experience_ids; + updateExperiencePanel(); +} + + +void LLLiveLSLEditor::updateExperiencePanel() +{ + if (mScriptEd->getAssociatedExperience().isNull()) + { + mExperienceEnabled->set(FALSE); + mExperiences->setVisible(FALSE); + if (mExperienceIds.size() > 0) + { + mExperienceEnabled->setEnabled(TRUE); + mExperienceEnabled->setToolTip(getString("add_experiences")); + } + else + { + mExperienceEnabled->setEnabled(FALSE); + mExperienceEnabled->setToolTip(getString("no_experiences")); + } + getChild("view_profile")->setVisible(FALSE); + } + else + { + mExperienceEnabled->setToolTip(getString("experience_enabled")); + mExperienceEnabled->setEnabled(getIsModifiable()); + mExperiences->setVisible(TRUE); + mExperienceEnabled->set(TRUE); + getChild("view_profile")->setToolTip(getString("show_experience_profile")); + buildExperienceList(); + } +} + +void LLLiveLSLEditor::buildExperienceList() +{ + mExperiences->clearRows(); + bool foundAssociated = false; + const LLUUID& associated = mScriptEd->getAssociatedExperience(); + LLUUID last; + LLScrollListItem* item; + for(LLSD::array_const_iterator it = mExperienceIds.beginArray(); it != mExperienceIds.endArray(); ++it) + { + LLUUID id = it->asUUID(); + EAddPosition position = ADD_BOTTOM; + if (id == associated) + { + foundAssociated = true; + position = ADD_TOP; + } + + const LLSD& experience = LLExperienceCache::instance().get(id); + if (experience.isUndefined()) + { + mExperiences->add(getString("loading"), id, position); + last = id; + } + else + { + std::string experience_name_string = experience[LLExperienceCache::NAME].asString(); + if (experience_name_string.empty()) + { + experience_name_string = LLTrans::getString("ExperienceNameUntitled"); + } + mExperiences->add(experience_name_string, id, position); + } + } + + if (!foundAssociated) + { + const LLSD& experience = LLExperienceCache::instance().get(associated); + if (experience.isDefined()) + { + std::string experience_name_string = experience[LLExperienceCache::NAME].asString(); + if (experience_name_string.empty()) + { + experience_name_string = LLTrans::getString("ExperienceNameUntitled"); + } + item=mExperiences->add(experience_name_string, associated, ADD_TOP); + } + else + { + item = mExperiences->add(getString("loading"), associated, ADD_TOP); + last = associated; + } + item->setEnabled(FALSE); + } + + if (last.notNull()) + { + mExperiences->setEnabled(FALSE); + LLExperienceCache::instance().get(last, boost::bind(&LLLiveLSLEditor::buildExperienceList, this)); + } + else + { + mExperiences->setEnabled(TRUE); + mExperiences->sortByName(TRUE); + mExperiences->setCurrentByIndex(mExperiences->getCurrentIndex()); + getChild("view_profile")->setVisible(TRUE); + } +} + + +void LLScriptEdCore::setAssociatedExperience(const LLUUID& experience_id) +{ + mAssociatedExperience = experience_id; +} + + + +void LLLiveLSLEditor::requestExperiences() +{ + if (!getIsModifiable()) + { + return; + } + + LLViewerRegion* region = gAgent.getRegion(); + if (region) + { + std::string lookup_url = region->getCapability("GetCreatorExperiences"); + if (!lookup_url.empty()) + { + LLHTTPClient::get(lookup_url, new LLCoroResponder( + boost::bind(&LLLiveLSLEditor::receiveExperienceIds, _1, getDerivedHandle()))); + } + } +} + +/*static*/ +void LLLiveLSLEditor::receiveExperienceIds(const LLCoroResponder& responder, LLHandle hparent) +{ + LLLiveLSLEditor* parent = hparent.get(); + if (!parent) + return; + + parent->setExperienceIds(responder.getContent()["experience_ids"]); +} + + /// --------------------------------------------------------------------------- /// LLScriptEdContainer /// --------------------------------------------------------------------------- @@ -1290,7 +1707,6 @@ void* LLPreviewLSL::createScriptEdPanel(void* userdata) LLPreviewLSL::onSearchReplace, self, 0); - return self->mScriptEd; } @@ -1449,7 +1865,6 @@ void LLPreviewLSL::onSave(void* userdata, BOOL close_after_save) // fails, go ahead and save the text anyway. void LLPreviewLSL::saveIfNeeded(bool sync /*= true*/) { - // LL_INFOS() << "LLPreviewLSL::saveIfNeeded()" << LL_ENDL; if(!mScriptEd->hasChanged()) { return; @@ -1474,13 +1889,14 @@ void LLPreviewLSL::saveIfNeeded(bool sync /*= true*/) mScriptEd->sync(); } + if (!gAgent.getRegion()) return; const LLInventoryItem *inv_item = getItem(); // save it out to asset server - std::string url = gAgent.getRegion()->getCapability("UpdateScriptAgent"); if(inv_item) { getWindow()->incBusyCount(); mPendingUploads++; + std::string url = gAgent.getRegion()->getCapability("UpdateScriptAgent"); if (!url.empty()) { uploadAssetViaCaps(url, filename, mItemUUID); @@ -1491,12 +1907,6 @@ void LLPreviewLSL::saveIfNeeded(bool sync /*= true*/) mScriptEd->mErrorList->setCommentText(LLTrans::getString("CompileQueueProblemUploading")); LLFile::remove(filename); } -#if 0 //Client side compiling disabled. - else if (gAssetStorage) - { - uploadAssetLegacy(filename, mItemUUID, tid); - } -#endif } } @@ -1518,180 +1928,6 @@ void LLPreviewLSL::uploadAssetViaCaps(const std::string& url, LLHTTPClient::post(url, body, new LLUpdateAgentInventoryResponder(body, filename, LLAssetType::AT_LSL_TEXT)); } -#if 0 //Client side compiling disabled. -void LLPreviewLSL::uploadAssetLegacy(const std::string& filename, - const LLUUID& item_id, - const LLTransactionID& tid) -{ - LLLineEditor* descEditor = getChild("desc"); - LLScriptSaveInfo* info = new LLScriptSaveInfo(item_id, - descEditor->getText(), - tid); - gAssetStorage->storeAssetData(filename, tid, - LLAssetType::AT_LSL_TEXT, - &LLPreviewLSL::onSaveComplete, - info); - - LLAssetID asset_id = tid.makeAssetID(gAgent.getSecureSessionID()); - std::string filepath = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,asset_id.asString()); - std::string dst_filename = llformat("%s.lso", filepath.c_str()); - std::string err_filename = llformat("%s.out", filepath.c_str()); - - const BOOL compile_to_mono = FALSE; - if(!lscript_compile(filename.c_str(), - dst_filename.c_str(), - err_filename.c_str(), - compile_to_mono, - asset_id.asString().c_str(), - gAgent.isGodlike())) - { - LL_INFOS() << "Compile failed!" << LL_ENDL; - //char command[256]; - //sprintf(command, "type %s\n", err_filename.c_str()); - //system(command); - - // load the error file into the error scrolllist - LLFILE* fp = LLFile::fopen(err_filename, "r"); - if(fp) - { - char buffer[MAX_STRING]; /*Flawfinder: ignore*/ - std::string line; - while(!feof(fp)) - { - if (fgets(buffer, MAX_STRING, fp) == NULL) - { - buffer[0] = '\0'; - } - if(feof(fp)) - { - break; - } - else - { - line.assign(buffer); - LLStringUtil::stripNonprintable(line); - - LLSD row; - row["columns"][0]["value"] = line; - row["columns"][0]["font"] = "OCRA"; - mScriptEd->mErrorList->addElement(row); - } - } - fclose(fp); - mScriptEd->selectFirstError(); - } - } - else - { - LL_INFOS() << "Compile worked!" << LL_ENDL; - if(gAssetStorage) - { - getWindow()->incBusyCount(); - mPendingUploads++; - LLUUID* this_uuid = new LLUUID(mItemUUID); - gAssetStorage->storeAssetData(dst_filename, - tid, - LLAssetType::AT_LSL_BYTECODE, - &LLPreviewLSL::onSaveBytecodeComplete, - (void**)this_uuid); - } - } - - // get rid of any temp files left lying around - LLFile::remove(filename); - LLFile::remove(err_filename); - LLFile::remove(dst_filename); -} - - -// static -void LLPreviewLSL::onSaveComplete(const LLUUID& asset_uuid, void* user_data, S32 status, LLExtStat ext_status) // StoreAssetData callback (fixed) -{ - LLScriptSaveInfo* info = reinterpret_cast(user_data); - if(0 == status) - { - if (info) - { - const LLViewerInventoryItem* item; - item = (const LLViewerInventoryItem*)gInventory.getItem(info->mItemUUID); - if(item) - { - LLPointer new_item = new LLViewerInventoryItem(item); - new_item->setAssetUUID(asset_uuid); - new_item->setTransactionID(info->mTransactionID); - new_item->updateServer(FALSE); - gInventory.updateItem(new_item); - gInventory.notifyObservers(); - } - else - { - LL_WARNS() << "Inventory item for script " << info->mItemUUID - << " is no longer in agent inventory." << LL_ENDL; - } - - // Find our window and close it if requested. - LLPreviewLSL* self = static_cast(LLPreview::find(info->mItemUUID)); - if (self) - { - getWindow()->decBusyCount(); - self->mPendingUploads--; - if (self->mPendingUploads <= 0 - && self->mCloseAfterSave) - { - self->close(); - } - } - } - } - else - { - LL_WARNS() << "Problem saving script: " << status << LL_ENDL; - LLSD args; - args["REASON"] = std::string(LLAssetStorage::getErrorString(status)); - LLNotificationsUtil::add("SaveScriptFailReason", args); - } - delete info; -} - -// static -void LLPreviewLSL::onSaveBytecodeComplete(const LLUUID& asset_uuid, void* user_data, S32 status, LLExtStat ext_status) // StoreAssetData callback (fixed) -{ - LLUUID* instance_uuid = (LLUUID*)user_data; - LLPreviewLSL* self = NULL; - if(instance_uuid) - { - self = static_cast(LLPreview::find(*instance_uuid)); - } - if (0 == status) - { - if (self) - { - LLSD row; - row["columns"][0]["value"] = "Compile successful!"; - row["columns"][0]["font"] = "SANSSERIF_SMALL"; - self->mScriptEd->mErrorList->addElement(row); - - // Find our window and close it if requested. - self->getWindow()->decBusyCount(); - self->mPendingUploads--; - if (self->mPendingUploads <= 0 - && self->mCloseAfterSave) - { - self->close(); - } - } - } - else - { - LL_WARNS() << "Problem saving LSL Bytecode (Preview)" << LL_ENDL; - LLSD args; - args["REASON"] = std::string(LLAssetStorage::getErrorString(status)); - LLNotificationsUtil::add("SaveBytecodeFailReason", args); - } - delete instance_uuid; -} -#endif - // static void LLPreviewLSL::onLoadComplete( LLVFS *vfs, const LLUUID& asset_uuid, LLAssetType::EType type, void* user_data, S32 status, LLExtStat ext_status) @@ -1760,7 +1996,6 @@ void LLPreviewLSL::onLoadComplete( LLVFS *vfs, const LLUUID& asset_uuid, LLAsset //static void* LLLiveLSLEditor::createScriptEdPanel(void* userdata) { - LLLiveLSLEditor *self = (LLLiveLSLEditor*)userdata; self->mScriptEd = new LLScriptEdCore( @@ -1772,19 +2007,18 @@ void* LLLiveLSLEditor::createScriptEdPanel(void* userdata) &LLLiveLSLEditor::onSearchReplace, self, 0); - return self->mScriptEd; } LLLiveLSLEditor::LLLiveLSLEditor(const std::string& name, const LLRect& rect, const std::string& title, const LLUUID& object_id, const LLUUID& item_id) : LLScriptEdContainer(name, rect, title, item_id, object_id), + mIsNew(false), mAskedForRunningInfo(FALSE), mHaveRunningInfo(FALSE), mCloseAfterSave(FALSE), mPendingUploads(0), - mIsModifiable(FALSE), - mIsNew(false) + mIsModifiable(FALSE) { mFactoryMap["script ed panel"] = LLCallbackMap(LLLiveLSLEditor::createScriptEdPanel, this); LLUICtrlFactory::getInstance()->buildFloater(this,"floater_live_lsleditor.xml", &getFactoryMap()); @@ -1805,6 +2039,16 @@ BOOL LLLiveLSLEditor::postBuild() mScriptEd->mEditor->makePristine(); mScriptEd->mEditor->setFocus(TRUE); + + mExperiences = getChild("Experiences..."); + mExperiences->setCommitCallback(boost::bind(&LLLiveLSLEditor::experienceChanged, this)); + + mExperienceEnabled = getChild("enable_xp"); + + childSetCommitCallback("enable_xp", onToggleExperience, this); + childSetCommitCallback("view_profile", onViewProfile, this); + + return LLPreview::postBuild(); } @@ -1848,59 +2092,65 @@ void LLLiveLSLEditor::loadAsset() if(object) { LLViewerInventoryItem* item = dynamic_cast(object->getInventoryObject(mItemUUID)); - if(item - && (gAgent.allowOperation(PERM_COPY, item->getPermissions(), GP_OBJECT_MANIPULATE) - || gAgent.isGodlike())) + + if (item) { - mItem = new LLViewerInventoryItem(item); - //LL_INFOS() << "asset id " << mItem->getAssetUUID() << LL_ENDL; + LLViewerRegion* region = object->getRegion(); + std::string url = std::string(); + if(region) + { + url = region->getCapability("GetMetadata"); + } + LLExperienceCache::instance().fetchAssociatedExperience(item->getParentUUID(), item->getUUID(), url, + boost::bind(&LLLiveLSLEditor::setAssociatedExperience, getDerivedHandle(), _1)); + + bool isGodlike = gAgent.isGodlike(); + bool copyManipulate = gAgent.allowOperation(PERM_COPY, item->getPermissions(), GP_OBJECT_MANIPULATE); + mIsModifiable = gAgent.allowOperation(PERM_MODIFY, item->getPermissions(), GP_OBJECT_MANIPULATE); + + if (!isGodlike && (!copyManipulate || !mIsModifiable)) + { + mItem = new LLViewerInventoryItem(item); + mScriptEd->setScriptText(getString("not_allowed"), FALSE); + mScriptEd->mEditor->makePristine(); + mScriptEd->enableSave(FALSE); + mAssetStatus = PREVIEW_ASSET_LOADED; + } + else if (copyManipulate || isGodlike) + { + mItem = new LLViewerInventoryItem(item); + // request the text from the object + LLUUID* user_data = new LLUUID(mItemUUID); // ^ mObjectUUID + gAssetStorage->getInvItemAsset(object->getRegion()->getHost(), + gAgent.getID(), + gAgent.getSessionID(), + item->getPermissions().getOwner(), + object->getID(), + item->getUUID(), + item->getAssetUUID(), + item->getType(), + &LLLiveLSLEditor::onLoadComplete, + (void*)user_data, + TRUE); + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_GetScriptRunning); + msg->nextBlockFast(_PREHASH_Script); + msg->addUUIDFast(_PREHASH_ObjectID, mObjectUUID); + msg->addUUIDFast(_PREHASH_ItemID, mItemUUID); + msg->sendReliable(object->getRegion()->getHost()); + mAskedForRunningInfo = TRUE; + mAssetStatus = PREVIEW_ASSET_LOADING; + } } - if(!gAgent.isGodlike() - && (item - && (!gAgent.allowOperation(PERM_COPY, item->getPermissions(), GP_OBJECT_MANIPULATE) - || !gAgent.allowOperation(PERM_MODIFY, item->getPermissions(), GP_OBJECT_MANIPULATE)))) - { - mItem = new LLViewerInventoryItem(item); - mScriptEd->setScriptText(getString("not_allowed"), FALSE); - mScriptEd->mEditor->makePristine(); - mScriptEd->enableSave(FALSE); - mAssetStatus = PREVIEW_ASSET_LOADED; - } - else if(item && mItem.notNull()) - { - // request the text from the object - LLUUID* user_data = new LLUUID(mItemUUID); // ^ mObjectUUID - gAssetStorage->getInvItemAsset(object->getRegion()->getHost(), - gAgent.getID(), - gAgent.getSessionID(), - item->getPermissions().getOwner(), - object->getID(), - item->getUUID(), - item->getAssetUUID(), - item->getType(), - &LLLiveLSLEditor::onLoadComplete, - (void*)user_data, - TRUE); - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_GetScriptRunning); - msg->nextBlockFast(_PREHASH_Script); - msg->addUUIDFast(_PREHASH_ObjectID, mObjectUUID); - msg->addUUIDFast(_PREHASH_ItemID, mItemUUID); - msg->sendReliable(object->getRegion()->getHost()); - mAskedForRunningInfo = TRUE; - mAssetStatus = PREVIEW_ASSET_LOADING; - } - else + if (mItem.isNull()) { mScriptEd->setScriptText(LLStringUtil::null, FALSE); mScriptEd->mEditor->makePristine(); mAssetStatus = PREVIEW_ASSET_LOADED; + mIsModifiable = FALSE; } - mIsModifiable = item && gAgent.allowOperation(PERM_MODIFY, - item->getPermissions(), - GP_OBJECT_MANIPULATE); refreshFromItem(item); // This is commented out, because we don't completely // handle script exports yet. @@ -1938,6 +2188,8 @@ void LLLiveLSLEditor::loadAsset() time_corrected()); mAssetStatus = PREVIEW_ASSET_LOADED; } + + requestExperiences(); } // static @@ -2117,6 +2369,7 @@ void LLLiveLSLEditor::draw() // Really ought to put in main window. setTitle(LLTrans::getString("ObjectOutOfRange")); runningCheckbox->setEnabled(FALSE); + mMonoCheckbox->setEnabled(FALSE); // object may have fallen out of range. mHaveRunningInfo = FALSE; } @@ -2228,26 +2481,21 @@ void LLLiveLSLEditor::saveIfNeeded(bool sync /*= true*/) BOOL is_running = getChild( "running")->get(); if (!url.empty()) { - uploadAssetViaCaps(url, filename, mObjectUUID, mItemUUID, is_running); + uploadAssetViaCaps(url, filename, mObjectUUID, mItemUUID, is_running, mScriptEd->getAssociatedExperience()); } else { mScriptEd->mErrorList->setCommentText(LLTrans::getString("CompileQueueProblemUploading")); LLFile::remove(filename); } -#if 0 //Client side compiling disabled. - else if (gAssetStorage) - { - uploadAssetLegacy(filename, object, tid, is_running); - } -#endif } void LLLiveLSLEditor::uploadAssetViaCaps(const std::string& url, const std::string& filename, const LLUUID& task_id, const LLUUID& item_id, - BOOL is_running) + BOOL is_running, + const LLUUID& experience_public_id) { LL_INFOS() << "Update Task Inventory via capability " << url << LL_ENDL; LLSD body; @@ -2255,188 +2503,11 @@ void LLLiveLSLEditor::uploadAssetViaCaps(const std::string& url, body["item_id"] = item_id; body["is_script_running"] = is_running; body["target"] = monoChecked() ? "mono" : "lsl2"; + body["experience"] = experience_public_id; LLHTTPClient::post(url, body, new LLUpdateTaskInventoryResponder(body, filename, LLAssetType::AT_LSL_TEXT)); } -#if 0 //Client side compiling disabled. -void LLLiveLSLEditor::uploadAssetLegacy(const std::string& filename, - LLViewerObject* object, - const LLTransactionID& tid, - BOOL is_running) -{ - LLLiveLSLSaveData* data = new LLLiveLSLSaveData(mObjectUUID, - mItem, - is_running); - gAssetStorage->storeAssetData(filename, tid, - LLAssetType::AT_LSL_TEXT, - &onSaveTextComplete, - (void*)data, - FALSE); - - LLAssetID asset_id = tid.makeAssetID(gAgent.getSecureSessionID()); - std::string filepath = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,asset_id.asString()); - std::string dst_filename = llformat("%s.lso", filepath.c_str()); - std::string err_filename = llformat("%s.out", filepath.c_str()); - - LLFILE *fp; - const BOOL compile_to_mono = FALSE; - if(!lscript_compile(filename.c_str(), - dst_filename.c_str(), - err_filename.c_str(), - compile_to_mono, - asset_id.asString().c_str(), - gAgent.isGodlike())) - { - // load the error file into the error scrolllist - LL_INFOS() << "Compile failed!" << LL_ENDL; - if(NULL != (fp = LLFile::fopen(err_filename, "r"))) - { - char buffer[MAX_STRING]; /*Flawfinder: ignore*/ - std::string line; - while(!feof(fp)) - { - - if (fgets(buffer, MAX_STRING, fp) == NULL) - { - buffer[0] = '\0'; - } - if(feof(fp)) - { - break; - } - else - { - line.assign(buffer); - LLStringUtil::stripNonprintable(line); - - LLSD row; - row["columns"][0]["value"] = line; - row["columns"][0]["font"] = "OCRA"; - mScriptEd->mErrorList->addElement(row); - } - } - fclose(fp); - mScriptEd->selectFirstError(); - // don't set the asset id, because we want to save the - // script, even though the compile failed. - //mItem->setAssetUUID(LLUUID::null); - object->saveScript(mItem, FALSE, false); - dialog_refresh_all(); - } - } - else - { - LL_INFOS() << "Compile worked!" << LL_ENDL; - mScriptEd->mErrorList->setCommentText(LLTrans::getString("CompileSuccessfulSaving")); - if(gAssetStorage) - { - LL_INFOS() << "LLLiveLSLEditor::saveAsset " - << mItem->getAssetUUID() << LL_ENDL; - getWindow()->incBusyCount(); - mPendingUploads++; - LLLiveLSLSaveData* data = NULL; - data = new LLLiveLSLSaveData(mObjectUUID, - mItem, - is_running); - gAssetStorage->storeAssetData(dst_filename, - tid, - LLAssetType::AT_LSL_BYTECODE, - &LLLiveLSLEditor::onSaveBytecodeComplete, - (void*)data); - dialog_refresh_all(); - } - } - - // get rid of any temp files left lying around - LLFile::remove(filename); - LLFile::remove(err_filename); - LLFile::remove(dst_filename); - - // If we successfully saved it, then we should be able to check/uncheck the running box! - LLCheckBoxCtrl* runningCheckbox = getChild( "running"); - runningCheckbox->setLabel(getString("script_running")); - runningCheckbox->setEnabled(TRUE); -} - -void LLLiveLSLEditor::onSaveTextComplete(const LLUUID& asset_uuid, void* user_data, S32 status, LLExtStat ext_status) // StoreAssetData callback (fixed) -{ - LLLiveLSLSaveData* data = (LLLiveLSLSaveData*)user_data; - - if (status) - { - LL_WARNS() << "Unable to save text for a script." << LL_ENDL; - LLSD args; - args["REASON"] = std::string(LLAssetStorage::getErrorString(status)); - LLNotificationsUtil::add("CompileQueueSaveText", args); - } - else - { - LLLiveLSLEditor* self = static_cast(LLPreview::find(data->mItem->getUUID())); // ^ data->mSaveObjectID - if (self) - { - self->getWindow()->decBusyCount(); - self->mPendingUploads--; - if (self->mPendingUploads <= 0 - && self->mCloseAfterSave) - { - self->close(); - } - } - } - delete data; - data = NULL; -} - - -void LLLiveLSLEditor::onSaveBytecodeComplete(const LLUUID& asset_uuid, void* user_data, S32 status, LLExtStat ext_status) // StoreAssetData callback (fixed) -{ - LLLiveLSLSaveData* data = (LLLiveLSLSaveData*)user_data; - if(!data) - return; - if(0 ==status) - { - LL_INFOS() << "LSL Bytecode saved" << LL_ENDL; - LLLiveLSLEditor* self = static_cast(LLPreview::find(data->mItem->getUUID())); // ^ data->mSaveObjectID - if(self) - { - // Tell the user that the compile worked. - self->mScriptEd->mErrorList->setCommentText(LLTrans::getString("SaveComplete")); - // close the window if this completes both uploads - self->getWindow()->decBusyCount(); - self->mPendingUploads--; - if (self->mPendingUploads <= 0 - && self->mCloseAfterSave) - { - self->close(); - } - } - LLViewerObject* object = gObjectList.findObject(data->mSaveObjectID); - if(object) - { - object->saveScript(data->mItem, data->mActive, false); - dialog_refresh_all(); - //LLToolDragAndDrop::dropScript(object, ids->first, - // LLAssetType::AT_LSL_TEXT, FALSE); - } - } - else - { - LL_INFOS() << "Problem saving LSL Bytecode (Live Editor)" << LL_ENDL; - LL_WARNS() << "Unable to save a compiled script." << LL_ENDL; - - LLSD args; - args["REASON"] = std::string(LLAssetStorage::getErrorString(status)); - LLNotificationsUtil::add("CompileQueueSaveBytecode", args); - } - - std::string filepath = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,asset_uuid.asString()); - std::string dst_filename = llformat("%s.lso", filepath.c_str()); - LLFile::remove(dst_filename); - delete data; -} -#endif - BOOL LLLiveLSLEditor::canClose() { return (mScriptEd->canClose()); @@ -2508,3 +2579,18 @@ BOOL LLLiveLSLEditor::monoChecked() const } return FALSE; } + +void LLLiveLSLEditor::setAssociatedExperience(LLHandle editor, const LLSD& experience) +{ + LLLiveLSLEditor* scriptEd = editor.get(); + if (scriptEd) + { + LLUUID id; + if (experience.has(LLExperienceCache::EXPERIENCE_ID)) + { + id = experience[LLExperienceCache::EXPERIENCE_ID].asUUID(); + } + scriptEd->mScriptEd->setAssociatedExperience(id); + scriptEd->updateExperiencePanel(); + } +} diff --git a/indra/newview/llpreviewscript.h b/indra/newview/llpreviewscript.h index dd1c8c780..35f6571f4 100644 --- a/indra/newview/llpreviewscript.h +++ b/indra/newview/llpreviewscript.h @@ -81,8 +81,8 @@ public: void initMenu(); - virtual void draw(); - /*virtual*/ BOOL postBuild(); + void draw() override; + BOOL postBuild() override; BOOL canClose(); void setEnableEditing(bool enable); @@ -104,7 +104,6 @@ public: static void onClickForward(void* userdata); static void onBtnInsertSample(void*); static void onBtnInsertFunction(LLUICtrl*, void*); - // Singu TODO: modernize the menu callbacks and get rid of/update this giant block of static functions static BOOL hasChanged(void* userdata); static void onBtnSave(void*); @@ -127,7 +126,9 @@ public: static BOOL enableSelectAllMenu(void* userdata); static BOOL enableDeselectMenu(void* userdata); - virtual bool hasAccelerators() const { return true; } + bool hasAccelerators() const override { return true; } + LLUUID getAssociatedExperience() const; + void setAssociatedExperience(const LLUUID& experience_id); private: static bool onHelpWebDialog(const LLSD& notification, const LLSD& response); @@ -139,7 +140,7 @@ private: void selectFirstError(); - virtual BOOL handleKeyHere(KEY key, MASK mask); + BOOL handleKeyHere(KEY key, MASK mask) override; void enableSave(BOOL b) {mEnableSave = b;} @@ -169,6 +170,7 @@ private: BOOL mEnableSave; BOOL mHasScriptData; LLLiveLSLFile* mLiveFile; + LLUUID mAssociatedExperience; LLScriptEdContainer* mContainer; // parent view @@ -194,41 +196,37 @@ protected: bool onExternalChange(const std::string& filename); virtual void saveIfNeeded(bool sync = true) = 0; - LLTextEditor* getEditor() { return mScriptEd->mEditor; } - /*virtual*/ const char *getTitleName() const { return "Script"; } + LLTextEditor* getEditor() const { return mScriptEd->mEditor; } + /*virtual*/ const char *getTitleName() const override { return "Script"; } // - /*virtual*/ BOOL canSaveAs() const; - /*virtual*/ void saveAs(); + /*virtual*/ BOOL canSaveAs() const override; + /*virtual*/ void saveAs() override; void saveAs_continued(AIFilePicker* filepicker); // LLScriptEdCore* mScriptEd; }; -// Used to view and edit a LSL from your inventory. -class LLPreviewLSL : public LLScriptEdContainer +// Used to view and edit an LSL script from your inventory. +class LLPreviewLSL final : public LLScriptEdContainer { public: LLPreviewLSL(const std::string& name, const LLRect& rect, const std::string& title, const LLUUID& item_uuid ); virtual void callbackLSLCompileSucceeded(); virtual void callbackLSLCompileFailed(const LLSD& compile_errors); - /*virtual*/ BOOL postBuild(); + /*virtual*/ BOOL postBuild() override; + protected: - virtual BOOL canClose(); + BOOL canClose() override; void closeIfNeeded(); - virtual void loadAsset(); - /*virtual*/ void saveIfNeeded(bool sync = true); + void loadAsset() override; + /*virtual*/ void saveIfNeeded(bool sync = true) override; void uploadAssetViaCaps(const std::string& url, const std::string& filename, const LLUUID& item_id); -#if 0 //Client side compiling disabled. - void uploadAssetLegacy(const std::string& filename, - const LLUUID& item_id, - const LLTransactionID& tid); -#endif static void onSearchReplace(void* userdata); static void onLoad(void* userdata); @@ -237,10 +235,6 @@ protected: static void onLoadComplete(LLVFS *vfs, const LLUUID& uuid, LLAssetType::EType type, void* user_data, S32 status, LLExtStat ext_status); -#if 0 //Client side compiling disabled. - static void onSaveComplete(const LLUUID& uuid, void* user_data, S32 status, LLExtStat ext_status); - static void onSaveBytecodeComplete(const LLUUID& asset_uuid, void* user_data, S32 status, LLExtStat ext_status); -#endif protected: static void* createScriptEdPanel(void* userdata); @@ -254,8 +248,8 @@ protected: }; -// Used to view and edit an LSL that is attached to an object. -class LLLiveLSLEditor : public LLScriptEdContainer +// Used to view and edit an LSL script that is attached to an object. +class LLLiveLSLEditor final : public LLScriptEdContainer { friend class LLLiveLSLFile; public: @@ -269,29 +263,35 @@ public: bool is_script_running); virtual void callbackLSLCompileFailed(const LLSD& compile_errors); - /*virtual*/ BOOL postBuild(); + /*virtual*/ BOOL postBuild() override; void setIsNew() { mIsNew = TRUE; } -private: - virtual BOOL canClose(); - void closeIfNeeded(); - virtual void draw(); + static void setAssociatedExperience(LLHandle editor, const LLSD& experience); + static void onToggleExperience(LLUICtrl* ui, void* userdata); + static void onViewProfile(LLUICtrl* ui, void* userdata); - virtual void loadAsset(); + void setExperienceIds(const LLSD& experience_ids); + void buildExperienceList(); + void updateExperiencePanel(); + void requestExperiences(); + void experienceChanged(); + void addAssociatedExperience(const LLSD& experience); + +private: + BOOL canClose() override; + void closeIfNeeded(); + void draw() override; + + void loadAsset() override; void loadAsset(BOOL is_new); - /*virtual*/ void saveIfNeeded(bool sync = true); + /*virtual*/ void saveIfNeeded(bool sync = true) override; void uploadAssetViaCaps(const std::string& url, - const std::string& filename, + const std::string& filename, const LLUUID& task_id, const LLUUID& item_id, - BOOL is_running); -#if 0 //Client side compiling disabled. - void uploadAssetLegacy(const std::string& filename, - LLViewerObject* object, - const LLTransactionID& tid, - BOOL is_running); -#endif + BOOL is_running, + const LLUUID& experience_public_id); BOOL monoChecked() const; @@ -302,10 +302,6 @@ private: static void onLoadComplete(LLVFS *vfs, const LLUUID& asset_uuid, LLAssetType::EType type, void* user_data, S32 status, LLExtStat ext_status); -#if 0 //Client side compiling disabled. - static void onSaveTextComplete(const LLUUID& asset_uuid, void* user_data, S32 status, LLExtStat ext_status); - static void onSaveBytecodeComplete(const LLUUID& asset_uuid, void* user_data, S32 status, LLExtStat ext_status); -#endif static void onRunningCheckboxClicked(LLUICtrl*, void* userdata); static void onReset(void* userdata); @@ -317,6 +313,8 @@ private: static void onMonoCheckboxClicked(LLUICtrl*, void* userdata); + static void receiveExperienceIds(const struct LLCoroResponder& responder, LLHandle parent); + private: bool mIsNew; //LLUUID mTransmitID; @@ -330,9 +328,16 @@ private: S32 mPendingUploads; BOOL getIsModifiable() const { return mIsModifiable; } // Evaluated on load assert - + LLCheckBoxCtrl* mMonoCheckbox; BOOL mIsModifiable; + + + LLComboBox* mExperiences; + LLCheckBoxCtrl* mExperienceEnabled; + LLSD mExperienceIds; + + LLHandle mExperienceProfile; }; #endif // LL_LLPREVIEWSCRIPT_H diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 7cb3be329..371d4c68c 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -1998,7 +1998,7 @@ void LLSelectMgr::selectionSetMedia(U8 media_type, const LLSD &media_data) else { // Add/update media object->setTEMediaFlags(te, mMediaFlags); - LLVOVolume *vo = dynamic_cast(object); + LLVOVolume *vo = object->asVolume(); llassert(NULL != vo); if (NULL != vo) { @@ -2024,7 +2024,7 @@ void LLSelectMgr::selectionSetMedia(U8 media_type, const LLSD &media_data) if (object->permModify()) { object->sendTEUpdate(); - LLVOVolume *vo = dynamic_cast(object); + LLVOVolume *vo = object->asVolume(); llassert(NULL != vo); // It's okay to skip this object if hasMedia() is false... // the sendTEUpdate() above would remove all media data if it were @@ -5446,6 +5446,7 @@ void LLSelectMgr::processObjectProperties(LLMessageSystem* msg, void** user_data node->mInventorySerial = inv_serial; node->mSitName.assign(sit_name); node->mTouchName.assign(touch_name); + if (auto obj = node->getObject()) obj->mOwnerID = owner_id; // Singu Note: Try to get Owner whenever possible } } @@ -7434,7 +7435,7 @@ S32 LLObjectSelection::getSelectedObjectRenderCost() ++child_iter) { LLViewerObject* child_obj = *child_iter; - LLVOVolume *child = dynamic_cast( child_obj ); + LLVOVolume *child = child_obj ? child_obj->asVolume() : nullptr; if (child) { cost += child->getRenderCost(textures); diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index 3f9a4ef0b..f07432fea 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -1787,7 +1787,7 @@ void renderComplexityDisplay(LLDrawable* drawablep) return; } - LLVOVolume *voVol = dynamic_cast(vobj); + LLVOVolume *voVol = vobj->asVolume();; if (!voVol) { diff --git a/indra/newview/llspeakers.cpp b/indra/newview/llspeakers.cpp index 3012aae00..2eb588e7d 100644 --- a/indra/newview/llspeakers.cpp +++ b/indra/newview/llspeakers.cpp @@ -240,7 +240,7 @@ LLSpeakersDelayActionsStorage::~LLSpeakersDelayActionsStorage() void LLSpeakersDelayActionsStorage::setActionTimer(const LLUUID& speaker_id) { bool not_found = true; - if (mActionTimersMap.size() > 0) + if (!mActionTimersMap.empty()) { not_found = mActionTimersMap.find(speaker_id) == mActionTimersMap.end(); } @@ -258,7 +258,7 @@ void LLSpeakersDelayActionsStorage::setActionTimer(const LLUUID& speaker_id) void LLSpeakersDelayActionsStorage::unsetActionTimer(const LLUUID& speaker_id) { - if (mActionTimersMap.size() == 0) return; + if (mActionTimersMap.empty()) return; LLSpeakerActionTimer::action_timer_iter_t it_speaker = mActionTimersMap.find(speaker_id); @@ -434,8 +434,8 @@ void LLSpeakerMgr::update(BOOL resort_ok) return; } - LLColor4 speaking_color = gSavedSettings.getColor4("SpeakingColor"); - LLColor4 overdriven_color = gSavedSettings.getColor4("OverdrivenColor"); + static const LLCachedControl speaking_color(gSavedSettings, "SpeakingColor"); + static const LLCachedControl overdriven_color(gSavedSettings, "OverdrivenColor"); if(resort_ok) // only allow list changes when user is not interacting with it { @@ -445,10 +445,10 @@ void LLSpeakerMgr::update(BOOL resort_ok) // update status of all current speakers BOOL voice_channel_active = (!mVoiceChannel && LLVoiceClient::getInstance()->inProximalChannel()) || (mVoiceChannel && mVoiceChannel->isActive()); bool re_sort = false; - for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); ++speaker_it) + for (auto& speaker : mSpeakers) { - LLUUID speaker_id = speaker_it->first; - LLSpeaker* speakerp = speaker_it->second; + LLUUID speaker_id = speaker.first; + LLSpeaker* speakerp = speaker.second; if (voice_channel_active && LLVoiceClient::getInstance()->getVoiceEnabled(speaker_id)) { @@ -532,12 +532,8 @@ void LLSpeakerMgr::update(BOOL resort_ok) bool index_changed = false; S32 recent_speaker_count = 0; S32 sort_index = 0; - for (speaker_list_t::iterator sorted_speaker_it = mSpeakersSorted.begin(); - sorted_speaker_it != mSpeakersSorted.end(); - ++sorted_speaker_it) + for (auto speakerp : mSpeakersSorted) { - LLPointer speakerp = *sorted_speaker_it; - // color code recent speakers who are not currently speaking if (speakerp->mStatus == LLSpeaker::STATUS_HAS_SPOKEN) { @@ -561,9 +557,6 @@ void LLSpeakerMgr::update(BOOL resort_ok) void LLSpeakerMgr::updateSpeakerList() { - // Always add the current agent (it has to be there...). Will do nothing if already there. - setSpeaker({ gAgentID, LLSpeaker::SPEAKER_AGENT, LLSpeaker::STATUS_VOICE_ACTIVE }); - // Are we bound to the currently active voice channel? if ((!mVoiceChannel && LLVoiceClient::getInstance()->inProximalChannel()) || (mVoiceChannel && mVoiceChannel->isActive())) { @@ -572,22 +565,21 @@ void LLSpeakerMgr::updateSpeakerList() // If we are, add all voice client participants to our list of known speakers std::vector speakers; speakers.reserve(participants.size()); - for (auto participant_it = participants.begin(); participant_it != participants.end(); ++participant_it) + for (auto participant : participants) { - speakers.emplace_back( - *participant_it, - (LLVoiceClient::getInstance()->isParticipantAvatar(*participant_it) ? LLSpeaker::SPEAKER_AGENT : LLSpeaker::SPEAKER_EXTERNAL), + speakers.emplace_back(participant, + (LLVoiceClient::getInstance()->isParticipantAvatar(participant) ? LLSpeaker::SPEAKER_AGENT : LLSpeaker::SPEAKER_EXTERNAL), LLSpeaker::STATUS_VOICE_ACTIVE, boost::none, boost::none, - LLVoiceClient::getInstance()->getDisplayName(*participant_it)); + LLVoiceClient::getInstance()->getDisplayName(participant)); } setSpeakers(speakers); } else { // If not, check if the list is empty, except if it's Nearby Chat (session_id NULL). - LLUUID session_id = getSessionID(); + LLUUID const& session_id = getSessionID(); if (!session_id.isNull() && !mSpeakerListUpdated) { // If the list is empty, we update it with whatever we have locally so that it doesn't stay empty too long. @@ -636,15 +628,16 @@ void LLSpeakerMgr::updateSpeakerList() mSpeakerListUpdated = true; } } - else if (floater && mSpeakers.size() == 0) + else if (floater && mSpeakers.empty()) { // For all other session type (ad-hoc, P2P, avaline), we use the initial participants targets list - for (const auto& id : floater->mInitialTargetIDs) + for (const auto& target_id : floater->mInitialTargetIDs) { // Add buddies if they are on line, add any other avatar. - if (!LLAvatarTracker::instance().isBuddy(id) || LLAvatarTracker::instance().isBuddyOnline(id)) + if (!LLAvatarTracker::instance().isBuddy(target_id) || LLAvatarTracker::instance().isBuddyOnline( + target_id)) { - setSpeaker({ id, LLSpeaker::SPEAKER_AGENT, LLSpeaker::STATUS_VOICE_ACTIVE }); + setSpeaker({target_id, LLSpeaker::SPEAKER_AGENT, LLSpeaker::STATUS_VOICE_ACTIVE }); } } mSpeakerListUpdated = true; @@ -656,13 +649,18 @@ void LLSpeakerMgr::updateSpeakerList() } } } + // Always add the current agent (it has to be there...). Will do nothing if already there. + setSpeaker({ gAgentID, LLSpeaker::SPEAKER_AGENT, LLSpeaker::STATUS_VOICE_ACTIVE }); } -void LLSpeakerMgr::setSpeakerNotInChannel(LLSpeaker* speakerp) +void LLSpeakerMgr::setSpeakerNotInChannel(LLPointer speakerp) { - speakerp->setStatus(LLSpeaker::STATUS_NOT_IN_CHANNEL); - speakerp->mDotColor = INACTIVE_COLOR; - mSpeakerDelayRemover->setActionTimer(speakerp->mID); + if (speakerp.notNull()) + { + speakerp->setStatus(LLSpeaker::STATUS_NOT_IN_CHANNEL); + speakerp->mDotColor = INACTIVE_COLOR; + mSpeakerDelayRemover->setActionTimer(speakerp->mID); + } } bool LLSpeakerMgr::removeSpeaker(const LLUUID& speaker_id) @@ -691,12 +689,12 @@ bool LLSpeakerMgr::removeSpeaker(const LLUUID& speaker_id) LLPointer LLSpeakerMgr::findSpeaker(const LLUUID& speaker_id) { //In some conditions map causes crash if it is empty(Windows only), adding check (EK) - if (mSpeakers.size() == 0) - return NULL; + if (mSpeakers.empty()) + return nullptr; speaker_map_t::iterator found_it = mSpeakers.find(speaker_id); if (found_it == mSpeakers.end()) { - return NULL; + return nullptr; } return found_it->second; } @@ -704,9 +702,9 @@ LLPointer LLSpeakerMgr::findSpeaker(const LLUUID& speaker_id) void LLSpeakerMgr::getSpeakerList(speaker_list_t* speaker_list, BOOL include_text) { speaker_list->clear(); - for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); ++speaker_it) + for (auto& speaker : mSpeakers) { - LLPointer speakerp = speaker_it->second; + LLPointer speakerp = speaker.second; // what about text only muted or inactive? if (include_text || speakerp->mStatus != LLSpeaker::STATUS_TEXT_ONLY) { @@ -715,12 +713,12 @@ void LLSpeakerMgr::getSpeakerList(speaker_list_t* speaker_list, BOOL include_tex } } -const LLUUID LLSpeakerMgr::getSessionID() +const LLUUID LLSpeakerMgr::getSessionID() const { return mVoiceChannel->getSessionID(); } -bool LLSpeakerMgr::isSpeakerToBeRemoved(const LLUUID& speaker_id) +bool LLSpeakerMgr::isSpeakerToBeRemoved(const LLUUID& speaker_id) const { return mSpeakerDelayRemover && mSpeakerDelayRemover->isTimerStarted(speaker_id); } @@ -746,7 +744,7 @@ void LLSpeakerMgr::speakerChatted(const LLUUID& speaker_id) } } -BOOL LLSpeakerMgr::isVoiceActive() +BOOL LLSpeakerMgr::isVoiceActive() const { // mVoiceChannel = NULL means current voice channel, whatever it is return LLVoiceClient::getInstance()->voiceEnabled() && mVoiceChannel && mVoiceChannel->isActive(); @@ -815,20 +813,19 @@ void LLIMSpeakerMgr::updateSpeakers(const LLSD& update) std::vector speakerentries; if ( update.has("agent_updates") && update["agent_updates"].isMap() ) { - - for (const auto& update : update["agent_updates"].map()) + for (const auto& update_it : update["agent_updates"].map()) { - LLUUID agent_id(update.first); + LLUUID agent_id(update_it.first); LLPointer speakerp = findSpeaker(agent_id); bool new_speaker = false; boost::optional moderator; boost::optional moderator_muted_text; - LLSD agent_data = update.second; + LLSD agent_data = update_it.second; if (agent_data.isMap() && agent_data.has("transition")) { - if (agent_data["transition"].asString() == "LEAVE" && speakerp.notNull()) + if (agent_data["transition"].asString() == "LEAVE") { setSpeakerNotInChannel(speakerp); } @@ -872,14 +869,13 @@ void LLIMSpeakerMgr::updateSpeakers(const LLSD& update) } else if ( update.has("updates") && update["updates"].isMap() ) { - LLSD::map_const_iterator update_it; - for (const auto& update : update["updates"].map()) + for (const auto& update_it : update["updates"].map()) { - LLUUID agent_id(update.first); + LLUUID agent_id(update_it.first); LLPointer speakerp = findSpeaker(agent_id); - std::string agent_transition = update_it->second.asString(); - if (agent_transition == "LEAVE" && speakerp.notNull()) + std::string agent_transition = update_it.second.asString(); + if (agent_transition == "LEAVE") { setSpeakerNotInChannel(speakerp); } @@ -902,7 +898,7 @@ void LLIMSpeakerMgr::toggleAllowTextChat(const LLUUID& speaker_id) LLPointer speakerp = findSpeaker(speaker_id); if (!speakerp) return; - std::string url = gAgent.getRegion()->getCapability("ChatSessionRequest"); + std::string url = gAgent.getRegionCapability("ChatSessionRequest"); LLSD data; data["method"] = "mute update"; data["session-id"] = getSessionID(); @@ -927,7 +923,7 @@ void LLIMSpeakerMgr::moderateVoiceParticipant(const LLUUID& avatar_id, bool unmu // do not send voice moderation changes for avatars not in voice channel if (!is_in_voice) return; - std::string url = gAgent.getRegion()->getCapability("ChatSessionRequest"); + std::string url = gAgent.getRegionCapability("ChatSessionRequest"); LLSD data; data["method"] = "mute update"; data["session-id"] = getSessionID(); @@ -967,7 +963,7 @@ void LLIMSpeakerMgr::processSessionUpdate(const LLSD& session_update) void LLIMSpeakerMgr::moderateVoiceSession(const LLUUID& session_id, bool disallow_voice) { - std::string url = gAgent.getRegion()->getCapability("ChatSessionRequest"); + std::string url = gAgent.getRegionCapability("ChatSessionRequest"); LLSD data; data["method"] = "session update"; data["session-id"] = session_id; @@ -983,13 +979,13 @@ void LLIMSpeakerMgr::moderateVoiceSession(const LLUUID& session_id, bool disallo void LLIMSpeakerMgr::forceVoiceModeratedMode(bool should_be_muted) { - for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); ++speaker_it) + for (auto& speaker : mSpeakers) { - LLUUID speaker_id = speaker_it->first; - LLSpeaker* speakerp = speaker_it->second; + LLUUID speaker_id = speaker.first; + LLSpeaker* speakerp = speaker.second; // participant does not match requested state - if (should_be_muted != (bool)speakerp->mModeratorMutedVoice) + if (should_be_muted != static_cast(speakerp->mModeratorMutedVoice)) { moderateVoiceParticipant(speaker_id, !should_be_muted); } @@ -1023,10 +1019,9 @@ void LLActiveSpeakerMgr::updateSpeakerList() LLSpeakerMgr::updateSpeakerList(); // clean up text only speakers - for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); ++speaker_it) + for (auto& speaker : mSpeakers) { - LLUUID speaker_id = speaker_it->first; - LLSpeaker* speakerp = speaker_it->second; + LLSpeaker* speakerp = speaker.second; if (speakerp->mStatus == LLSpeaker::STATUS_TEXT_ONLY) { // automatically flag text only speakers for removal @@ -1072,10 +1067,10 @@ void LLLocalSpeakerMgr::updateSpeakerList() setSpeakers(speakers); // check if text only speakers have moved out of chat range - for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); ++speaker_it) + for (auto& speaker : mSpeakers) { - LLUUID speaker_id = speaker_it->first; - LLPointer speakerp = speaker_it->second; + LLUUID speaker_id = speaker.first; + LLPointer speakerp = speaker.second; if (speakerp.notNull() && speakerp->mStatus == LLSpeaker::STATUS_TEXT_ONLY) { LLVOAvatar* avatarp = gObjectList.findAvatar(speaker_id); diff --git a/indra/newview/llspeakers.h b/indra/newview/llspeakers.h index 689ba336f..e28cd9a20 100644 --- a/indra/newview/llspeakers.h +++ b/indra/newview/llspeakers.h @@ -36,7 +36,7 @@ class LLSpeakerMgr; class LLVoiceChannel; // data for a given participant in a voice channel -class LLSpeaker : public LLRefCount, public LLOldEvents::LLObservable, public LLHandleProvider, public boost::signals2::trackable +class LLSpeaker final : public LLRefCount, public LLOldEvents::LLObservable, public LLHandleProvider, public boost::signals2::trackable { public: typedef enum e_speaker_type @@ -80,7 +80,7 @@ public: }; LLSpeaker(const speaker_entry_t& entry); - ~LLSpeaker() {}; + ~LLSpeaker() = default; void update(const speaker_entry_t& entry); void lookupName(); @@ -130,44 +130,44 @@ public: S32 mSortIndex; }; -class LLSpeakerUpdateSpeakerEvent : public LLOldEvents::LLEvent +class LLSpeakerUpdateSpeakerEvent final : public LLOldEvents::LLEvent { public: LLSpeakerUpdateSpeakerEvent(LLSpeaker* source); - /*virtual*/ LLSD getValue(); + /*virtual*/ LLSD getValue() override; private: const LLUUID& mSpeakerID; }; -class LLSpeakerUpdateModeratorEvent : public LLOldEvents::LLEvent +class LLSpeakerUpdateModeratorEvent final : public LLOldEvents::LLEvent { public: LLSpeakerUpdateModeratorEvent(LLSpeaker* source); - /*virtual*/ LLSD getValue(); + /*virtual*/ LLSD getValue() override; private: const LLUUID& mSpeakerID; BOOL mIsModerator; }; -class LLSpeakerTextModerationEvent : public LLOldEvents::LLEvent +class LLSpeakerTextModerationEvent final : public LLOldEvents::LLEvent { public: LLSpeakerTextModerationEvent(LLSpeaker* source); - /*virtual*/ LLSD getValue(); + /*virtual*/ LLSD getValue() override; }; -class LLSpeakerVoiceModerationEvent : public LLOldEvents::LLEvent +class LLSpeakerVoiceModerationEvent final : public LLOldEvents::LLEvent { public: LLSpeakerVoiceModerationEvent(LLSpeaker* source); - /*virtual*/ LLSD getValue(); + /*virtual*/ LLSD getValue() override; }; -class LLSpeakerListChangeEvent : public LLOldEvents::LLEvent +class LLSpeakerListChangeEvent final : public LLOldEvents::LLEvent { public: LLSpeakerListChangeEvent(LLSpeakerMgr* source, const LLUUID& speaker_id); - /*virtual*/ LLSD getValue(); + /*virtual*/ LLSD getValue() override; private: const LLUUID& mSpeakerID; @@ -183,7 +183,7 @@ private: * Otherwise it should be deleted manually in place where it is used. * If action callback is not set timer will tick only once and deleted. */ -class LLSpeakerActionTimer : public LLEventTimer +class LLSpeakerActionTimer final : public LLEventTimer { public: typedef std::function action_callback_t; @@ -200,14 +200,14 @@ public: * @param speaker_id - LLUUID of speaker which will be passed into action callback. */ LLSpeakerActionTimer(action_callback_t action_cb, F32 action_period, const LLUUID& speaker_id); - virtual ~LLSpeakerActionTimer() {}; + virtual ~LLSpeakerActionTimer() = default; /** * Implements timer "tick". * * If action callback is not specified returns true. Instance will be deleted by LLEventTimer::updateClass(). */ - virtual BOOL tick(); + BOOL tick() override; /** * Clears the callback. @@ -285,13 +285,13 @@ public: void setSpeakers(const std::vector& speakers); LLPointer setSpeaker(const speaker_entry_t& speakers); - BOOL isVoiceActive(); + BOOL isVoiceActive() const; typedef std::vector > speaker_list_t; void getSpeakerList(speaker_list_t* speaker_list, BOOL include_text); LLVoiceChannel* getVoiceChannel() { return mVoiceChannel; } - const LLUUID getSessionID(); - bool isSpeakerToBeRemoved(const LLUUID& speaker_id); + const LLUUID getSessionID() const; + bool isSpeakerToBeRemoved(const LLUUID& speaker_id) const; /** * Removes avaline speaker. @@ -310,7 +310,7 @@ public: protected: virtual void updateSpeakerList(); - void setSpeakerNotInChannel(LLSpeaker* speackerp); + void setSpeakerNotInChannel(LLPointer speackerp); bool removeSpeaker(const LLUUID& speaker_id); typedef std::map > speaker_map_t; @@ -336,7 +336,7 @@ protected: bool mModerateModeHandledFirstTime; }; -class LLIMSpeakerMgr : public LLSpeakerMgr +class LLIMSpeakerMgr final : public LLSpeakerMgr { LOG_CLASS(LLIMSpeakerMgr); @@ -376,7 +376,7 @@ public: void processSessionUpdate(const LLSD& session_update); protected: - virtual void updateSpeakerList(); + void updateSpeakerList() override; void moderateVoiceSession(const LLUUID& session_id, bool disallow_voice); @@ -387,24 +387,24 @@ protected: }; -class LLActiveSpeakerMgr : public LLSpeakerMgr, public LLSingleton +class LLActiveSpeakerMgr final : public LLSpeakerMgr, public LLSingleton { LOG_CLASS(LLActiveSpeakerMgr); public: LLActiveSpeakerMgr(); protected: - virtual void updateSpeakerList(); + void updateSpeakerList() override; }; -class LLLocalSpeakerMgr : public LLSpeakerMgr, public LLSingleton +class LLLocalSpeakerMgr final : public LLSpeakerMgr, public LLSingleton { LOG_CLASS(LLLocalSpeakerMgr); public: LLLocalSpeakerMgr(); ~LLLocalSpeakerMgr (); protected: - virtual void updateSpeakerList(); + void updateSpeakerList() override; }; #endif // LL_LLSPEAKERS_H diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index add23140c..750de91bb 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -44,8 +44,7 @@ #include "llviewermedia_streamingaudio.h" #include "llaudioengine.h" - -#if LL_FMODSTUDIO +#ifdef LL_FMODSTUDIO # include "llaudioengine_fmodstudio.h" #endif @@ -61,6 +60,7 @@ #include "llares.h" #include "llavatarnamecache.h" +#include "llexperiencecache.h" #include "lllandmark.h" #include "llcachename.h" #include "lldir.h" @@ -230,7 +230,6 @@ // #include "llpathfindingmanager.h" -#include "llevents.h" #include "lgghunspell_wrapper.h" @@ -238,6 +237,8 @@ #include "rlvhandler.h" // [/RLVa:KB] +#include "llevents.h" +#include "llexperiencelog.h" #if LL_WINDOWS #include "llwindebug.h" #include "lldxhardware.h" @@ -319,7 +320,7 @@ void transition_back_to_login_panel(const std::string& emsg); void callback_cache_name(const LLUUID& id, const std::string& full_name, bool is_group) { - LLNameUI::refreshAll(id, full_name, is_group); + LLNameUI::refreshAll(id, full_name); // TODO: Actually be intelligent about the refresh. // For now, just brute force refresh the dialogs. @@ -1087,27 +1088,12 @@ bool idle_startup() } //Get these logs out of my newview root directory, PLEASE. - if (gHippoGridManager->getCurrentGrid()->isSecondLife()) - { - gDirUtilp->setPerAccountChatLogsDir(LLStringUtil::null, - gSavedSettings.getString("FirstName"), gSavedSettings.getString("LastName") ); - } - else - { - gDirUtilp->setPerAccountChatLogsDir(gHippoGridManager->getConnectedGrid()->getGridNick(), - gSavedSettings.getString("FirstName"), gSavedSettings.getString("LastName") ); - } + gDirUtilp->setPerAccountChatLogsDir(gHippoGridManager->getCurrentGrid()->isSecondLife() ? LLStringUtil::null : gHippoGridManager->getConnectedGrid()->getGridNick(), + gSavedSettings.getString("FirstName"), gSavedSettings.getString("LastName")); LLFile::mkdir(gDirUtilp->getChatLogsDir()); LLFile::mkdir(gDirUtilp->getPerAccountChatLogsDir()); - // NaCl - Antispam - U32 antispam_time = gSavedSettings.getU32("_NACL_AntiSpamTime"); - U32 antispam_amount = gSavedSettings.getU32("_NACL_AntiSpamAmount"); - NACLAntiSpamRegistry::registerQueues(antispam_time, antispam_amount); - gSavedSettings.getControl("_NACL_AntiSpamGlobalQueue")->getSignal()->connect(boost::bind(&NACLAntiSpamRegistry::handleNaclAntiSpamGlobalQueueChanged, _2)); - gSavedSettings.getControl("_NACL_AntiSpamTime")->getSignal()->connect(boost::bind(&NACLAntiSpamRegistry::handleNaclAntiSpamTimeChanged, _2)); - gSavedSettings.getControl("_NACL_AntiSpamAmount")->getSignal()->connect(boost::bind(&NACLAntiSpamRegistry::handleNaclAntiSpamAmountChanged, _2)); - // NaCl End + NACLAntiSpamRegistry::startup(); // NaCl - Antispam //good a place as any to create user windlight directories std::string user_windlight_path_name(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight", "")); @@ -1725,6 +1711,9 @@ bool idle_startup() // object is created. I think this must be done after setting the region. JC gAgent.setPositionAgent(agent_start_position_region); + display_startup(); + LLStartUp::initExperiences(); + display_startup(); LLStartUp::setStartupState( STATE_MULTIMEDIA_INIT ); return FALSE; @@ -3019,17 +3008,7 @@ void pass_processObjectPropertiesFamily(LLMessageSystem *msg, void**) void process_script_running_reply(LLMessageSystem* msg, void** v) { LLLiveLSLEditor::processScriptRunningReply(msg, v); - if (ScriptCounter::sCheckMap.size()) - { - LLUUID item_id; - msg->getUUIDFast(_PREHASH_Script, _PREHASH_ItemID, item_id); - std::map::iterator it = ScriptCounter::sCheckMap.find(item_id); - if (it != ScriptCounter::sCheckMap.end()) - { - it->second->processRunningReply(msg); - ScriptCounter::sCheckMap.erase(it); - } - } + ScriptCounter::processScriptRunningReply(msg); } void register_viewer_callbacks(LLMessageSystem* msg) @@ -3551,12 +3530,22 @@ void LLStartUp::initNameCache() LLAvatarNameCache::setUseUsernames(!phoenix_name_system || phoenix_name_system == 1 || phoenix_name_system == 3); } + +void LLStartUp::initExperiences() +{ + // Should trigger loading the cache. + LLExperienceCache::instance().setCapabilityQuery( + boost::bind(&LLAgent::getRegionCapability, &gAgent, _1)); + + LLExperienceLog::instance().initialize(); +} + void LLStartUp::cleanupNameCache() { LLAvatarNameCache::cleanupClass(); delete gCacheName; - gCacheName = NULL; + gCacheName = nullptr; } bool LLStartUp::dispatchURL() @@ -4288,3 +4277,4 @@ void transition_back_to_login_panel(const std::string& emsg) reset_login(); // calls LLStartUp::setStartupState( STATE_LOGIN_SHOW ); gSavedSettings.setBOOL("AutoLogin", FALSE); } + diff --git a/indra/newview/llstartup.h b/indra/newview/llstartup.h index f53d9d5b0..71f89e59b 100644 --- a/indra/newview/llstartup.h +++ b/indra/newview/llstartup.h @@ -104,6 +104,7 @@ public: static void fontInit(); static void initNameCache(); + static void initExperiences(); static void cleanupNameCache(); diff --git a/indra/newview/llsurface.cpp b/indra/newview/llsurface.cpp index 3447b81e2..84583d7e4 100644 --- a/indra/newview/llsurface.cpp +++ b/indra/newview/llsurface.cpp @@ -163,8 +163,8 @@ void LLSurface::create(const S32 grids_per_edge, mOOGridsPerEdge = 1.f / mGridsPerEdge; mGridsPerPatchEdge = grids_per_patch_edge; mPatchesPerEdge = (mGridsPerEdge - 1) / mGridsPerPatchEdge; - mMetersPerGrid = width / ((F32)(mGridsPerEdge - 1)); - mMetersPerEdge = mMetersPerGrid * (mGridsPerEdge - 1); + mMetersPerGrid = width / (F32)grids_per_edge; + mMetersPerEdge = mMetersPerGrid * grids_per_edge; // Aurora Sim sTextureSize = width; // Aurora Sim diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index 3065a71a0..162e715ae 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -523,7 +523,7 @@ class SGHostBlackList{ } //should make a functor. if i cared. static void cleanup() { - std::remove_if(blacklist.begin(), blacklist.end(), is_obsolete); + (void)std::remove_if(blacklist.begin(), blacklist.end(), is_obsolete); } static iter find(std::string host) { diff --git a/indra/newview/lltoolgrab.cpp b/indra/newview/lltoolgrab.cpp index 835d0be67..267b34761 100644 --- a/indra/newview/lltoolgrab.cpp +++ b/indra/newview/lltoolgrab.cpp @@ -403,7 +403,7 @@ void LLToolGrab::startGrab() mDragStartPointGlobal = grab_start_global; mDragStartFromCamera = grab_start_global - gAgentCamera.getCameraPositionGlobal(); - send_ObjectGrab_message(objectp, mGrabPick, grab_offset); + send_ObjectGrab_message(objectp, true, &mGrabPick, grab_offset); mGrabOffsetFromCenterInitial = grab_offset; mGrabHiddenOffsetFromCamera = mDragStartFromCamera; @@ -1079,7 +1079,7 @@ void LLToolGrab::stopGrab() case GRAB_ACTIVE_CENTER: case GRAB_NONPHYSICAL: case GRAB_LOCKED: - send_ObjectDeGrab_message(objectp, pick); + send_ObjectGrab_message(objectp, false, &pick); mVerticalDragging = FALSE; break; @@ -1133,64 +1133,45 @@ LLVector3d LLToolGrab::getGrabPointGlobal() } -void send_ObjectGrab_message(LLViewerObject* object, const LLPickInfo & pick, const LLVector3 &grab_offset) +void send_ObjectGrab_message(LLViewerObject* object, bool grab, const LLPickInfo* const pick, const LLVector3 &grab_offset) { if (!object) return; LLMessageSystem *msg = gMessageSystem; - msg->newMessageFast(_PREHASH_ObjectGrab); + msg->newMessageFast(grab ? _PREHASH_ObjectGrab : _PREHASH_ObjectDeGrab); msg->nextBlockFast( _PREHASH_AgentData); msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); msg->nextBlockFast( _PREHASH_ObjectData); msg->addU32Fast( _PREHASH_LocalID, object->mLocalID); - msg->addVector3Fast(_PREHASH_GrabOffset, grab_offset); - msg->nextBlock("SurfaceInfo"); - msg->addVector3("UVCoord", LLVector3(pick.mUVCoords)); - msg->addVector3("STCoord", LLVector3(pick.mSTCoords)); - msg->addS32Fast(_PREHASH_FaceIndex, pick.mObjectFace); - msg->addVector3("Position", pick.mIntersection); - msg->addVector3("Normal", pick.mNormal); - msg->addVector3("Binormal", pick.mBinormal); + if (grab) msg->addVector3Fast(_PREHASH_GrabOffset, grab_offset); + if (pick) + { + msg->nextBlock("SurfaceInfo"); + msg->addVector3("UVCoord", LLVector3(pick->mUVCoords)); + msg->addVector3("STCoord", LLVector3(pick->mSTCoords)); + msg->addS32Fast(_PREHASH_FaceIndex, pick->mObjectFace); + msg->addVector3("Position", pick->mIntersection); + msg->addVector3("Normal", pick->mNormal); + msg->addVector3("Binormal", pick->mBinormal); + } msg->sendMessage( object->getRegion()->getHost()); /* Diagnostic code - LL_INFOS() << "mUVCoords: " << pick.mUVCoords - << ", mSTCoords: " << pick.mSTCoords - << ", mObjectFace: " << pick.mObjectFace - << ", mIntersection: " << pick.mIntersection - << ", mNormal: " << pick.mNormal - << ", mBinormal: " << pick.mBinormal + if (pick) + { + LL_INFOS() << "mUVCoords: " << pick->mUVCoords + << ", mSTCoords: " << pick->mSTCoords + << ", mObjectFace: " << pick->mObjectFace + << ", mIntersection: " << pick->mIntersection + << ", mNormal: " << pick->mNormal + << ", mBinormal: " << pick->mBinormal << LL_ENDL; + } LL_INFOS() << "Avatar pos: " << gAgent.getPositionAgent() << LL_ENDL; LL_INFOS() << "Object pos: " << object->getPosition() << LL_ENDL; */ } - -void send_ObjectDeGrab_message(LLViewerObject* object, const LLPickInfo & pick) -{ - if (!object) return; - - LLMessageSystem *msg = gMessageSystem; - - msg->newMessageFast(_PREHASH_ObjectDeGrab); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_ObjectData); - msg->addU32Fast(_PREHASH_LocalID, object->mLocalID); - msg->nextBlock("SurfaceInfo"); - msg->addVector3("UVCoord", LLVector3(pick.mUVCoords)); - msg->addVector3("STCoord", LLVector3(pick.mSTCoords)); - msg->addS32Fast(_PREHASH_FaceIndex, pick.mObjectFace); - msg->addVector3("Position", pick.mIntersection); - msg->addVector3("Normal", pick.mNormal); - msg->addVector3("Binormal", pick.mBinormal); - msg->sendMessage(object->getRegion()->getHost()); -} - - - diff --git a/indra/newview/lltoolgrab.h b/indra/newview/lltoolgrab.h index d5c99a43f..98f5fdd91 100644 --- a/indra/newview/lltoolgrab.h +++ b/indra/newview/lltoolgrab.h @@ -41,9 +41,7 @@ class LLPickInfo; // Message utilities -void send_ObjectGrab_message(LLViewerObject* object, const LLPickInfo & pick, const LLVector3 &grab_offset); -void send_ObjectDeGrab_message(LLViewerObject* object, const LLPickInfo & pick); - +void send_ObjectGrab_message(LLViewerObject* object, bool grab, const LLPickInfo* const pick = nullptr, const LLVector3& grab_offset = LLVector3::zero); class LLToolGrab : public LLTool, public LLSingleton diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp index 9fd131d59..0f24ca943 100644 --- a/indra/newview/lltoolpie.cpp +++ b/indra/newview/lltoolpie.cpp @@ -533,7 +533,7 @@ void LLToolPie::walkToClickedLocation() mAutoPilotDestination->setDuration(3.f); */ - handle_go_to(); + handle_go_to(mPick.mPosGlobal); } // When we get object properties after left-clicking on an object @@ -569,7 +569,7 @@ void LLToolPie::selectionPropertiesReceived() case CLICK_ACTION_PAY: if ( LLToolPie::getInstance()->mClickActionPayEnabled ) { - handle_give_money_dialog(); + handle_give_money_dialog(selected_object); } break; case CLICK_ACTION_OPEN: @@ -763,8 +763,7 @@ BOOL LLToolPie::handleMouseUp(S32 x, S32 y, MASK mask) void LLToolPie::stopClickToWalk() { - mPick.mPosGlobal = gAgent.getPositionGlobal(); - handle_go_to(); + handle_go_to(gAgent.getPositionGlobal()); /* Singu TODO: llhudeffectblob if(mAutoPilotDestination) { diff --git a/indra/newview/llviewerdisplayname.cpp b/indra/newview/llviewerdisplayname.cpp index c7f817032..1e559072a 100644 --- a/indra/newview/llviewerdisplayname.cpp +++ b/indra/newview/llviewerdisplayname.cpp @@ -56,25 +56,22 @@ namespace LLViewerDisplayName void doNothing() { } } -class LLSetDisplayNameResponder : public LLHTTPClient::ResponderIgnoreBody +class LLSetDisplayNameResponder final : public LLHTTPClient::ResponderIgnoreBody { LOG_CLASS(LLSetDisplayNameResponder); private: // only care about errors - /*virtual*/ void httpFailure() + void httpFailure() override { - LL_WARNS() << dumpResponse() << LL_ENDL; - LLViewerDisplayName::sSetDisplayNameSignal(false, "", LLSD()); + LLViewerDisplayName::sSetDisplayNameSignal(false, LLStringUtil::null, LLSD()); LLViewerDisplayName::sSetDisplayNameSignal.disconnect_all_slots(); } - /*virtual*/ char const* getName(void) const { return "LLSetDisplayNameResponder"; } + char const* getName() const override { return "LLSetDisplayNameResponder"; } }; void LLViewerDisplayName::set(const std::string& display_name, const set_name_slot_t& slot) { - // TODO: simple validation here - LLViewerRegion* region = gAgent.getRegion(); llassert(region); std::string cap_url = region->getCapability("SetDisplayName"); @@ -93,7 +90,7 @@ void LLViewerDisplayName::set(const std::string& display_name, const set_name_sl // Our display name will be in cache before the viewer's UI is available // to request a change, so we can use direct lookup without callback. LLAvatarName av_name; - if (!LLAvatarNameCache::get( gAgent.getID(), &av_name)) + if (!LLAvatarNameCache::get(gAgent.getID(), &av_name)) { slot(false, "name unavailable", LLSD()); return; @@ -104,8 +101,6 @@ void LLViewerDisplayName::set(const std::string& display_name, const set_name_sl change_array.append(av_name.getDisplayName()); change_array.append(display_name); - LL_INFOS() << "Set name POST to " << cap_url << LL_ENDL; - // Record our caller for when the server sends back a reply sSetDisplayNameSignal.connect(slot); @@ -117,14 +112,14 @@ void LLViewerDisplayName::set(const std::string& display_name, const set_name_sl LLHTTPClient::post(cap_url, body, new LLSetDisplayNameResponder, headers); } -class LLSetDisplayNameReply : public LLHTTPNode +class LLSetDisplayNameReply final : public LLHTTPNode { LOG_CLASS(LLSetDisplayNameReply); public: /*virtual*/ void post( LLHTTPNode::ResponsePtr response, const LLSD& context, - const LLSD& input) const + const LLSD& input) const override { LLSD body = input["body"]; @@ -157,12 +152,12 @@ public: }; -class LLDisplayNameUpdate : public LLHTTPNode +class LLDisplayNameUpdate final : public LLHTTPNode { /*virtual*/ void post( LLHTTPNode::ResponsePtr response, const LLSD& context, - const LLSD& input) const + const LLSD& input) const override { LLSD body = input["body"]; LLUUID agent_id = body["agent_id"]; @@ -195,7 +190,7 @@ class LLDisplayNameUpdate : public LLHTTPNode { LLSD args; args["OLD_NAME"] = old_display_name; - args["SLID"] = av_name.getUserName(); + args["SLID"] = "secondlife:///app/agent/" + agent_id.asString() + "/username"; args["NEW_NAME"] = av_name.getDisplayName(); LLNotificationsUtil::add("DisplayNameUpdate", args); } diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index f5e9c666c..db781e6b5 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -4,7 +4,7 @@ * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. + * Copyright (C) 2014, 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 @@ -84,20 +84,44 @@ static const char * const LOG_INV("Inventory"); static const char * const LOG_LOCAL("InventoryLocalize"); static const char * const LOG_NOTECARD("copy_inventory_from_notecard"); +#if 1 +// *TODO$: LLInventoryCallback should be deprecated to conform to the new boost::bind/coroutine model. +// temp code in transition void doInventoryCb(LLPointer cb, LLUUID id) { if (cb.notNull()) cb->fire(id); } +#endif ///---------------------------------------------------------------------------- /// Helper class to store special inventory item names and their localized values. ///---------------------------------------------------------------------------- -class LLLocalizedInventoryItemsDictionary : public LLSingleton +class LLLocalizedInventoryItemsDictionary final : public LLSingleton { public: std::map mInventoryItemsDict; + /** + * Finds passed name in dictionary and replaces it with found localized value. + * + * @param object_name - string to be localized. + * @return true if passed name was found and localized, false otherwise. + */ + bool localizeInventoryObjectName(std::string& object_name) + { + LL_DEBUGS(LOG_LOCAL) << "Searching for localization: " << object_name << LL_ENDL; + + std::map::const_iterator dictionary_iter = mInventoryItemsDict.find(object_name); + + bool found = dictionary_iter != mInventoryItemsDict.end(); + if(found) + { + object_name = dictionary_iter->second; + LL_DEBUGS(LOG_LOCAL) << "Found, new name is: " << object_name << LL_ENDL; + } + return found; + } LLLocalizedInventoryItemsDictionary() { mInventoryItemsDict["New Shape"] = LLTrans::getString("New Shape"); @@ -196,27 +220,6 @@ public: mInventoryItemsDict["dance7"] = LLTrans::getString("dance7"); mInventoryItemsDict["dance8"] = LLTrans::getString("dance8"); } - - /** - * Finds passed name in dictionary and replaces it with found localized value. - * - * @param object_name - string to be localized. - * @return true if passed name was found and localized, false otherwise. - */ - bool localizeInventoryObjectName(std::string& object_name) - { - LL_DEBUGS(LOG_LOCAL) << "Searching for localization: " << object_name << LL_ENDL; - - std::map::const_iterator dictionary_iter = mInventoryItemsDict.find(object_name); - - bool found = dictionary_iter != mInventoryItemsDict.end(); - if(found) - { - object_name = dictionary_iter->second; - LL_DEBUGS(LOG_LOCAL) << "Found, new name is: " << object_name << LL_ENDL; - } - return found; - } }; @@ -324,6 +327,7 @@ void LLViewerInventoryItem::updateServer(BOOL is_new) const if(!mIsComplete) { // *FIX: deal with this better. + // If we're crashing here then the UI is incorrectly enabled. LL_ERRS(LOG_INV) << "LLViewerInventoryItem::updateServer() - for incomplete item" << LL_ENDL; LLNotificationsUtil::add("IncompleteInventoryItem"); @@ -455,7 +459,7 @@ void LLViewerInventoryItem::setTransactionID(const LLTransactionID& transaction_ { mTransactionID = transaction_id; } -// virtual + void LLViewerInventoryItem::packMessage(LLMessageSystem* msg) const { msg->addUUIDFast(_PREHASH_ItemID, mUUID); @@ -474,6 +478,7 @@ void LLViewerInventoryItem::packMessage(LLMessageSystem* msg) const U32 crc = getCRC32(); msg->addU32Fast(_PREHASH_CRC, crc); } + // virtual BOOL LLViewerInventoryItem::importFile(LLFILE* fp) { @@ -621,7 +626,7 @@ void LLViewerInventoryCategory::updateServer(BOOL is_new) const if (AISAPI::isAvailable()) { LLSD new_llsd = asLLSD(); - AISAPI::completion_t cr = boost::bind(&doInventoryCb, (LLPointer)NULL, _1); + AISAPI::completion_t cr = boost::bind(&doInventoryCb, LLPointer(NULL), _1); AISAPI::UpdateCategory(getUUID(), new_llsd, cr); } else @@ -833,7 +838,7 @@ bool LLViewerInventoryCategory::acceptItem(LLInventoryItem* inv_item) LLInventoryModel::item_array_t* item_array; gInventory.getDirectDescendentsOf(getUUID(),cat_array,item_array); // Destination stock folder must be empty OR types of incoming and existing items must be identical and have the same permissions - accept = (!item_array->size() || + accept = (item_array->empty() || ((item_array->at(0)->getInventoryType() == inv_item->getInventoryType()) && (item_array->at(0)->getPermissions().getMaskNextOwner() == inv_item->getPermissions().getMaskNextOwner()))); } @@ -981,10 +986,10 @@ void LLInventoryCallbackManager::destroyClass() { if (sInstance) { - for (callback_map_t::iterator it = sInstance->mMap.begin(), end_it = sInstance->mMap.end(); it != end_it; ++it) + for (auto& it : sInstance->mMap) { // drop LLPointer reference to callback - it->second = NULL; + it.second = NULL; } sInstance->mMap.clear(); } @@ -1020,7 +1025,7 @@ void LLInventoryCallbackManager::fire(U32 callback_id, const LLUUID& item_id) } //void rez_attachment_cb(const LLUUID& inv_item, LLViewerJointAttachment *attachmentp) -// [SL:KB] - Patch: Appearance-DnDWear | Checked: 2010-09-28 (Catznip-3.0.0a) | Added: Catznip-2.2.0a +// [SL:KB] - Patch: Appearance-DnDWear | Checked: 2010-09-28 (Catznip-3.4) void rez_attachment_cb(const LLUUID& inv_item, LLViewerJointAttachment *attachmentp, bool replace) // [/SL:KB] { @@ -1107,6 +1112,7 @@ void create_gesture_cb(const LLUUID& inv_item) } } + void create_notecard_cb(const LLUUID& inv_item) { if (!inv_item.isNull()) @@ -1173,10 +1179,10 @@ void create_inventory_item(const LLUUID& agent_id, const LLUUID& session_id, void create_inventory_callingcard(const LLUUID& avatar_id, const LLUUID& parent /*= LLUUID::null*/, LLPointer cb/*=NULL*/) { std::string item_desc = avatar_id.asString(); - std::string item_name; - gCacheName->getFullName(avatar_id, item_name); + LLAvatarName av_name; + LLAvatarNameCache::get(avatar_id, &av_name); create_inventory_item(gAgent.getID(), gAgent.getSessionID(), - parent, LLTransactionID::tnull, item_name, item_desc, LLAssetType::AT_CALLINGCARD, + parent, LLTransactionID::tnull, av_name.getLegacyName(), item_desc, LLAssetType::AT_CALLINGCARD, LLInventoryType::IT_CALLINGCARD, NOT_WEARABLE, PERM_MOVE | PERM_TRANSFER, cb); } @@ -1432,11 +1438,6 @@ void update_inventory_item( const LLSD& updates, LLPointer cb) { - //Singu Note: - // There was some rlva-specific code here, however it adversely affected serverside - // baking when using AISv3. Its omission looks likeley to be inconsequental, but if that's incorrect - // any bugs introduced by its removal are minor compared to non-functional serverside baking. - if (AISAPI::isAvailable()) { AISAPI::completion_t cr = boost::bind(&doInventoryCb, cb, _1); @@ -1466,7 +1467,6 @@ void update_inventory_item( LLInventoryModel::LLCategoryUpdate up(new_item->getParentUUID(), 0); gInventory.accountForUpdate(up); gInventory.updateItem(new_item); - if (cb) { cb->fire(item_id); @@ -1525,11 +1525,9 @@ void remove_inventory_items( LLPointer cb ) { - for (LLInventoryObject::object_list_t::iterator it = items_to_kill.begin(); - it != items_to_kill.end(); - ++it) + for (auto& it : items_to_kill) { - remove_inventory_item(*it, cb); + remove_inventory_item(it, cb); } } @@ -1603,7 +1601,7 @@ public: mCB(cb) { } - /* virtual */ void fire(const LLUUID& item_id) {} + /* virtual */ void fire(const LLUUID& item_id) override {} ~LLRemoveCategoryOnDestroy() { LLInventoryModel::EHasChildren children = gInventory.categoryHasChildren(mID); @@ -1629,6 +1627,10 @@ void remove_inventory_category( LLPointer obj = gInventory.getCategory(cat_id); if(obj) { + if (!gInventory.isCategoryComplete(cat_id)) + { + LL_WARNS() << "Removing (purging) incomplete category " << obj->getName() << LL_ENDL; + } if(LLFolderType::lookupIsProtectedType(obj->getPreferredType())) { LLNotificationsUtil::add("CannotRemoveProtectedCategories"); @@ -1849,9 +1851,9 @@ void create_new_item(const std::string& name, LLViewerAssetType::generateDescriptionFor(asset_type, desc); next_owner_perm = (next_owner_perm) ? next_owner_perm : PERM_MOVE | PERM_TRANSFER; - LLPointer cb = NULL; + LLPointer cb = nullptr; - switch(inv_type) + switch (inv_type) { case LLInventoryType::IT_LSL: { @@ -2003,9 +2005,9 @@ void remove_folder_contents(const LLUUID& category, bool keep_outfit_links, LLInventoryModel::item_array_t items; gInventory.collectDescendents(category, cats, items, LLInventoryModel::EXCLUDE_TRASH); - for (U32 i = 0; i < items.size(); ++i) + for (auto& i : items) { - LLViewerInventoryItem *item = items.at(i); + LLViewerInventoryItem *item = i; if (keep_outfit_links && (item->getActualType() == LLAssetType::AT_LINK_FOLDER)) continue; if (item->getIsLinkType()) @@ -2084,7 +2086,7 @@ const std::string NEW_GESTURE_NAME = "New Gesture"; // *TODO:Translate? (probabl } else { - LL_WARNS() << "Can't create unrecognized type " << type_name << LL_ENDL; + LL_WARNS(LOG_INV) << "Can't create unrecognized type " << type_name << LL_ENDL; } } root->setNeedsAutoRename(TRUE); @@ -2371,9 +2373,9 @@ PermissionMask LLViewerInventoryItem::getPermissionMask() const //---------- -void LLViewerInventoryItem::onCallingCardNameLookup(const LLUUID& id, const std::string& name, bool is_group) +void LLViewerInventoryItem::onCallingCardNameLookup(const LLUUID& id, const LLAvatarName& name) { - rename(name); + rename(name.getLegacyName()); gInventory.addChangedMask(LLInventoryObserver::LABEL, getUUID()); gInventory.notifyObservers(); } @@ -2382,9 +2384,10 @@ class LLRegenerateLinkCollector : public LLInventoryCollectFunctor { public: LLRegenerateLinkCollector(const LLViewerInventoryItem *target_item) : mTargetItem(target_item) {} - virtual ~LLRegenerateLinkCollector() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item) + virtual ~LLRegenerateLinkCollector() = default; + + bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item) override { if (item) { @@ -2412,11 +2415,8 @@ LLUUID find_possible_item_for_regeneration(const LLViewerInventoryItem *target_i items, LLInventoryModel::EXCLUDE_TRASH, candidate_matches); - for (LLViewerInventoryItem::item_array_t::const_iterator item_iter = items.begin(); - item_iter != items.end(); - ++item_iter) + for (const LLViewerInventoryItem* item : items) { - const LLViewerInventoryItem *item = (*item_iter); if(item) return item->getUUID(); } @@ -2438,11 +2438,9 @@ BOOL LLViewerInventoryItem::regenerateLink() items, LLInventoryModel::EXCLUDE_TRASH, asset_id_matches); - for (LLViewerInventoryItem::item_array_t::iterator item_iter = items.begin(); - item_iter != items.end(); - item_iter++) + for (auto& item_iter : items) { - LLViewerInventoryItem *item = (*item_iter); + LLViewerInventoryItem *item = item_iter; item->setAssetUUID(target_item_id); item->updateServer(FALSE); gInventory.addChangedMask(LLInventoryObserver::REBUILD, item->getUUID()); diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h index 8825b0417..e24beb89a 100644 --- a/indra/newview/llviewerinventory.h +++ b/indra/newview/llviewerinventory.h @@ -42,6 +42,7 @@ class LLFolderView; class LLFolderBridge; class LLViewerInventoryCategory; +class LLAvatarName; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLViewerInventoryItem @@ -50,7 +51,7 @@ class LLViewerInventoryCategory; // their inventory. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLViewerInventoryItem : public LLInventoryItem, public boost::signals2::trackable +class LLViewerInventoryItem final : public LLInventoryItem, public boost::signals2::trackable { public: typedef std::vector > item_array_t; @@ -59,24 +60,24 @@ protected: ~LLViewerInventoryItem( void ); // ref counted public: - virtual LLAssetType::EType getType() const; - virtual const LLUUID& getAssetUUID() const; + LLAssetType::EType getType() const override; + const LLUUID& getAssetUUID() const override; virtual const LLUUID& getProtectedAssetUUID() const; // returns LLUUID::null if current agent does not have permission to expose this asset's UUID to the user - virtual const std::string& getName() const; + const std::string& getName() const override; virtual S32 getSortField() const; //virtual void setSortField(S32 sortField); virtual void getSLURL(); //Caches SLURL for landmark. //*TODO: Find a better way to do it and remove this method from here. - virtual const LLPermissions& getPermissions() const; + const LLPermissions& getPermissions() const override; virtual const bool getIsFullPerm() const; // 'fullperm' in the popular sense: modify-ok & copy-ok & transfer-ok, no special god rules applied - virtual const LLUUID& getCreatorUUID() const; - virtual const std::string& getDescription() const; - virtual const LLSaleInfo& getSaleInfo() const; - virtual LLInventoryType::EType getInventoryType() const; + const LLUUID& getCreatorUUID() const override; + const std::string& getDescription() const override; + const LLSaleInfo& getSaleInfo() const override; + LLInventoryType::EType getInventoryType() const override; virtual bool isWearableType() const; virtual LLWearableType::EType getWearableType() const; - virtual U32 getFlags() const; - virtual time_t getCreationDate() const; - virtual U32 getCRC32() const; // really more of a checksum. + U32 getFlags() const override; + time_t getCreationDate() const override; + U32 getCRC32() const override; // really more of a checksum. static BOOL extractSortFieldAndDisplayName(const std::string& name, S32* sortField, std::string* displayName); @@ -112,7 +113,7 @@ public: LLViewerInventoryItem(const LLInventoryItem* other); void copyViewerItem(const LLViewerInventoryItem* other); - /*virtual*/ void copyItem(const LLInventoryItem* other); + /*virtual*/ void copyItem(const LLInventoryItem* other) override; // construct a new clone of this item - it creates a new viewer // inventory item using the copy constructor, and returns it. @@ -120,15 +121,15 @@ public: void cloneViewerItem(LLPointer& newitem) const; // virtual methods - virtual void updateParentOnServer(BOOL restamp) const; - virtual void updateServer(BOOL is_new) const; + void updateParentOnServer(BOOL restamp) const override; + void updateServer(BOOL is_new) const override; void fetchFromServer(void) const; - virtual void packMessage(LLMessageSystem* msg) const; - virtual BOOL unpackMessage(LLMessageSystem* msg, const char* block, S32 block_num = 0); + void packMessage(LLMessageSystem* msg) const override; + BOOL unpackMessage(LLMessageSystem* msg, const char* block, S32 block_num = 0) override; virtual BOOL unpackMessage(const LLSD& item); - virtual BOOL importFile(LLFILE* fp); - virtual BOOL importLegacyStream(std::istream& input_stream); + BOOL importFile(LLFILE* fp) override; + BOOL importLegacyStream(std::istream& input_stream) override; // file handling on the viewer. These are not meant for anything // other than cacheing. @@ -160,7 +161,7 @@ public: PermissionMask getPermissionMask() const; // callback - void onCallingCardNameLookup(const LLUUID& id, const std::string& name, bool is_group); + void onCallingCardNameLookup(const LLUUID& id, const LLAvatarName& name); // If this is a broken link, try to fix it and any other identical link. BOOL regenerateLink(); @@ -184,7 +185,7 @@ public: // new ones as needed. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLViewerInventoryCategory : public LLInventoryCategory +class LLViewerInventoryCategory final : public LLInventoryCategory { public: typedef std::vector > cat_array_t; @@ -204,10 +205,10 @@ public: LLViewerInventoryCategory(const LLViewerInventoryCategory* other); void copyViewerCategory(const LLViewerInventoryCategory* other); - virtual void updateParentOnServer(BOOL restamp_children) const; - virtual void updateServer(BOOL is_new) const; + void updateParentOnServer(BOOL restamp_children) const override; + void updateServer(BOOL is_new) const override; - virtual void packMessage(LLMessageSystem* msg) const; + void packMessage(LLMessageSystem* msg) const override; const LLUUID& getOwnerID() const { return mOwnerID; } @@ -234,7 +235,7 @@ public: bool importFileLocal(LLFILE* fp); void determineFolderType(); void changeType(LLFolderType::EType new_folder_type); - virtual void unpackMessage(LLMessageSystem* msg, const char* block, S32 block_num = 0); + void unpackMessage(LLMessageSystem* msg, const char* block, S32 block_num = 0) override; virtual BOOL unpackMessage(const LLSD& category); // returns true if the category object will accept the incoming item @@ -259,37 +260,37 @@ public: class LLViewerJointAttachment; -//void rez_attachment_cb(const LLUUID& inv_item, LLViewerJointAttachment *attachmentp); -// [SL:KB] - Patch: Appearance-DnDWear | Checked: 2010-09-28 (Catznip-3.0.0a) | Added: Catznip-2.2.0a +// [SL:KB] - Patch: Appearance-DnDWear | Checked: 2010-09-28 (Catznip-3.4) void rez_attachment_cb(const LLUUID& inv_item, LLViewerJointAttachment *attachmentp, bool replace = false); // [/SL:KB] +//void rez_attachment_cb(const LLUUID& inv_item, LLViewerJointAttachment *attachmentp); void activate_gesture_cb(const LLUUID& inv_item); void create_gesture_cb(const LLUUID& inv_item); -class AddFavoriteLandmarkCallback : public LLInventoryCallback +class AddFavoriteLandmarkCallback final : public LLInventoryCallback { public: AddFavoriteLandmarkCallback() : mTargetLandmarkId(LLUUID::null) {} void setTargetLandmarkId(const LLUUID& target_uuid) { mTargetLandmarkId = target_uuid; } private: - void fire(const LLUUID& inv_item); + void fire(const LLUUID& inv_item) override; LLUUID mTargetLandmarkId; }; -typedef boost::function inventory_func_type; -typedef boost::function llsd_func_type; -typedef boost::function nullary_func_type; +typedef std::function inventory_func_type; +typedef std::function llsd_func_type; +typedef std::function nullary_func_type; void no_op_inventory_func(const LLUUID&); // A do-nothing inventory_func void no_op_llsd_func(const LLSD&); // likewise for LLSD void no_op(); // A do-nothing nullary func. // Shim between inventory callback and boost function/callable -class LLBoostFuncInventoryCallback: public LLInventoryCallback +class LLBoostFuncInventoryCallback : public LLInventoryCallback { public: @@ -301,7 +302,7 @@ public: } // virtual - void fire(const LLUUID& item_id) + void fire(const LLUUID& item_id) override { mFireFunc(item_id); } diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 9676acf0c..06047dcf6 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -2347,7 +2347,7 @@ void LLViewerMediaImpl::mouseDoubleClick(S32 x, S32 y, MASK mask, S32 button) } ////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::scrollWheel(S32 x, S32 y, MASK mask) +void LLViewerMediaImpl::scrollWheel(S32 x, S32 y, S32 scroll_x, S32 scroll_y, MASK mask) { LLPluginClassMedia* mMediaSource = getMediaPlugin(); scaleMouse(&x, &y); @@ -2355,7 +2355,7 @@ void LLViewerMediaImpl::scrollWheel(S32 x, S32 y, MASK mask) mLastMouseY = y; if (mMediaSource) { - mMediaSource->scrollEvent(x, y, mask); + mMediaSource->scrollEvent(x, y, scroll_x, scroll_y, mask); } } @@ -3529,7 +3529,7 @@ LLViewerMediaImpl::canCut() const //////////////////////////////////////////////////////////////////////////////// // virtual void -LLViewerMediaImpl::copy() +LLViewerMediaImpl::copy() const { LLPluginClassMedia* mMediaSource = getMediaPlugin(); if (mMediaSource) diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h index 14dc08fae..224225498 100644 --- a/indra/newview/llviewermedia.h +++ b/indra/newview/llviewermedia.h @@ -227,8 +227,8 @@ public: void mouseUp(const LLVector2& texture_coords, MASK mask, S32 button = 0); void mouseMove(const LLVector2& texture_coords, MASK mask); void mouseDoubleClick(const LLVector2& texture_coords, MASK mask); - void mouseDoubleClick(S32 x,S32 y, MASK mask, S32 button = 0); - void scrollWheel(S32 x, S32 y, MASK mask); + void mouseDoubleClick(S32 x, S32 y, MASK mask, S32 button = 0); + void scrollWheel(S32 x, S32 y, S32 scroll_x, S32 scroll_y, MASK mask); void mouseCapture(); void navigateBack(); @@ -339,7 +339,7 @@ public: /*virtual*/ void cut() override; /*virtual*/ BOOL canCut() const override; - /*virtual*/ void copy() override; + /*virtual*/ void copy() const override final; /*virtual*/ BOOL canCopy() const override; /*virtual*/ void paste() override; diff --git a/indra/newview/llviewermediafocus.cpp b/indra/newview/llviewermediafocus.cpp index f7f579e94..e3b02acd4 100644 --- a/indra/newview/llviewermediafocus.cpp +++ b/indra/newview/llviewermediafocus.cpp @@ -376,12 +376,7 @@ BOOL LLViewerMediaFocus::handleScrollWheel(S32 x, S32 y, S32 clicks) LLViewerMediaImpl* media_impl = getFocusedMediaImpl(); if(media_impl && media_impl->hasMedia()) { - // the scrollEvent() API's x and y are not the same as handleScrollWheel's x and y. - // The latter is the position of the mouse at the time of the event - // The former is the 'scroll amount' in x and y, respectively. - // All we have for 'scroll amount' here is 'clicks'. - // We're also not passed the keyboard modifier mask, but we can get that from gKeyboard. - media_impl->getMediaPlugin()->scrollEvent(0, clicks, gKeyboard->currentMask(TRUE)); + media_impl->scrollWheel(x, y, 0, clicks, gKeyboard->currentMask(TRUE)); retval = TRUE; } return retval; diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 171abfce2..4fefe7e45 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -37,6 +37,7 @@ #include "lfidbearer.h" #include "llanimationstates.h" // For ANIM_AGENT_AWAY #include "llavatarnamecache.h" // IDEVO +#include "llexperiencecache.h" #include "llinventorypanel.h" #include "llnotifications.h" #include "llnotificationsutil.h" @@ -55,7 +56,6 @@ #include "llagentcamera.h" #include "llappearancemgr.h" #include "llagentwearables.h" - #include "llagentpilot.h" #include "llavatarpropertiesprocessor.h" #include "llcallingcard.h" @@ -74,6 +74,8 @@ #include "llfloatercustomize.h" #include "llfloaterdirectory.h" #include "llfloatereditui.h" +#include "llfloaterexperienceprofile.h" +#include "llfloaterexperiences.h" #include "llfloaterfonttest.h" #include "llfloatergodtools.h" #include "llfloaterhtmlcurrency.h" @@ -94,6 +96,7 @@ #include "llframestats.h" #include "llavataractions.h" #include "llgivemoney.h" +#include "llgroupactions.h" #include "llgroupmgr.h" #include "llhoverview.h" #include "llhudeffecttrail.h" @@ -104,6 +107,7 @@ #include "llmenuoptionpathfindingrebakenavmesh.h" #include "llmutelist.h" #include "llnotify.h" +#include "llpanelexperiences.h" #include "llparcel.h" #include "llregioninfomodel.h" #include "llselectmgr.h" @@ -134,6 +138,7 @@ #include "llfloaternotificationsconsole.h" // +#include "jcfloaterareasearch.h" #include "lltexteditor.h" // Initialize the text editor menu listeners in here #include "llfloatermessagelog.h" #include "shfloatermediaticker.h" @@ -204,16 +209,16 @@ extern AIHTTPView* gHttpView; // Globals // -LLMenuBarGL *gMenuBarView = NULL; -LLViewerMenuHolderGL *gMenuHolder = NULL; -LLMenuBarGL *gLoginMenuBarView = NULL; +LLMenuBarGL *gMenuBarView = nullptr; +LLViewerMenuHolderGL *gMenuHolder = nullptr; +LLMenuBarGL *gLoginMenuBarView = nullptr; // Pie menus -LLContextMenu *gPieSelf = NULL; -LLContextMenu *gPieAvatar = NULL; -LLContextMenu *gPieObject = NULL; -LLContextMenu *gPieAttachment = NULL; -LLContextMenu *gPieLand = NULL; +LLContextMenu *gPieSelf = nullptr; +LLContextMenu *gPieAvatar = nullptr; +LLContextMenu *gPieObject = nullptr; +LLContextMenu *gPieAttachment = nullptr; +LLContextMenu *gPieLand = nullptr; // local constants const std::string CLIENT_MENU_NAME("Advanced"); @@ -221,20 +226,20 @@ const std::string SERVER_MENU_NAME("Admin"); const std::string SAVE_INTO_TASK_INVENTORY("Save Object Back to Object Contents"); -LLMenuGL* gAttachSubMenu = NULL; -LLMenuGL* gDetachSubMenu = NULL; -LLMenuGL* gTakeOffClothes = NULL; -LLMenuGL* gMeshesAndMorphsMenu = NULL; -LLContextMenu* gPieRate = NULL; -LLContextMenu* gAttachScreenPieMenu = NULL; -LLContextMenu* gAttachPieMenu = NULL; -LLContextMenu* gAttachPieMenu2 = NULL; -LLContextMenu* gDetachPieMenu = NULL; -LLContextMenu* gDetachPieMenu2 = NULL; -LLContextMenu* gDetachScreenPieMenu = NULL; +LLMenuGL* gAttachSubMenu = nullptr; +LLMenuGL* gDetachSubMenu = nullptr; +LLMenuGL* gTakeOffClothes = nullptr; +LLMenuGL* gMeshesAndMorphsMenu = nullptr; +LLContextMenu* gPieRate = nullptr; +LLContextMenu* gAttachScreenPieMenu = nullptr; +LLContextMenu* gAttachPieMenu = nullptr; +LLContextMenu* gAttachPieMenu2 = nullptr; +LLContextMenu* gDetachPieMenu = nullptr; +LLContextMenu* gDetachPieMenu2 = nullptr; +LLContextMenu* gDetachScreenPieMenu = nullptr; -LLMenuItemCallGL* gAFKMenu = NULL; -LLMenuItemCallGL* gBusyMenu = NULL; +LLMenuItemCallGL* gAFKMenu = nullptr; +LLMenuItemCallGL* gBusyMenu = nullptr; typedef LLMemberListener view_listener_t; @@ -352,7 +357,7 @@ void handle_pose_stand_stop(void*) } void cleanup_pose_stand() { - handle_pose_stand_stop(NULL); + handle_pose_stand_stop(nullptr); } BOOL handle_check_pose(void* userdata) { return current_pose.notNull(); } @@ -475,15 +480,15 @@ void reset_vertex_buffers(void *user_data) gPipeline.resetVertexBuffers(); } -class LLMenuParcelObserver : public LLParcelObserver +class LLMenuParcelObserver final : public LLParcelObserver { public: LLMenuParcelObserver(); ~LLMenuParcelObserver(); - virtual void changed(); + void changed() override; }; -static LLMenuParcelObserver* gMenuParcelObserver = NULL; +static LLMenuParcelObserver* gMenuParcelObserver = nullptr; LLMenuParcelObserver::LLMenuParcelObserver() { @@ -497,9 +502,9 @@ LLMenuParcelObserver::~LLMenuParcelObserver() void LLMenuParcelObserver::changed() { - gMenuHolder->childSetEnabled("Land Buy Pass", LLPanelLandGeneral::enableBuyPass(NULL)); + gMenuHolder->childSetEnabled("Land Buy Pass", LLPanelLandGeneral::enableBuyPass(nullptr)); - BOOL buyable = enable_buy_land(NULL); + BOOL buyable = enable_buy_land(nullptr); gMenuHolder->childSetEnabled("Land Buy", buyable); gMenuHolder->childSetEnabled("Buy Land...", buyable); } @@ -598,21 +603,26 @@ void set_merchant_SLM_menu() gToolBar->getChild("marketplace_listings_btn")->setEnabled(true); } -void check_merchant_status() +void check_merchant_status(bool force) { if (!gSavedSettings.getBOOL("InventoryOutboxDisplayBoth")) { - // Reset the SLM status: we actually want to check again, that's the point of calling check_merchant_status() - LLMarketplaceData::instance().setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_NOT_INITIALIZED); - + if (force) + { + // Reset the SLM status: we actually want to check again, that's the point of calling check_merchant_status() + LLMarketplaceData::instance().setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_NOT_INITIALIZED); + } // Hide SLM related menu item gMenuHolder->getChild("MarketplaceListings")->setVisible(FALSE); // Also disable the toolbar button for Marketplace Listings gToolBar->getChild("marketplace_listings_btn")->setEnabled(false); - // Launch an SLM test connection to get the merchant status - LLMarketplaceData::instance().initializeSLM(boost::bind(&set_merchant_SLM_menu)); + if (!gAgent.getRegionCapability("DirectDelivery").empty()) + { + // Launch an SLM test connection to get the merchant status + LLMarketplaceData::instance().initializeSLM(boost::bind(&set_merchant_SLM_menu)); + } } } @@ -691,13 +701,13 @@ void init_menus() /*LLMenuGL* sub = new LLMenuGL("Pose Stand..."); menu->addChild(sub); - sub->addChild(new LLMenuItemCallGL( "Legs Together Arms Out", &handle_pose_stand_ltao, NULL)); - sub->addChild(new LLMenuItemCallGL( "Legs Together Arms Half", &handle_pose_stand_ltah, NULL)); - sub->addChild(new LLMenuItemCallGL( "Legs Together Arms Down", &handle_pose_stand_ltad, NULL)); - sub->addChild(new LLMenuItemCallGL( "Legs Out Arms Up", &handle_pose_stand_loau, NULL)); - sub->addChild(new LLMenuItemCallGL( "Legs Out Arms Out", &handle_pose_stand_loao, NULL)); - sub->addChild(new LLMenuItemCallGL( "Legs Half Arms Out", &handle_pose_stand_lhao, NULL)); - sub->addChild(new LLMenuItemCallGL( "Stop Pose Stand", &handle_pose_stand_stop, NULL)); + sub->addChild(new LLMenuItemCallGL( "Legs Together Arms Out", &handle_pose_stand_ltao, nullptr)); + sub->addChild(new LLMenuItemCallGL( "Legs Together Arms Half", &handle_pose_stand_ltah, nullptr)); + sub->addChild(new LLMenuItemCallGL( "Legs Together Arms Down", &handle_pose_stand_ltad, nullptr)); + sub->addChild(new LLMenuItemCallGL( "Legs Out Arms Up", &handle_pose_stand_loau, nullptr)); + sub->addChild(new LLMenuItemCallGL( "Legs Out Arms Out", &handle_pose_stand_loao, nullptr)); + sub->addChild(new LLMenuItemCallGL( "Legs Half Arms Out", &handle_pose_stand_lhao, nullptr)); + sub->addChild(new LLMenuItemCallGL( "Stop Pose Stand", &handle_pose_stand_stop, nullptr)); // ------------------------------------------------------*/ // TomY TODO convert these two @@ -728,9 +738,9 @@ void init_menus() menu = new LLMenuGL(CLIENT_MENU_NAME); menu->setCanTearOff(FALSE); - menu->addChild(new LLMenuItemCallGL("Debug Settings...", handle_singleton_toggle, NULL, NULL)); + menu->addChild(new LLMenuItemCallGL("Debug Settings...", handle_singleton_toggle, nullptr, nullptr)); // Debugging view for unified notifications: CTRL-SHIFT-5 - menu->addChild(new LLMenuItemCallGL("Notifications Console...", handle_show_notifications_console, NULL, NULL, '5', MASK_CONTROL|MASK_SHIFT)); + menu->addChild(new LLMenuItemCallGL("Notifications Console...", handle_show_notifications_console, nullptr, nullptr, '5', MASK_CONTROL|MASK_SHIFT)); menu->addChild(new LLMenuItemCallGL("Load from XML...", handle_load_from_xml)); gLoginMenuBarView->addChild(menu); menu->updateParent(LLMenuGL::sMenuContainer); @@ -748,8 +758,7 @@ void init_menus() gMenuHolder->addChild(gLoginMenuBarView); // Singu Note: Initialize common ScrollListMenus here - LFIDBearer::addCommonMenu(LLUICtrlFactory::getInstance()->buildMenu("menu_avs_list.xml", gMenuHolder)); // 0 - //LFIDBearer::addCommonMenu(LLUICtrlFactory::getInstance()->buildMenu("menu_groups_list.xml")); // 1 // Singu TODO + LFIDBearer::buildMenus(); LLView* ins = gMenuBarView->getChildView("insert_world", true, false); ins->setVisible(false); @@ -770,7 +779,7 @@ void init_menus() void init_client_menu(LLMenuGL* menu) { - LLMenuGL* sub_menu = NULL; + LLMenuGL* sub_menu = nullptr; { @@ -780,20 +789,20 @@ void init_client_menu(LLMenuGL* menu) menu->addChild(sub); sub->addChild(new LLMenuItemCheckGL("Frame Console", &toggle_visibility, - NULL, + nullptr, &get_visibility, (void*)gDebugView->mFrameStatView, '2', MASK_CONTROL|MASK_SHIFT ) ); sub->addChild(new LLMenuItemCheckGL("Texture Console", &toggle_visibility, - NULL, + nullptr, &get_visibility, (void*)gTextureView, '3', MASK_CONTROL|MASK_SHIFT ) ); LLView* debugview = gDebugView->mDebugConsolep; sub->addChild(new LLMenuItemCheckGL("Debug Console", &toggle_visibility, - NULL, + nullptr, &get_visibility, debugview, '4', MASK_CONTROL|MASK_SHIFT ) ); @@ -802,13 +811,13 @@ void init_client_menu(LLMenuGL* menu) { sub->addChild(new LLMenuItemCheckGL("Texture Size Console", &toggle_visibility, - NULL, + nullptr, &get_visibility, (void*)gTextureSizeView, '5', MASK_CONTROL|MASK_SHIFT ) ); sub->addChild(new LLMenuItemCheckGL("Texture Category Console", &toggle_visibility, - NULL, + nullptr, &get_visibility, (void*)gTextureCategoryView, '6', MASK_CONTROL|MASK_SHIFT ) ); @@ -816,16 +825,16 @@ void init_client_menu(LLMenuGL* menu) sub->addChild(new LLMenuItemCheckGL("HTTP Console", &toggle_visibility, - NULL, + nullptr, &get_visibility, (void*)gHttpView, '7', MASK_CONTROL|MASK_SHIFT ) ); - sub->addChild(new LLMenuItemCheckGL("Region Debug Console", handle_singleton_toggle, NULL, handle_singleton_check,NULL,'`', MASK_CONTROL|MASK_SHIFT)); + sub->addChild(new LLMenuItemCheckGL("Region Debug Console", handle_singleton_toggle, nullptr, handle_singleton_check,nullptr,'`', MASK_CONTROL|MASK_SHIFT)); sub->addChild(new LLMenuItemCheckGL("Fast Timers", &toggle_visibility, - NULL, + nullptr, &get_visibility, (void*)gDebugView->mFastTimerView, '9', MASK_CONTROL|MASK_SHIFT ) ); @@ -834,25 +843,25 @@ void init_client_menu(LLMenuGL* menu) // Debugging view for unified notifications sub->addChild(new LLMenuItemCallGL("Notifications Console...", - &handle_show_notifications_console, NULL, NULL, '5', MASK_CONTROL|MASK_SHIFT )); + &handle_show_notifications_console, nullptr, nullptr, '5', MASK_CONTROL|MASK_SHIFT )); sub->addSeparator(); sub->addChild(new LLMenuItemCallGL("Region Info to Debug Console", - &handle_region_dump_settings, NULL)); + &handle_region_dump_settings, nullptr)); sub->addChild(new LLMenuItemCallGL("Group Info to Debug Console", - &handle_dump_group_info, NULL, NULL)); + &handle_dump_group_info, nullptr, nullptr)); sub->addChild(new LLMenuItemCallGL("Capabilities Info to Debug Console", - &handle_dump_capabilities_info, NULL, NULL)); + &handle_dump_capabilities_info, nullptr, nullptr)); sub->createJumpKeys(); } // neither of these works particularly well at the moment /*menu->addChild(new LLMenuItemCallGL( "Reload UI XML", &reload_ui, - NULL, NULL) );*/ + nullptr, nullptr) );*/ /*menu->addChild(new LLMenuItemCallGL("Reload settings/colors", - &handle_reload_settings, NULL, NULL));*/ + &handle_reload_settings, nullptr, nullptr));*/ menu->addChild(new LLMenuItemCallGL("Reload personal setting overrides", &reload_personal_settings_overrides)); @@ -861,7 +870,7 @@ void init_client_menu(LLMenuGL* menu) sub_menu->setCanTearOff(TRUE); sub_menu->addChild(new LLMenuItemCheckGL("Velocity", &toggle_visibility, - NULL, + nullptr, &get_visibility, (void*)gVelocityBar)); @@ -876,25 +885,25 @@ void init_client_menu(LLMenuGL* menu) menu->addChild(new LLMenuItemCheckGL( "High-res Snapshot", &menu_toggle_control, - NULL, + nullptr, &menu_check_control, (void*)"HighResSnapshot")); menu->addChild(new LLMenuItemCheckGL( "Quiet Snapshots to Disk", &menu_toggle_control, - NULL, + nullptr, &menu_check_control, (void*)"QuietSnapshotsToDisk")); menu->addChild(new LLMenuItemCheckGL("Show Mouselook Crosshairs", &menu_toggle_control, - NULL, + nullptr, &menu_check_control, (void*)"ShowCrosshairs")); menu->addChild(new LLMenuItemCheckGL("Debug Permissions", &menu_toggle_control, - NULL, + nullptr, &menu_check_control, (void*)"DebugPermissions")); @@ -906,7 +915,7 @@ void init_client_menu(LLMenuGL* menu) { menu->addChild(new LLMenuItemCheckGL("Hacked Godmode", &handle_toggle_hacked_godmode, - NULL, + nullptr, &check_toggle_hacked_godmode, (void*)"HackedGodmode")); } @@ -915,7 +924,7 @@ void init_client_menu(LLMenuGL* menu) menu->addChild(new LLMenuItemCallGL("Clear Group Cache", LLGroupMgr::debugClearAllGroups)); - menu->addChild(new LLMenuItemCheckGL("Use Web Map Tiles", menu_toggle_control, NULL, menu_check_control, (void*)"UseWebMapTiles")); + menu->addChild(new LLMenuItemCheckGL("Use Web Map Tiles", menu_toggle_control, nullptr, menu_check_control, (void*)"UseWebMapTiles")); menu->addSeparator(); @@ -955,67 +964,67 @@ void init_client_menu(LLMenuGL* menu) menu->addChild(sub_menu); { - LLMenuGL* sub = NULL; + LLMenuGL* sub = nullptr; sub = new LLMenuGL("Network"); sub->setCanTearOff(TRUE); - sub->addChild(new LLMenuItemCallGL( "Message Log", &handle_open_message_log, NULL)); + sub->addChild(new LLMenuItemCallGL("Message Log", handle_open_message_log, nullptr)); sub->addChild(new LLMenuItemCallGL("Enable Message Log", - &handle_viewer_enable_message_log, NULL)); + &handle_viewer_enable_message_log, nullptr)); sub->addChild(new LLMenuItemCallGL("Disable Message Log", - &handle_viewer_disable_message_log, NULL)); + &handle_viewer_disable_message_log, nullptr)); sub->addSeparator(); sub->addChild(new LLMenuItemCheckGL("Velocity Interpolate Objects", &velocity_interpolate, - NULL, + nullptr, &menu_check_control, (void*)"VelocityInterpolate")); sub->addChild(new LLMenuItemCheckGL("Ping Interpolate Object Positions", &menu_toggle_control, - NULL, + nullptr, &menu_check_control, (void*)"PingInterpolate")); sub->addSeparator(); sub->addChild(new LLMenuItemCallGL("Drop a Packet", - &drop_packet, NULL, NULL, + &drop_packet, nullptr, nullptr, 'L', MASK_ALT | MASK_CONTROL)); menu->addChild( sub ); sub->createJumpKeys(); } { - LLMenuGL* sub = NULL; + LLMenuGL* sub = nullptr; sub = new LLMenuGL("Recorder"); sub->setCanTearOff(TRUE); - sub->addChild(new LLMenuItemCheckGL("Full Session Logging", &menu_toggle_control, NULL, &menu_check_control, (void*)"StatsSessionTrackFrameStats")); + sub->addChild(new LLMenuItemCheckGL("Full Session Logging", &menu_toggle_control, nullptr, &menu_check_control, (void*)"StatsSessionTrackFrameStats")); - sub->addChild(new LLMenuItemCallGL("Start Logging", &LLFrameStats::startLogging, NULL)); - sub->addChild(new LLMenuItemCallGL("Stop Logging", &LLFrameStats::stopLogging, NULL)); - sub->addChild(new LLMenuItemCallGL("Log 10 Seconds", &LLFrameStats::timedLogging10, NULL)); - sub->addChild(new LLMenuItemCallGL("Log 30 Seconds", &LLFrameStats::timedLogging30, NULL)); - sub->addChild(new LLMenuItemCallGL("Log 60 Seconds", &LLFrameStats::timedLogging60, NULL)); + sub->addChild(new LLMenuItemCallGL("Start Logging", &LLFrameStats::startLogging, nullptr)); + sub->addChild(new LLMenuItemCallGL("Stop Logging", &LLFrameStats::stopLogging, nullptr)); + sub->addChild(new LLMenuItemCallGL("Log 10 Seconds", &LLFrameStats::timedLogging10, nullptr)); + sub->addChild(new LLMenuItemCallGL("Log 30 Seconds", &LLFrameStats::timedLogging30, nullptr)); + sub->addChild(new LLMenuItemCallGL("Log 60 Seconds", &LLFrameStats::timedLogging60, nullptr)); sub->addSeparator(); - sub->addChild(new LLMenuItemCallGL("Start Playback", &LLAgentPilot::startPlayback, NULL)); - sub->addChild(new LLMenuItemCallGL("Stop Playback", &LLAgentPilot::stopPlayback, NULL)); + sub->addChild(new LLMenuItemCallGL("Start Playback", &LLAgentPilot::startPlayback, nullptr)); + sub->addChild(new LLMenuItemCallGL("Stop Playback", &LLAgentPilot::stopPlayback, nullptr)); sub->addChild(new LLMenuItemToggleGL("Loop Playback", &LLAgentPilot::sLoop) ); - sub->addChild(new LLMenuItemCallGL("Start Record", &LLAgentPilot::startRecord, NULL)); - sub->addChild(new LLMenuItemCallGL("Stop Record", &LLAgentPilot::saveRecord, NULL)); + sub->addChild(new LLMenuItemCallGL("Start Record", &LLAgentPilot::startRecord, nullptr)); + sub->addChild(new LLMenuItemCallGL("Stop Record", &LLAgentPilot::saveRecord, nullptr)); menu->addChild( sub ); sub->createJumpKeys(); } { - LLMenuGL* sub = NULL; + LLMenuGL* sub = nullptr; sub = new LLMenuGL("Media"); sub->setCanTearOff(TRUE); sub->addChild(new LLMenuItemCallGL("Reload MIME types", &LLMIMETypes::reload)); - sub->addChild(new LLMenuItemCallGL("Web Browser Test", &handle_web_browser_test, NULL, NULL, KEY_F1)); + sub->addChild(new LLMenuItemCallGL("Web Browser Test", &handle_web_browser_test, nullptr, nullptr, KEY_F1)); menu->addChild( sub ); sub->createJumpKeys(); } @@ -1028,29 +1037,29 @@ void init_client_menu(LLMenuGL* menu) menu->addSeparator(); menu->addChild(new LLMenuItemCallGL("Compress Images...", - &handle_compress_image, NULL, NULL)); + &handle_compress_image, nullptr, nullptr)); menu->addChild(new LLMenuItemCheckGL("Limit Select Distance", &menu_toggle_control, - NULL, + nullptr, &menu_check_control, (void*)"LimitSelectDistance")); menu->addChild(new LLMenuItemCheckGL("Disable Camera Constraints", &menu_toggle_control, - NULL, + nullptr, &menu_check_control, (void*)"DisableCameraConstraints")); menu->addChild(new LLMenuItemCheckGL("Mouse Smoothing", &menu_toggle_control, - NULL, + nullptr, &menu_check_control, (void*) "MouseSmooth")); // Singu Note: When this menu is xml, handle this above, with the other insertion points { - LLMenuItemCallGL* item = new LLMenuItemCallGL("insert_advanced", NULL); + LLMenuItemCallGL* item = new LLMenuItemCallGL("insert_advanced", nullptr); item->setVisible(false); menu->addChild(item); } @@ -1058,22 +1067,22 @@ void init_client_menu(LLMenuGL* menu) menu->addChild(new LLMenuItemCheckGL( "Console Window", &menu_toggle_control, - NULL, + nullptr, &menu_check_control, (void*)"ShowConsoleWindow")); // [RLVa:KB] - Checked: 2009-07-08 (RLVa-1.0.0e) | Modified: RLVa-1.0.0e | OK if (gSavedSettings.controlExists(RLV_SETTING_MAIN)) - menu->addChild(new LLMenuItemCheckGL("RestrainedLove API", &rlvMenuToggleEnabled, NULL, &rlvMenuCheckEnabled, NULL)); + menu->addChild(new LLMenuItemCheckGL("RestrainedLove API", &rlvMenuToggleEnabled, nullptr, &rlvMenuCheckEnabled, nullptr)); // [/RLVa:KB] if(gSavedSettings.getBOOL("QAMode")) { - LLMenuGL* sub = NULL; + LLMenuGL* sub = nullptr; sub = new LLMenuGL("Debugging"); sub->setCanTearOff(TRUE); #if LL_WINDOWS - sub->addChild(new LLMenuItemCallGL("Force Breakpoint", &force_error_breakpoint, NULL, NULL, 'B', MASK_CONTROL | MASK_ALT)); + sub->addChild(new LLMenuItemCallGL("Force Breakpoint", &force_error_breakpoint, nullptr, nullptr, 'B', MASK_CONTROL | MASK_ALT)); #endif sub->addChild(new LLMenuItemCallGL("Force LLError And Crash", &force_error_llerror)); sub->addChild(new LLMenuItemCallGL("Force Bad Memory Access", &force_error_bad_memory_access)); @@ -1087,18 +1096,18 @@ void init_client_menu(LLMenuGL* menu) menu->addChild(new LLMenuItemCheckGL( "Output Debug Minidump", &menu_toggle_control, - NULL, + nullptr, &menu_check_control, (void*)"SaveMinidump")); - menu->addChild(new LLMenuItemCallGL("Debug Settings...", handle_singleton_toggle, NULL, NULL)); - menu->addChild(new LLMenuItemCheckGL("View Admin Options", &handle_admin_override_toggle, NULL, &check_admin_override, NULL, 'V', MASK_CONTROL | MASK_ALT)); + menu->addChild(new LLMenuItemCallGL("Debug Settings...", handle_singleton_toggle, nullptr, nullptr)); + menu->addChild(new LLMenuItemCheckGL("View Admin Options", &handle_admin_override_toggle, nullptr, &check_admin_override, nullptr, 'V', MASK_CONTROL | MASK_ALT)); menu->addChild(new LLMenuItemCallGL("Request Admin Status", - &handle_god_mode, NULL, NULL, 'G', MASK_ALT | MASK_CONTROL)); + &handle_god_mode, nullptr, nullptr, 'G', MASK_ALT | MASK_CONTROL)); menu->addChild(new LLMenuItemCallGL("Leave Admin Status", - &handle_leave_god_mode, NULL, NULL, 'G', MASK_ALT | MASK_SHIFT | MASK_CONTROL)); + &handle_leave_god_mode, nullptr, nullptr, 'G', MASK_ALT | MASK_SHIFT | MASK_CONTROL)); menu->createJumpKeys(); } @@ -1108,25 +1117,25 @@ void init_debug_world_menu(LLMenuGL* menu) /* REMOVE mouse move sun from menu options menu->addChild(new LLMenuItemCheckGL("Mouse Moves Sun", &menu_toggle_control, - NULL, + nullptr, &menu_check_control, (void*)"MouseSun", 'M', MASK_CONTROL|MASK_ALT)); */ menu->addChild(new LLMenuItemCheckGL("Sim Sun Override", &menu_toggle_control, - NULL, + nullptr, &menu_check_control, (void*)"SkyOverrideSimSunPosition")); menu->addChild(new LLMenuItemCallGL("Dump Scripted Camera", - &handle_dump_followcam, NULL, NULL)); + &handle_dump_followcam, nullptr, nullptr)); menu->addChild(new LLMenuItemCheckGL("Fixed Weather", &menu_toggle_control, - NULL, + nullptr, &menu_check_control, (void*)"FixedWeather")); menu->addChild(new LLMenuItemCallGL("Dump Region Object Cache", - &handle_dump_region_object_cache, NULL, NULL)); + &handle_dump_region_object_cache, nullptr, nullptr)); menu->createJumpKeys(); } @@ -1152,9 +1161,9 @@ static void handle_export_menus_to_xml_continued(AIFilePicker* filepicker) void init_debug_ui_menu(LLMenuGL* menu) { - menu->addChild(new LLMenuItemCheckGL("Rotate Mini-Map", menu_toggle_control, NULL, menu_check_control, (void*)"MiniMapRotate")); - menu->addChild(new LLMenuItemCheckGL("Use default system color picker", menu_toggle_control, NULL, menu_check_control, (void*)"UseDefaultColorPicker")); - menu->addChild(new LLMenuItemCheckGL("Show search panel in overlay bar", menu_toggle_control, NULL, menu_check_control, (void*)"ShowSearchBar")); + menu->addChild(new LLMenuItemCheckGL("Rotate Mini-Map", menu_toggle_control, nullptr, menu_check_control, (void*)"MiniMapRotate")); + menu->addChild(new LLMenuItemCheckGL("Use default system color picker", menu_toggle_control, nullptr, menu_check_control, (void*)"UseDefaultColorPicker")); + menu->addChild(new LLMenuItemCheckGL("Show search panel in overlay bar", menu_toggle_control, nullptr, menu_check_control, (void*)"ShowSearchBar")); menu->addSeparator(); // commented out until work is complete: DEV-32268 @@ -1162,33 +1171,33 @@ void init_debug_ui_menu(LLMenuGL* menu) menu->addChild(new LLMenuItemCallGL("Editable UI", &edit_ui)); menu->addChild(new LLMenuItemCallGL( "Dump SelectMgr", &dump_select_mgr)); menu->addChild(new LLMenuItemCallGL( "Dump Inventory", &dump_inventory)); - menu->addChild(new LLMenuItemCallGL( "Dump Focus Holder", &handle_dump_focus, NULL, NULL, 'F', MASK_ALT | MASK_CONTROL)); - menu->addChild(new LLMenuItemCallGL( "Print Selected Object Info", &print_object_info, NULL, NULL, 'P', MASK_CONTROL|MASK_SHIFT )); - menu->addChild(new LLMenuItemCallGL( "Print Agent Info", &print_agent_nvpairs, NULL, NULL, 'P', MASK_SHIFT )); - menu->addChild(new LLMenuItemCallGL( "Memory Stats", &output_statistics, NULL, NULL, 'M', MASK_SHIFT | MASK_ALT | MASK_CONTROL)); + menu->addChild(new LLMenuItemCallGL( "Dump Focus Holder", &handle_dump_focus, nullptr, nullptr, 'F', MASK_ALT | MASK_CONTROL)); + menu->addChild(new LLMenuItemCallGL( "Print Selected Object Info", &print_object_info, nullptr, nullptr, 'P', MASK_CONTROL|MASK_SHIFT )); + menu->addChild(new LLMenuItemCallGL( "Print Agent Info", &print_agent_nvpairs, nullptr, nullptr, 'P', MASK_SHIFT )); + menu->addChild(new LLMenuItemCallGL( "Memory Stats", &output_statistics, nullptr, nullptr, 'M', MASK_SHIFT | MASK_ALT | MASK_CONTROL)); menu->addChild(new LLMenuItemCheckGL("Double-Click Auto-Pilot", - menu_toggle_double_click_control, NULL, menu_check_control, + menu_toggle_double_click_control, nullptr, menu_check_control, (void*)"DoubleClickAutoPilot")); // add for double click teleport support menu->addChild(new LLMenuItemCheckGL("Double-Click Teleport", - menu_toggle_double_click_control, NULL, menu_check_control, + menu_toggle_double_click_control, nullptr, menu_check_control, (void*)"DoubleClickTeleport")); menu->addSeparator(); -// menu->addChild(new LLMenuItemCallGL( "Print Packets Lost", &print_packets_lost, NULL, NULL, 'L', MASK_SHIFT )); - menu->addChild(new LLMenuItemCheckGL("Debug SelectMgr", menu_toggle_control, NULL, menu_check_control, (void*)"DebugSelectMgr")); +// menu->addChild(new LLMenuItemCallGL( "Print Packets Lost", &print_packets_lost, nullptr, nullptr, 'L', MASK_SHIFT )); + menu->addChild(new LLMenuItemCheckGL("Debug SelectMgr", menu_toggle_control, nullptr, menu_check_control, (void*)"DebugSelectMgr")); menu->addChild(new LLMenuItemToggleGL("Debug Clicks", &gDebugClicks)); menu->addChild(new LLMenuItemToggleGL("Debug Views", &LLView::sDebugRects)); - menu->addChild(new LLMenuItemCheckGL("Show Name Tooltips", toggle_show_xui_names, NULL, check_show_xui_names, NULL)); + menu->addChild(new LLMenuItemCheckGL("Show Name Tooltips", toggle_show_xui_names, nullptr, check_show_xui_names, nullptr)); menu->addChild(new LLMenuItemToggleGL("Debug Mouse Events", &LLView::sDebugMouseHandling)); menu->addChild(new LLMenuItemToggleGL("Debug Keys", &LLView::sDebugKeys)); menu->addChild(new LLMenuItemToggleGL("Debug WindowProc", &gDebugWindowProc)); menu->addChild(new LLMenuItemToggleGL("Debug Text Editor Tips", &gDebugTextEditorTips)); menu->addSeparator(); - menu->addChild(new LLMenuItemCheckGL("Show Time", menu_toggle_control, NULL, menu_check_control, (void*)"DebugShowTime")); - menu->addChild(new LLMenuItemCheckGL("Show Render Info", menu_toggle_control, NULL, menu_check_control, (void*)"DebugShowRenderInfo")); - menu->addChild(new LLMenuItemCheckGL("Show Matrices", menu_toggle_control, NULL, menu_check_control, (void*)"DebugShowRenderMatrices")); - menu->addChild(new LLMenuItemCheckGL("Show Color Under Cursor", menu_toggle_control, NULL, menu_check_control, (void*)"DebugShowColor")); - menu->addChild(new LLMenuItemCheckGL("Show FPS", menu_toggle_control, NULL, menu_check_control, (void*)"SLBShowFPS")); + menu->addChild(new LLMenuItemCheckGL("Show Time", menu_toggle_control, nullptr, menu_check_control, (void*)"DebugShowTime")); + menu->addChild(new LLMenuItemCheckGL("Show Render Info", menu_toggle_control, nullptr, menu_check_control, (void*)"DebugShowRenderInfo")); + menu->addChild(new LLMenuItemCheckGL("Show Matrices", menu_toggle_control, nullptr, menu_check_control, (void*)"DebugShowRenderMatrices")); + menu->addChild(new LLMenuItemCheckGL("Show Color Under Cursor", menu_toggle_control, nullptr, menu_check_control, (void*)"DebugShowColor")); + menu->addChild(new LLMenuItemCheckGL("Show FPS", menu_toggle_control, nullptr, menu_check_control, (void*)"SLBShowFPS")); menu->createJumpKeys(); } @@ -1202,16 +1211,16 @@ void init_debug_xui_menu(LLMenuGL* menu) menu->addChild(new LLMenuItemCallGL("Load from XML...", handle_load_from_xml)); // //menu->addChild(new LLMenuItemCallGL("Save to XML...", handle_save_to_xml)); - menu->addChild(new LLMenuItemCallGL("Save to XML...", handle_save_to_xml, NULL, NULL, 'X', MASK_CONTROL | MASK_ALT | MASK_SHIFT)); + menu->addChild(new LLMenuItemCallGL("Save to XML...", handle_save_to_xml, nullptr, nullptr, 'X', MASK_CONTROL | MASK_ALT | MASK_SHIFT)); // - menu->addChild(new LLMenuItemCheckGL("Show XUI Names", toggle_show_xui_names, NULL, check_show_xui_names, NULL)); + menu->addChild(new LLMenuItemCheckGL("Show XUI Names", toggle_show_xui_names, nullptr, check_show_xui_names, nullptr)); menu->createJumpKeys(); } void init_debug_rendering_menu(LLMenuGL* menu) { - LLMenuGL* sub_menu = NULL; + LLMenuGL* sub_menu = nullptr; /////////////////////////// // @@ -1222,43 +1231,43 @@ void init_debug_rendering_menu(LLMenuGL* menu) menu->addChild(sub_menu); sub_menu->addChild(new LLMenuItemCheckGL("Simple", - &LLPipeline::toggleRenderTypeControl, NULL, + &LLPipeline::toggleRenderTypeControl, nullptr, &LLPipeline::hasRenderTypeControl, (void*)LLPipeline::RENDER_TYPE_SIMPLE, '1', MASK_CONTROL|MASK_ALT|MASK_SHIFT)); sub_menu->addChild(new LLMenuItemCheckGL("Alpha", - &LLPipeline::toggleRenderTypeControl, NULL, + &LLPipeline::toggleRenderTypeControl, nullptr, &LLPipeline::hasRenderTypeControl, (void*)LLPipeline::RENDER_TYPE_ALPHA, '2', MASK_CONTROL|MASK_ALT|MASK_SHIFT)); sub_menu->addChild(new LLMenuItemCheckGL("Tree", - &LLPipeline::toggleRenderTypeControl, NULL, + &LLPipeline::toggleRenderTypeControl, nullptr, &LLPipeline::hasRenderTypeControl, (void*)LLPipeline::RENDER_TYPE_TREE, '3', MASK_CONTROL|MASK_ALT|MASK_SHIFT)); sub_menu->addChild(new LLMenuItemCheckGL("Character", - &LLPipeline::toggleRenderTypeControl, NULL, + &LLPipeline::toggleRenderTypeControl, nullptr, &LLPipeline::hasRenderTypeControl, (void*)LLPipeline::RENDER_TYPE_AVATAR, '4', MASK_CONTROL|MASK_ALT|MASK_SHIFT)); sub_menu->addChild(new LLMenuItemCheckGL("SurfacePatch", - &LLPipeline::toggleRenderTypeControl, NULL, + &LLPipeline::toggleRenderTypeControl, nullptr, &LLPipeline::hasRenderTypeControl, (void*)LLPipeline::RENDER_TYPE_TERRAIN, '5', MASK_CONTROL|MASK_ALT|MASK_SHIFT)); sub_menu->addChild(new LLMenuItemCheckGL("Sky", - &LLPipeline::toggleRenderTypeControl, NULL, + &LLPipeline::toggleRenderTypeControl, nullptr, &LLPipeline::hasRenderTypeControl, (void*)LLPipeline::RENDER_TYPE_SKY, '6', MASK_CONTROL|MASK_ALT|MASK_SHIFT)); sub_menu->addChild(new LLMenuItemCheckGL("Water", - &LLPipeline::toggleRenderTypeControl, NULL, + &LLPipeline::toggleRenderTypeControl, nullptr, &LLPipeline::hasRenderTypeControl, (void*)LLPipeline::RENDER_TYPE_WATER, '7', MASK_CONTROL|MASK_ALT|MASK_SHIFT)); sub_menu->addChild(new LLMenuItemCheckGL("Ground", - &LLPipeline::toggleRenderTypeControl, NULL, + &LLPipeline::toggleRenderTypeControl, nullptr, &LLPipeline::hasRenderTypeControl, (void*)LLPipeline::RENDER_TYPE_GROUND, '8', MASK_CONTROL|MASK_ALT|MASK_SHIFT)); sub_menu->addChild(new LLMenuItemCheckGL("Volume", - &LLPipeline::toggleRenderTypeControl, NULL, + &LLPipeline::toggleRenderTypeControl, nullptr, &LLPipeline::hasRenderTypeControl, (void*)LLPipeline::RENDER_TYPE_VOLUME, '9', MASK_CONTROL|MASK_ALT|MASK_SHIFT)); sub_menu->addChild(new LLMenuItemCheckGL("Grass", - &LLPipeline::toggleRenderTypeControl, NULL, + &LLPipeline::toggleRenderTypeControl, nullptr, &LLPipeline::hasRenderTypeControl, (void*)LLPipeline::RENDER_TYPE_GRASS, '0', MASK_CONTROL|MASK_ALT|MASK_SHIFT)); //NOTE: Using a static variable, as an unsigned long long cannot fit in the space of a pointer. Pass pointer to callbacks @@ -1268,15 +1277,15 @@ void init_debug_rendering_menu(LLMenuGL* menu) #endif ); sub_menu->addChild(new LLMenuItemCheckGL("Clouds", //This clobbers skyuseclassicclouds, but.. big deal. - &LLPipeline::toggleRenderPairedTypeControl, NULL, + &LLPipeline::toggleRenderPairedTypeControl, nullptr, &LLPipeline::hasRenderPairedTypeControl, (void*)&cloud_flags, '-', MASK_CONTROL|MASK_ALT| MASK_SHIFT)); sub_menu->addChild(new LLMenuItemCheckGL("Particles", - &LLPipeline::toggleRenderTypeControl, NULL, + &LLPipeline::toggleRenderTypeControl, nullptr, &LLPipeline::hasRenderTypeControl, (void*)LLPipeline::RENDER_TYPE_PARTICLES, '=', MASK_CONTROL|MASK_ALT|MASK_SHIFT)); sub_menu->addChild(new LLMenuItemCheckGL("Bump", - &LLPipeline::toggleRenderTypeControl, NULL, + &LLPipeline::toggleRenderTypeControl, nullptr, &LLPipeline::hasRenderTypeControl, (void*)LLPipeline::RENDER_TYPE_BUMP, '\\', MASK_CONTROL|MASK_ALT|MASK_SHIFT)); sub_menu->createJumpKeys(); @@ -1289,35 +1298,35 @@ void init_debug_rendering_menu(LLMenuGL* menu) #define MODIFIER MASK_ALT #endif sub_menu->addChild(new LLMenuItemCheckGL("UI", - &LLPipeline::toggleRenderDebugFeature, NULL, + &LLPipeline::toggleRenderDebugFeature, nullptr, &LLPipeline::toggleRenderDebugFeatureControl, (void*)LLPipeline::RENDER_DEBUG_FEATURE_UI, KEY_F1, MODIFIER|MASK_CONTROL)); sub_menu->addChild(new LLMenuItemCheckGL("Selected", - &LLPipeline::toggleRenderDebugFeature, NULL, + &LLPipeline::toggleRenderDebugFeature, nullptr, &LLPipeline::toggleRenderDebugFeatureControl, (void*)LLPipeline::RENDER_DEBUG_FEATURE_SELECTED, KEY_F2, MODIFIER|MASK_CONTROL)); sub_menu->addChild(new LLMenuItemCheckGL("Highlighted", - &LLPipeline::toggleRenderDebugFeature, NULL, + &LLPipeline::toggleRenderDebugFeature, nullptr, &LLPipeline::toggleRenderDebugFeatureControl, (void*)LLPipeline::RENDER_DEBUG_FEATURE_HIGHLIGHTED, KEY_F3, MODIFIER|MASK_CONTROL)); sub_menu->addChild(new LLMenuItemCheckGL("Dynamic Textures", - &LLPipeline::toggleRenderDebugFeature, NULL, + &LLPipeline::toggleRenderDebugFeature, nullptr, &LLPipeline::toggleRenderDebugFeatureControl, (void*)LLPipeline::RENDER_DEBUG_FEATURE_DYNAMIC_TEXTURES, KEY_F4, MODIFIER|MASK_CONTROL)); sub_menu->addChild(new LLMenuItemCheckGL( "Foot Shadows", - &LLPipeline::toggleRenderDebugFeature, NULL, + &LLPipeline::toggleRenderDebugFeature, nullptr, &LLPipeline::toggleRenderDebugFeatureControl, (void*)LLPipeline::RENDER_DEBUG_FEATURE_FOOT_SHADOWS, KEY_F5, MODIFIER|MASK_CONTROL)); sub_menu->addChild(new LLMenuItemCheckGL("Fog", - &LLPipeline::toggleRenderDebugFeature, NULL, + &LLPipeline::toggleRenderDebugFeature, nullptr, &LLPipeline::toggleRenderDebugFeatureControl, (void*)LLPipeline::RENDER_DEBUG_FEATURE_FOG, KEY_F6, MODIFIER|MASK_CONTROL)); sub_menu->addChild(new LLMenuItemCheckGL("Test FRInfo", - &LLPipeline::toggleRenderDebugFeature, NULL, + &LLPipeline::toggleRenderDebugFeature, nullptr, &LLPipeline::toggleRenderDebugFeatureControl, (void*)LLPipeline::RENDER_DEBUG_FEATURE_FR_INFO, KEY_F8, MODIFIER|MASK_CONTROL)); sub_menu->addChild(new LLMenuItemCheckGL( "Flexible Objects", - &LLPipeline::toggleRenderDebugFeature, NULL, + &LLPipeline::toggleRenderDebugFeature, nullptr, &LLPipeline::toggleRenderDebugFeatureControl, (void*)LLPipeline::RENDER_DEBUG_FEATURE_FLEXIBLE, KEY_F9, MODIFIER|MASK_CONTROL)); sub_menu->createJumpKeys(); @@ -1330,79 +1339,79 @@ void init_debug_rendering_menu(LLMenuGL* menu) sub_menu->setCanTearOff(TRUE); menu->addChild(sub_menu); - sub_menu->addChild(new LLMenuItemCheckGL("Verify", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Verify", &LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_VERIFY)); - sub_menu->addChild(new LLMenuItemCheckGL("BBoxes", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("BBoxes", &LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_BBOXES)); - sub_menu->addChild(new LLMenuItemCheckGL("Points", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Points", &LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_POINTS)); - sub_menu->addChild(new LLMenuItemCheckGL("Octree", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Octree", &LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_OCTREE)); - sub_menu->addChild(new LLMenuItemCheckGL("Shadow Frusta", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Shadow Frusta", &LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA)); - sub_menu->addChild(new LLMenuItemCheckGL("Occlusion", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Occlusion", &LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_OCCLUSION)); - sub_menu->addChild(new LLMenuItemCheckGL("Render Batches", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Render Batches", &LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_BATCH_SIZE)); - sub_menu->addChild(new LLMenuItemCheckGL("Animated Textures", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Animated Textures", &LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_TEXTURE_ANIM)); - sub_menu->addChild(new LLMenuItemCheckGL("Texture Priority", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Texture Priority", &LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY)); - sub_menu->addChild(new LLMenuItemCheckGL("Avatar Rendering Cost", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Avatar Rendering Cost", &LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_SHAME, 'C', MASK_CONTROL|MASK_ALT|MASK_SHIFT)); - sub_menu->addChild(new LLMenuItemCheckGL("Texture Area (sqrt(A))",&LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Texture Area (sqrt(A))",&LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_TEXTURE_AREA)); - sub_menu->addChild(new LLMenuItemCheckGL("Face Area (sqrt(A))",&LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Face Area (sqrt(A))",&LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_FACE_AREA)); - sub_menu->addChild(new LLMenuItemCheckGL("Lights", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Lights", &LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_LIGHTS)); - sub_menu->addChild(new LLMenuItemCheckGL("Particles", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Particles", &LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_PARTICLES)); - sub_menu->addChild(new LLMenuItemCheckGL("Composition", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Composition", &LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_COMPOSITION)); - sub_menu->addChild(new LLMenuItemCheckGL("Glow",&LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Glow",&LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_GLOW)); - sub_menu->addChild(new LLMenuItemCheckGL("Raycasting", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Raycasting", &LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_RAYCAST)); - sub_menu->addChild(new LLMenuItemCheckGL("Sculpt", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Sculpt", &LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_SCULPTED)); - sub_menu->addChild(new LLMenuItemCheckGL("Build Queue", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Build Queue", &LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_BUILD_QUEUE)); - sub_menu->addChild(new LLMenuItemCheckGL("Update Types", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Update Types", &LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_UPDATE_TYPE)); - sub_menu->addChild(new LLMenuItemCheckGL("Physics Shapes", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Physics Shapes", &LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_PHYSICS_SHAPES)); - sub_menu->addChild(new LLMenuItemCheckGL("Normals", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Normals", &LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_NORMALS)); - sub_menu->addChild(new LLMenuItemCheckGL("LOD Info", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("LOD Info", &LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_LOD_INFO)); - sub_menu->addChild(new LLMenuItemCheckGL("Wind Vectors", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Wind Vectors", &LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_WIND_VECTORS)); - sub_menu->addChild(new LLMenuItemCheckGL("Complexity", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Complexity", &LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_RENDER_COMPLEXITY)); @@ -1411,7 +1420,7 @@ void init_debug_rendering_menu(LLMenuGL* menu) sub_menu->addChild(new LLMenuItemCheckGL("Camera Offset", &menu_toggle_control, - NULL, + nullptr, &menu_check_control, (void*)"CameraOffset")); @@ -1426,68 +1435,68 @@ void init_debug_rendering_menu(LLMenuGL* menu) menu->addChild( sub_menu ); menu->addSeparator(); - menu->addChild(new LLMenuItemCheckGL("Axes", menu_toggle_control, NULL, menu_check_control, (void*)"ShowAxes")); + menu->addChild(new LLMenuItemCheckGL("Axes", menu_toggle_control, nullptr, menu_check_control, (void*)"ShowAxes")); menu->addSeparator(); - menu->addChild(new LLMenuItemCheckGL("Hide Selected", menu_toggle_control, NULL, menu_check_control, (void*)"HideSelectedObjects")); + menu->addChild(new LLMenuItemCheckGL("Hide Selected", menu_toggle_control, nullptr, menu_check_control, (void*)"HideSelectedObjects")); menu->addSeparator(); - menu->addChild(new LLMenuItemCheckGL("Tangent Basis", menu_toggle_control, NULL, menu_check_control, (void*)"ShowTangentBasis")); - menu->addChild(new LLMenuItemCallGL("Selected Texture Info", handle_selected_texture_info, NULL, NULL, 'T', MASK_CONTROL|MASK_SHIFT|MASK_ALT)); - //menu->addChild(new LLMenuItemCallGL("Dump Image List", handle_dump_image_list, NULL, NULL, 'I', MASK_CONTROL|MASK_SHIFT)); + menu->addChild(new LLMenuItemCheckGL("Tangent Basis", menu_toggle_control, nullptr, menu_check_control, (void*)"ShowTangentBasis")); + menu->addChild(new LLMenuItemCallGL("Selected Texture Info", handle_selected_texture_info, nullptr, nullptr, 'T', MASK_CONTROL|MASK_SHIFT|MASK_ALT)); + //menu->addChild(new LLMenuItemCallGL("Dump Image List", handle_dump_image_list, nullptr, nullptr, 'I', MASK_CONTROL|MASK_SHIFT)); - menu->addChild(new LLMenuItemCheckGL("Wireframe", advanced_toggle_wireframe, NULL, advanced_check_wireframe, NULL, 'R', MASK_CONTROL|MASK_SHIFT)); + menu->addChild(new LLMenuItemCheckGL("Wireframe", advanced_toggle_wireframe, nullptr, advanced_check_wireframe, nullptr, 'R', MASK_CONTROL|MASK_SHIFT)); LLMenuItemCheckGL* item; - item = new LLMenuItemCheckGL("Object-Object Occlusion", menu_toggle_control, NULL, menu_check_control, (void*)"UseOcclusion", 'O', MASK_CONTROL|MASK_SHIFT); + item = new LLMenuItemCheckGL("Object-Object Occlusion", menu_toggle_control, nullptr, menu_check_control, (void*)"UseOcclusion", 'O', MASK_CONTROL|MASK_SHIFT); item->setEnabled(gGLManager.mHasOcclusionQuery && LLFeatureManager::getInstance()->isFeatureAvailable("UseOcclusion")); menu->addChild(item); - item = new LLMenuItemCheckGL("Debug GL", menu_toggle_control, NULL, menu_check_control, (void*)"RenderDebugGL"); + item = new LLMenuItemCheckGL("Debug GL", menu_toggle_control, nullptr, menu_check_control, (void*)"RenderDebugGL"); menu->addChild(item); - item = new LLMenuItemCheckGL("Debug Pipeline", menu_toggle_control, NULL, menu_check_control, (void*)"RenderDebugPipeline"); + item = new LLMenuItemCheckGL("Debug Pipeline", menu_toggle_control, nullptr, menu_check_control, (void*)"RenderDebugPipeline"); menu->addChild(item); - item = new LLMenuItemCheckGL("Automatic Alpha Masks (non-deferred)", menu_toggle_control, NULL, menu_check_control, (void*)"RenderAutoMaskAlphaNonDeferred"); + item = new LLMenuItemCheckGL("Automatic Alpha Masks (non-deferred)", menu_toggle_control, nullptr, menu_check_control, (void*)"RenderAutoMaskAlphaNonDeferred"); menu->addChild(item); - item = new LLMenuItemCheckGL("Automatic Alpha Masks (deferred)", menu_toggle_control, NULL, menu_check_control, (void*)"RenderAutoMaskAlphaDeferred"); + item = new LLMenuItemCheckGL("Automatic Alpha Masks (deferred)", menu_toggle_control, nullptr, menu_check_control, (void*)"RenderAutoMaskAlphaDeferred"); menu->addChild(item); - item = new LLMenuItemCheckGL("Aggressive Alpha Masking", menu_toggle_control, NULL, menu_check_control, (void*)"SHUseRMSEAutoMask"); + item = new LLMenuItemCheckGL("Aggressive Alpha Masking", menu_toggle_control, nullptr, menu_check_control, (void*)"SHUseRMSEAutoMask"); menu->addChild(item); - menu->addChild(new LLMenuItemCallGL("Rebuild Vertex Buffers", reset_vertex_buffers, NULL, NULL, 'V', MASK_CONTROL | MASK_SHIFT)); + menu->addChild(new LLMenuItemCallGL("Rebuild Vertex Buffers", reset_vertex_buffers, nullptr, nullptr, 'V', MASK_CONTROL | MASK_SHIFT)); - item = new LLMenuItemCheckGL("Animate Trees", menu_toggle_control, NULL, menu_check_control, (void*)"RenderAnimateTrees"); + item = new LLMenuItemCheckGL("Animate Trees", menu_toggle_control, nullptr, menu_check_control, (void*)"RenderAnimateTrees"); menu->addChild(item); - item = new LLMenuItemCheckGL("Animate Textures", menu_toggle_control, NULL, menu_check_control, (void*)"AnimateTextures"); + item = new LLMenuItemCheckGL("Animate Textures", menu_toggle_control, nullptr, menu_check_control, (void*)"AnimateTextures"); menu->addChild(item); - item = new LLMenuItemCheckGL("Disable Textures", menu_toggle_control, NULL, menu_check_control, (void*)"TextureDisable"); + item = new LLMenuItemCheckGL("Disable Textures", menu_toggle_control, nullptr, menu_check_control, (void*)"TextureDisable"); menu->addChild(item); - item = new LLMenuItemCheckGL("HTTP Get Textures", menu_toggle_control, NULL, menu_check_control, (void*)"ImagePipelineUseHTTP"); + item = new LLMenuItemCheckGL("HTTP Get Textures", menu_toggle_control, nullptr, menu_check_control, (void*)"ImagePipelineUseHTTP"); menu->addChild(item); - item = new LLMenuItemCheckGL("Run Multiple Threads", menu_toggle_control, NULL, menu_check_control, (void*)"RunMultipleThreads"); + item = new LLMenuItemCheckGL("Run Multiple Threads", menu_toggle_control, nullptr, menu_check_control, (void*)"RunMultipleThreads"); menu->addChild(item); - item = new LLMenuItemCheckGL("Cheesy Beacon", menu_toggle_control, NULL, menu_check_control, (void*)"CheesyBeacon"); + item = new LLMenuItemCheckGL("Cheesy Beacon", menu_toggle_control, nullptr, menu_check_control, (void*)"CheesyBeacon"); menu->addChild(item); - item = new LLMenuItemCheckGL("Attached Lights", menu_toggle_attached_lights, NULL, menu_check_control, (void*)"RenderAttachedLights"); + item = new LLMenuItemCheckGL("Attached Lights", menu_toggle_attached_lights, nullptr, menu_check_control, (void*)"RenderAttachedLights"); menu->addChild(item); - item = new LLMenuItemCheckGL("Attached Particles", menu_toggle_attached_particles, NULL, menu_check_control, (void*)"RenderAttachedParticles"); + item = new LLMenuItemCheckGL("Attached Particles", menu_toggle_attached_particles, nullptr, menu_check_control, (void*)"RenderAttachedParticles"); menu->addChild(item); - item = new LLMenuItemCheckGL("Audit Texture", menu_toggle_control, NULL, menu_check_control, (void*)"AuditTexture"); + item = new LLMenuItemCheckGL("Audit Texture", menu_toggle_control, nullptr, menu_check_control, (void*)"AuditTexture"); menu->addChild(item); menu->addSeparator(); - menu->addChild(new LLMenuItemCallGL("Memory Leaking Simulation", LLFloaterMemLeak::show, NULL, NULL)); + menu->addChild(new LLMenuItemCallGL("Memory Leaking Simulation", LLFloaterMemLeak::show, nullptr, nullptr)); menu->createJumpKeys(); } @@ -1496,13 +1505,13 @@ void init_debug_avatar_menu(LLMenuGL* menu) { LLMenuGL* sub_menu = new LLMenuGL("Character Tests"); sub_menu->setCanTearOff(TRUE); - sub_menu->addChild(new LLMenuItemCheckGL("Go Away/AFK When Idle", menu_toggle_control, NULL, menu_check_control, (void*)"AllowIdleAFK")); + sub_menu->addChild(new LLMenuItemCheckGL("Go Away/AFK When Idle", menu_toggle_control, nullptr, menu_check_control, (void*)"AllowIdleAFK")); sub_menu->addChild(new LLMenuItemCallGL("Appearance To XML", &handle_dump_archetype_xml)); // HACK for easy testing of avatar geometry sub_menu->addChild(new LLMenuItemCallGL( "Toggle Character Geometry", - &handle_god_request_avatar_geometry, &is_god_customer_service, NULL)); + &handle_god_request_avatar_geometry, &is_god_customer_service, nullptr)); sub_menu->addChild(new LLMenuItemCallGL("Test Male", handle_test_male)); @@ -1512,19 +1521,19 @@ void init_debug_avatar_menu(LLMenuGL* menu) sub_menu->addChild(new LLMenuItemCallGL("Toggle PG", handle_toggle_pg)); - sub_menu->addChild(new LLMenuItemCheckGL("Allow Select Avatar", menu_toggle_control, NULL, menu_check_control, (void*)"AllowSelectAvatar")); + sub_menu->addChild(new LLMenuItemCheckGL("Allow Select Avatar", menu_toggle_control, nullptr, menu_check_control, (void*)"AllowSelectAvatar")); sub_menu->createJumpKeys(); menu->addChild(sub_menu); - menu->addChild(new LLMenuItemCheckGL("Tap-Tap-Hold To Run", menu_toggle_control, NULL, menu_check_control, (void*)"AllowTapTapHoldRun")); - menu->addChild(new LLMenuItemCallGL("Force Params to Default", &LLAgent::clearVisualParams, NULL)); - menu->addChild(new LLMenuItemCallGL("Reload Vertex Shader", &reload_vertex_shader, NULL)); + menu->addChild(new LLMenuItemCheckGL("Tap-Tap-Hold To Run", menu_toggle_control, nullptr, menu_check_control, (void*)"AllowTapTapHoldRun")); + menu->addChild(new LLMenuItemCallGL("Force Params to Default", &LLAgent::clearVisualParams, nullptr)); + menu->addChild(new LLMenuItemCallGL("Reload Vertex Shader", &reload_vertex_shader, nullptr)); menu->addChild(new LLMenuItemToggleGL("Animation Info", &LLVOAvatar::sShowAnimationDebug)); - menu->addChild(new LLMenuItemCallGL("Slow Motion Animations", &slow_mo_animations, NULL)); + menu->addChild(new LLMenuItemCallGL("Slow Motion Animations", &slow_mo_animations, nullptr)); LLMenuItemCheckGL* item; - item = new LLMenuItemCheckGL("Show Look At", menu_toggle_control, NULL, menu_check_control, (void*)"AscentShowLookAt"); + item = new LLMenuItemCheckGL("Show Look At", menu_toggle_control, nullptr, menu_check_control, (void*)"AscentShowLookAt"); menu->addChild(item); menu->addChild(new LLMenuItemToggleGL("Show Point At", &LLHUDEffectPointAt::sDebugPointAt)); @@ -1535,27 +1544,27 @@ void init_debug_avatar_menu(LLMenuGL* menu) //diabling collision plane due to DEV-14477 -brad //menu->addChild(new LLMenuItemToggleGL("Show Collision Plane", &LLVOAvatar::sShowFootPlane)); menu->addChild(new LLMenuItemCheckGL("Show Collision Skeleton", - &LLPipeline::toggleRenderDebug, NULL, + &LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_AVATAR_VOLUME)); menu->addChild(new LLMenuItemCheckGL("Show Avatar Joints", - &LLPipeline::toggleRenderDebug, NULL, + &LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_AVATAR_JOINTS)); menu->addChild(new LLMenuItemCheckGL("Display Agent Target", - &LLPipeline::toggleRenderDebug, NULL, + &LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_AGENT_TARGET)); menu->addChild(new LLMenuItemCheckGL("Attachment Bytes", - &LLPipeline::toggleRenderDebug, NULL, + &LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_ATTACHMENT_BYTES)); menu->addChild(new LLMenuItemToggleGL( "Debug Rotation", &LLVOAvatar::sDebugAvatarRotation)); menu->addChild(new LLMenuItemCallGL("Dump Attachments", handle_dump_attachments)); menu->addChild(new LLMenuItemCallGL("Rebake Textures", handle_rebake_textures)); #ifndef LL_RELEASE_FOR_DOWNLOAD - menu->addChild(new LLMenuItemCallGL("Debug Avatar Textures", handle_debug_avatar_textures, NULL, NULL, 'A', MASK_SHIFT|MASK_CONTROL|MASK_ALT)); - menu->addChild(new LLMenuItemCallGL("Dump Local Textures", handle_dump_avatar_local_textures, NULL, NULL, 'M', MASK_SHIFT|MASK_ALT )); + menu->addChild(new LLMenuItemCallGL("Debug Avatar Textures", handle_debug_avatar_textures, nullptr, nullptr, 'A', MASK_SHIFT|MASK_CONTROL|MASK_ALT)); + menu->addChild(new LLMenuItemCallGL("Dump Local Textures", handle_dump_avatar_local_textures, nullptr, nullptr, 'M', MASK_SHIFT|MASK_ALT )); #endif gMeshesAndMorphsMenu = new LLMenuGL("Meshes and Morphs"); @@ -1576,39 +1585,39 @@ void init_debug_rlva_menu(LLMenuGL* menu) pDbgMenu->setCanTearOff(TRUE); if (gSavedSettings.controlExists(RLV_SETTING_DEBUG)) - pDbgMenu->addChild(new LLMenuItemCheckGL("Show Debug Messages", menu_toggle_control, NULL, menu_check_control, (void*)RLV_SETTING_DEBUG)); + pDbgMenu->addChild(new LLMenuItemCheckGL("Show Debug Messages", menu_toggle_control, nullptr, menu_check_control, (void*)RLV_SETTING_DEBUG)); pDbgMenu->addSeparator(); if (gSavedSettings.controlExists(RLV_SETTING_ENABLELEGACYNAMING)) - pDbgMenu->addChild(new LLMenuItemCheckGL("Enable Legacy Naming", menu_toggle_control, NULL, menu_check_control, (void*)RLV_SETTING_ENABLELEGACYNAMING)); + pDbgMenu->addChild(new LLMenuItemCheckGL("Enable Legacy Naming", menu_toggle_control, nullptr, menu_check_control, (void*)RLV_SETTING_ENABLELEGACYNAMING)); if (gSavedSettings.controlExists(RLV_SETTING_SHAREDINVAUTORENAME)) - pDbgMenu->addChild(new LLMenuItemCheckGL("Rename Shared Items on Wear", menu_toggle_control, NULL, menu_check_control, (void*)RLV_SETTING_SHAREDINVAUTORENAME)); + pDbgMenu->addChild(new LLMenuItemCheckGL("Rename Shared Items on Wear", menu_toggle_control, nullptr, menu_check_control, (void*)RLV_SETTING_SHAREDINVAUTORENAME)); menu->addChild(pDbgMenu); menu->addSeparator(); } if (gSavedSettings.controlExists(RLV_SETTING_ENABLESHAREDWEAR)) - menu->addChild(new LLMenuItemCheckGL("Enable Shared Wear", menu_toggle_control, NULL, menu_check_control, (void*)RLV_SETTING_ENABLESHAREDWEAR)); + menu->addChild(new LLMenuItemCheckGL("Enable Shared Wear", menu_toggle_control, nullptr, menu_check_control, (void*)RLV_SETTING_ENABLESHAREDWEAR)); menu->addSeparator(); if ( (gSavedSettings.controlExists(RLV_SETTING_HIDELOCKEDLAYER)) && (gSavedSettings.controlExists(RLV_SETTING_HIDELOCKEDATTACH)) ) { - menu->addChild(new LLMenuItemCheckGL("Hide Locked Layers", menu_toggle_control, NULL, menu_check_control, (void*)RLV_SETTING_HIDELOCKEDLAYER)); - menu->addChild(new LLMenuItemCheckGL("Hide Locked Attachments", menu_toggle_control, NULL, menu_check_control, (void*)RLV_SETTING_HIDELOCKEDATTACH)); + menu->addChild(new LLMenuItemCheckGL("Hide Locked Layers", menu_toggle_control, nullptr, menu_check_control, (void*)RLV_SETTING_HIDELOCKEDLAYER)); + menu->addChild(new LLMenuItemCheckGL("Hide Locked Attachments", menu_toggle_control, nullptr, menu_check_control, (void*)RLV_SETTING_HIDELOCKEDATTACH)); //sub_menu->addChild(new LLMenuItemToggleGL("Hide locked inventory", &rlv_handler_t::fHideLockedInventory)); menu->addSeparator(); } if (gSavedSettings.controlExists(RLV_SETTING_FORBIDGIVETORLV)) - menu->addChild(new LLMenuItemCheckGL("Forbid Give to #RLV", menu_toggle_control, NULL, menu_check_control, (void*)RLV_SETTING_FORBIDGIVETORLV)); + menu->addChild(new LLMenuItemCheckGL("Forbid Give to #RLV", menu_toggle_control, nullptr, menu_check_control, (void*)RLV_SETTING_FORBIDGIVETORLV)); if (gSavedSettings.controlExists(RLV_SETTING_ENABLELEGACYNAMING)) - menu->addChild(new LLMenuItemCheckGL("Show Name Tags", menu_toggle_control, NULL, menu_check_control, (void*)RLV_SETTING_SHOWNAMETAGS)); + menu->addChild(new LLMenuItemCheckGL("Show Name Tags", menu_toggle_control, nullptr, menu_check_control, (void*)RLV_SETTING_SHOWNAMETAGS)); menu->addSeparator(); - menu->addChild(new LLMenuItemCheckGL("Restrictions...", &RlvFloaterBehaviours::toggle, NULL, &RlvFloaterBehaviours::visible, NULL)); - menu->addChild(new LLMenuItemCheckGL("Locks...", &RlvFloaterLocks::toggle, NULL, &RlvFloaterLocks::visible, NULL)); - menu->addChild(new LLMenuItemCheckGL("Strings...", &RlvFloaterStrings::toggle, NULL, &RlvFloaterStrings::visible, NULL)); + menu->addChild(new LLMenuItemCheckGL("Restrictions...", &RlvFloaterBehaviours::toggle, nullptr, &RlvFloaterBehaviours::visible, nullptr)); + menu->addChild(new LLMenuItemCheckGL("Locks...", &RlvFloaterLocks::toggle, nullptr, &RlvFloaterLocks::visible, nullptr)); + menu->addChild(new LLMenuItemCheckGL("Strings...", &RlvFloaterStrings::toggle, nullptr, &RlvFloaterStrings::visible, nullptr)); } // [/RLVa:KB] @@ -1619,18 +1628,18 @@ void init_server_menu(LLMenuGL* menu) menu->addChild(sub); sub->addChild(new LLMenuItemCallGL( "Take Copy", - &force_take_copy, &is_god_customer_service, NULL, + &force_take_copy, &is_god_customer_service, nullptr, 'O', MASK_SHIFT | MASK_ALT | MASK_CONTROL)); #ifdef _CORY_TESTING sub->addChild(new LLMenuItemCallGL( "Export Copy", - &force_export_copy, NULL, NULL)); + &force_export_copy, nullptr, nullptr)); sub->addChild(new LLMenuItemCallGL( "Import Geometry", - &force_import_geometry, NULL, NULL)); + &force_import_geometry, nullptr, nullptr)); #endif //sub->addChild(new LLMenuItemCallGL( "Force Public", - // &handle_object_owner_none, NULL, NULL)); + // &handle_object_owner_none, nullptr, nullptr)); //sub->addChild(new LLMenuItemCallGL( "Force Ownership/Permissive", - // &handle_object_owner_self_and_permissive, NULL, NULL, 'K', MASK_SHIFT | MASK_ALT | MASK_CONTROL)); + // &handle_object_owner_self_and_permissive, nullptr, nullptr, 'K', MASK_SHIFT | MASK_ALT | MASK_CONTROL)); sub->addChild(new LLMenuItemCallGL( "Force Owner To Me", &handle_object_owner_self, &is_god_customer_service)); sub->addChild(new LLMenuItemCallGL( "Force Owner Permissive", @@ -1638,11 +1647,11 @@ void init_server_menu(LLMenuGL* menu) //sub->addChild(new LLMenuItemCallGL( "Force Totally Permissive", // &handle_object_permissive)); sub->addChild(new LLMenuItemCallGL( "Delete", - &handle_force_delete, &is_god_customer_service, NULL, KEY_DELETE, MASK_SHIFT | MASK_ALT | MASK_CONTROL)); + &handle_force_delete, &is_god_customer_service, nullptr, KEY_DELETE, MASK_SHIFT | MASK_ALT | MASK_CONTROL)); sub->addChild(new LLMenuItemCallGL( "Lock", - &handle_object_lock, &is_god_customer_service, NULL, 'L', MASK_SHIFT | MASK_ALT | MASK_CONTROL)); + &handle_object_lock, &is_god_customer_service, nullptr, 'L', MASK_SHIFT | MASK_ALT | MASK_CONTROL)); sub->addChild(new LLMenuItemCallGL( "Get Asset IDs", - &handle_object_asset_ids, &is_god_customer_service, NULL, 'I', MASK_SHIFT | MASK_ALT | MASK_CONTROL)); + &handle_object_asset_ids, &is_god_customer_service, nullptr, 'I', MASK_SHIFT | MASK_ALT | MASK_CONTROL)); sub->createJumpKeys(); } { @@ -1651,10 +1660,10 @@ void init_server_menu(LLMenuGL* menu) sub->addChild(new LLMenuItemCallGL("Owner To Me", &handle_force_parcel_owner_to_me, - &is_god_customer_service, NULL)); + &is_god_customer_service, nullptr)); sub->addChild(new LLMenuItemCallGL("Set to Linden Content", &handle_force_parcel_to_content, - &is_god_customer_service, NULL)); + &is_god_customer_service, nullptr)); sub->addSeparator(); sub->addChild(new LLMenuItemCallGL("Claim Public Land", &handle_claim_public_land, &is_god_customer_service)); @@ -1666,14 +1675,14 @@ void init_server_menu(LLMenuGL* menu) menu->addChild(sub); sub->addChild(new LLMenuItemCallGL("Dump Temp Asset Data", &handle_region_dump_temp_asset_data, - &is_god_customer_service, NULL)); + &is_god_customer_service, nullptr)); sub->createJumpKeys(); } menu->addChild(new LLMenuItemCallGL( "God Tools...", - &LLFloaterGodTools::show, &enable_god_basic, NULL)); + &LLFloaterGodTools::show, &enable_god_basic, nullptr)); { - LLMenuItemCallGL* item = new LLMenuItemCallGL("insert_admin", NULL); + LLMenuItemCallGL* item = new LLMenuItemCallGL("insert_admin", nullptr); item->setVisible(false); menu->addChild(item); } @@ -1681,7 +1690,7 @@ void init_server_menu(LLMenuGL* menu) menu->addSeparator(); menu->addChild(new LLMenuItemCallGL("Save Region State", - &LLPanelRegionTools::onSaveState, &is_god_customer_service, NULL)); + &LLPanelRegionTools::onSaveState, &is_god_customer_service, nullptr)); menu->createJumpKeys(); } @@ -1691,9 +1700,9 @@ void init_server_menu(LLMenuGL* menu) ////////////////////// /* -class LLAdvancedToggleWireframe : public view_listener_t +class LLAdvancedToggleWireframe final : public view_listener_t { - bool handleEvent(const LLSD& userdata) + bool handleEvent(const LLSD& userdata) override */ void advanced_toggle_wireframe(void*) { @@ -1715,9 +1724,9 @@ class LLAdvancedToggleWireframe : public view_listener_t /* }; -class LLAdvancedCheckWireframe : public view_listener_t +class LLAdvancedCheckWireframe final : public view_listener_t { - bool handleEvent(const LLSD& userdata) + bool handleEvent(const LLSD& userdata) override */ BOOL advanced_check_wireframe(void*) { @@ -1733,28 +1742,28 @@ class LLAdvancedCheckWireframe : public view_listener_t void cleanup_menus() { delete gMenuParcelObserver; - gMenuParcelObserver = NULL; + gMenuParcelObserver = nullptr; delete gPieSelf; - gPieSelf = NULL; + gPieSelf = nullptr; delete gPieAvatar; - gPieAvatar = NULL; + gPieAvatar = nullptr; delete gPieObject; - gPieObject = NULL; + gPieObject = nullptr; delete gPieAttachment; - gPieAttachment = NULL; + gPieAttachment = nullptr; delete gPieLand; - gPieLand = NULL; + gPieLand = nullptr; delete gMenuBarView; - gMenuBarView = NULL; + gMenuBarView = nullptr; delete gMenuHolder; - gMenuHolder = NULL; + gMenuHolder = nullptr; sMenus.clear(); } @@ -1763,9 +1772,9 @@ void cleanup_menus() // Object pie menu //----------------------------------------------------------------------------- -class LLObjectReportAbuse : public view_listener_t +class LLObjectReportAbuse final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); if (objectp) @@ -1777,9 +1786,9 @@ class LLObjectReportAbuse : public view_listener_t }; // Enabled it you clicked an object -class LLObjectEnableReportAbuse : public view_listener_t +class LLObjectEnableReportAbuse final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = LLSelectMgr::getInstance()->getSelection()->getObjectCount() != 0; gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); @@ -1787,25 +1796,22 @@ class LLObjectEnableReportAbuse : public view_listener_t } }; -class LLObjectTouch : public view_listener_t +class LLObjectTouch final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - handle_object_touch(); + handle_object_touch(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(), &LLToolPie::getInstance()->getPick()); return true; } }; -void handle_object_touch() +void handle_object_touch(LLViewerObject* object, const LLPickInfo* const pick) { - LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); if (!object) return; - LLPickInfo pick = LLToolPie::getInstance()->getPick(); - // [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Modified: RLVa-1.1.0l // NOTE: fallback code since we really shouldn't be getting an active selection if we can't touch this - if ( (rlv_handler_t::isEnabled()) && (!gRlvHandler.canTouch(object, pick.mObjectOffset)) ) + if ( (rlv_handler_t::isEnabled()) && (!gRlvHandler.canTouch(object, pick ? pick->mObjectOffset : LLVector3::zero)) ) { RLV_ASSERT(false); return; @@ -1815,28 +1821,30 @@ void handle_object_touch() // *NOTE: Hope the packets arrive safely and in order or else // there will be some problems. // *TODO: Just fix this bad assumption. - send_ObjectGrab_message(object, pick, LLVector3::zero); - send_ObjectDeGrab_message(object, pick); + send_ObjectGrab_message(object, true, pick); + send_ObjectGrab_message(object, false, pick); } +bool enable_object_touch(LLViewerObject* obj, const LLVector3& offset = LLVector3::zero) +{ + bool new_value = obj && obj->flagHandleTouch(); +// [RLVa:KB] - Checked: 2010-11-12 (RLVa-1.2.1g) | Added: RLVa-1.2.1g + if (new_value && rlv_handler_t::isEnabled()) + { + // RELEASE-RLVa: [RLVa-1.2.1] Make sure this stays in sync with handle_object_touch() + new_value = gRlvHandler.canTouch(obj, offset); + } +// [/RLVa:KB] + return new_value; +} bool enable_object_touch(const LLSD& userdata) { - LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - - bool new_value = obj && obj->flagHandleTouch(); -// [RLVa:KB] - Checked: 2010-11-12 (RLVa-1.2.1g) | Added: RLVa-1.2.1g - if ( (rlv_handler_t::isEnabled()) && (new_value) ) - { - // RELEASE-RLVa: [RLVa-1.2.1] Make sure this stays in sync with handle_object_touch() - new_value = gRlvHandler.canTouch(obj, LLToolPie::getInstance()->getPick().mObjectOffset); - } -// [/RLVa:KB] - std::string touch_text; // Update label based on the node touch name if available. - LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); + auto selection = LLSelectMgr::getInstance()->getSelection(); + LLSelectNode* node = selection->getFirstRootNode(); if (node && node->mValid && !node->mTouchName.empty()) { touch_text = node->mTouchName; @@ -1848,13 +1856,14 @@ bool enable_object_touch(const LLSD& userdata) gMenuHolder->childSetText("Object Touch", touch_text); gMenuHolder->childSetText("Attachment Object Touch", touch_text); - return new_value; + + return enable_object_touch(selection->getPrimaryObject(), LLToolPie::getInstance()->getPick().mObjectOffset); }; // One object must have touch sensor -class LLObjectEnableTouch : public view_listener_t +class LLObjectEnableTouch final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { gMenuHolder->findControl(userdata["control"].asString())->setValue(enable_object_touch(userdata)); return true; @@ -1883,9 +1892,9 @@ void handle_object_open() // LLFloaterOpenObject::show(); } -class LLObjectOpen : public view_listener_t +class LLObjectOpen final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { handle_object_open(); return true; @@ -1905,9 +1914,9 @@ bool enable_object_open() return root->allowOpen(); } -class LLObjectEnableOpen : public view_listener_t +class LLObjectEnableOpen final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { gMenuHolder->findControl(userdata["control"].asString())->setValue(enable_object_open()); @@ -1915,18 +1924,18 @@ class LLObjectEnableOpen : public view_listener_t } }; -class LLViewJoystickFlycam : public view_listener_t +class LLViewJoystickFlycam final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { handle_toggle_flycam(); return true; } }; -class LLViewCheckJoystickFlycam : public view_listener_t +class LLViewCheckJoystickFlycam final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = LLViewerJoystick::getInstance()->getOverrideCamera(); gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); @@ -1940,9 +1949,9 @@ void handle_toggle_flycam() LLViewerJoystick::getInstance()->toggleFlycam(); } -class LLObjectBuild : public view_listener_t +class LLObjectBuild final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { if (gAgentCamera.getFocusOnAvatar() && !LLToolMgr::getInstance()->inEdit() && gSavedSettings.getBOOL("EditCameraMovement") ) { @@ -1982,7 +1991,7 @@ void handle_object_edit() { LLObjectSelectionHandle hSel = LLSelectMgr::getInstance()->getSelection(); RlvSelectIsEditable f; - if ((hSel.notNull()) && ((hSel->getFirstRootNode(&f, TRUE)) != NULL)) + if ((hSel.notNull()) && ((hSel->getFirstRootNode(&f, TRUE)) != nullptr)) return; // Can't edit any object under @edit=n } else if ( (gRlvHandler.hasBehaviour(RLV_BHVR_FARTOUCH)) && @@ -2034,9 +2043,9 @@ void handle_object_edit() return; } -class LLObjectEdit : public view_listener_t +class LLObjectEdit final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { handle_object_edit(); return true; @@ -2083,9 +2092,9 @@ bool add_object_to_blacklist( const LLUUID& id, const std::string& entry_name ) } // Derenderizer. Originally by Phox. -class LLObjectDerender : public view_listener_t +class LLObjectDerender final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLViewerObject* slct = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); if(!slct)return true; @@ -2220,7 +2229,7 @@ void reload_objects(LLTextureReloader& texture_list, LLViewerObject::const_child { texture_list.addTexture(object->getTEImage(i)); const LLTextureEntry* te = object->getTE(i); - if (LLMaterial* mat = te ? te->getMaterialParams().get() : NULL) + if (LLMaterial* mat = te ? te->getMaterialParams().get() : nullptr) { if (mat->getSpecularID().notNull()) texture_list.addTexture(LLViewerTextureManager::getFetchedTexture(mat->getSpecularID())); @@ -2237,9 +2246,9 @@ void reload_objects(LLTextureReloader& texture_list, LLViewerObject::const_child } } -class LLAvatarReloadTextures : public view_listener_t +class LLAvatarReloadTextures final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); if(avatar) @@ -2270,9 +2279,9 @@ class LLAvatarReloadTextures : public view_listener_t return true; } }; -class LLObjectReloadTextures : public view_listener_t +class LLObjectReloadTextures final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLViewerObject::vobj_list_t object_list; @@ -2292,9 +2301,9 @@ class LLObjectReloadTextures : public view_listener_t //--------------------------------------------------------------------------- // Land pie menu //--------------------------------------------------------------------------- -class LLLandBuild : public view_listener_t +class LLLandBuild final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLViewerParcelMgr::getInstance()->deselectLand(); @@ -2324,20 +2333,20 @@ class LLLandBuild : public view_listener_t } }; -class LLLandBuyPass : public view_listener_t +class LLLandBuyPass final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLPanelLandGeneral::onClickBuyPass((void *)FALSE); return true; } }; -class LLLandEnableBuyPass : public view_listener_t +class LLLandEnableBuyPass final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - bool new_value = LLPanelLandGeneral::enableBuyPass(NULL); + bool new_value = LLPanelLandGeneral::enableBuyPass(nullptr); gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); return true; } @@ -2398,16 +2407,16 @@ bool enable_object_edit() { LLObjectSelectionHandle hSel = LLSelectMgr::getInstance()->getSelection(); RlvSelectIsEditable f; - enable = (hSel.notNull()) && ((hSel->getFirstRootNode(&f, TRUE)) == NULL); + enable = (hSel.notNull()) && ((hSel->getFirstRootNode(&f, TRUE)) == nullptr); // [/RLVa:KB] } return enable; } -class LLEnableEdit : public view_listener_t +class LLEnableEdit final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { gMenuHolder->findControl(userdata["control"].asString())->setValue(enable_object_edit()); return true; @@ -2420,17 +2429,17 @@ bool enable_object_select_in_pathfinding_linksets() return LLPathfindingManager::getInstance()->isPathfindingEnabledForCurrentRegion() && LLSelectMgr::getInstance()->selectGetEditableLinksets(); } -class LLObjectEnablePFLinksetsSelected : public view_listener_t +class LLObjectEnablePFLinksetsSelected final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { return enable_object_select_in_pathfinding_linksets(); } }; -class LLObjectPFCharactersSelected : public view_listener_t +class LLObjectPFCharactersSelected final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLFloaterPathfindingCharacters::openCharactersWithSelectedObjects(); return true; @@ -2442,26 +2451,26 @@ bool enable_object_select_in_pathfinding_characters() return LLPathfindingManager::getInstance()->isPathfindingEnabledForCurrentRegion() && LLSelectMgr::getInstance()->selectGetViewableCharacters(); } -class LLObjectEnablePFCharactersSelected : public view_listener_t +class LLObjectEnablePFCharactersSelected final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { return enable_object_select_in_pathfinding_characters(); } }; -class LLSelfRemoveAllAttachments : public view_listener_t +class LLSelfRemoveAllAttachments final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLAppearanceMgr::instance().removeAllAttachmentsFromAvatar(); return true; } }; -class LLSelfEnableRemoveAllAttachments : public view_listener_t +class LLSelfEnableRemoveAllAttachments final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = false; if (isAgentAvatarValid()) @@ -2486,9 +2495,9 @@ class LLSelfEnableRemoveAllAttachments : public view_listener_t } }; -class LLSelfVisibleScriptInfo : public view_listener_t +class LLSelfVisibleScriptInfo final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { if (LLViewerRegion* region = gAgent.getRegion()) gMenuHolder->findControl(userdata["control"].asString())->setValue(!region->getCapability("AttachmentResources").empty()); @@ -2505,15 +2514,22 @@ BOOL enable_has_attachments(void*) //--------------------------------------------------------------------------- // Avatar pie menu //--------------------------------------------------------------------------- -//void handle_follow(void *userdata) -//{ -// // follow a given avatar by ID -// LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); -// if (objectp) -// { -// gAgent.startFollowPilot(objectp->getID()); -// } -//} + +class LLObjectFollow final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + // follow a given avatar by ID + LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (objectp) + { + if (auto av = objectp->getAvatarAncestor()) // Follow the avatar, not a control avatar or an attachment, if possible + objectp = av; + gAgent.startFollowPilot(objectp->getID(), true, gSavedSettings.getF32("SinguFollowDistance")); + } + return true; + } +}; bool enable_object_mute() { @@ -2540,18 +2556,18 @@ bool enable_object_mute() } } -class LLObjectEnableMute : public view_listener_t +class LLObjectEnableMute final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { gMenuHolder->findControl(userdata["control"].asString())->setValue(enable_object_mute()); return true; } }; -class LLObjectMute : public view_listener_t +class LLObjectMute final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); if (!object) return true; @@ -2601,7 +2617,7 @@ class LLObjectMute : public view_listener_t else { LLMuteList::getInstance()->add(mute); - LLFloaterMute::showInstance(); + LLFloaterMute::showInstance()->selectMute(mute.mID);; } return true; @@ -2609,20 +2625,20 @@ class LLObjectMute : public view_listener_t }; // -class LLObjectEnableCopyUUID : public view_listener_t +class LLObjectEnableCopyUUID final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - bool new_value = (object != NULL); + bool new_value = (object != nullptr); gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); return true; } }; -class LLObjectCopyUUID : public view_listener_t +class LLObjectCopyUUID final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); if(object) @@ -2633,9 +2649,9 @@ class LLObjectCopyUUID : public view_listener_t } }; -class LLObjectData : public view_listener_t +class LLObjectData final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); if(object) @@ -2662,9 +2678,9 @@ class LLObjectData : public view_listener_t } }; -class LLSyncAnimations : public view_listener_t +class LLSyncAnimations final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { void resync_anims(); resync_anims(); @@ -2672,9 +2688,9 @@ class LLSyncAnimations : public view_listener_t } }; -class LLCanIHasKillEmAll : public view_listener_t +class LLCanIHasKillEmAll final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLViewerObject* objpos = LLSelectMgr::getInstance()->getSelection()->getFirstRootObject(); bool new_value = false; @@ -2690,9 +2706,9 @@ class LLCanIHasKillEmAll : public view_listener_t } }; -class LLOHGOD : public view_listener_t +class LLOHGOD final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLViewerObject* objpos = LLSelectMgr::getInstance()->getSelection()->getFirstRootObject(); bool new_value = false; @@ -2709,9 +2725,9 @@ class LLOHGOD : public view_listener_t } }; -class LLPowerfulWizard : public view_listener_t +class LLPowerfulWizard final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLViewerObject* objpos = LLSelectMgr::getInstance()->getSelection()->getFirstRootObject(); if(objpos) @@ -2745,9 +2761,9 @@ class LLPowerfulWizard : public view_listener_t } }; -class LLKillEmAll : public view_listener_t +class LLKillEmAll final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { // Originally by SimmanFederal // Moved here by a big fat fuckin dog. @@ -2787,9 +2803,9 @@ class LLKillEmAll : public view_listener_t } }; -class LLObjectMeasure : public view_listener_t +class LLObjectMeasure final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { static LLVector3 startMeasurePoint = LLVector3::zero; static bool startpoint_set = false; @@ -2826,9 +2842,9 @@ class LLObjectMeasure : public view_listener_t } }; -class LLObjectPFLinksetsSelected : public view_listener_t +class LLObjectPFLinksetsSelected final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLFloaterPathfindingLinksets::openLinksetsWithSelectedObjects(); return true; @@ -2837,12 +2853,10 @@ class LLObjectPFLinksetsSelected : public view_listener_t // -bool handle_go_to() +void simulator_autopilot(const LLVector3d& pos) { - // try simulator autopilot std::vector strings; std::string val; - LLVector3d pos = LLToolPie::getInstance()->getPick().mPosGlobal; val = llformat("%.9g", pos.mdV[VX]); strings.push_back(val); val = llformat("%.9g", pos.mdV[VY]); @@ -2850,6 +2864,14 @@ bool handle_go_to() val = llformat("%.9g", pos.mdV[VZ]); strings.push_back(val); send_generic_message("autopilot", strings); +} + +void handle_go_to(const LLVector3d& pos) +{ + gAgent.stopAutoPilot(true); // Go To cancels viewer autopilot + + // try simulator autopilot + simulator_autopilot(pos); LLViewerParcelMgr::getInstance()->deselectLand(); @@ -2868,20 +2890,20 @@ bool handle_go_to() // Could be first use LLFirstUse::useGoTo(); - return true; } -class LLGoToObject : public view_listener_t +class LLGoToObject final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - return handle_go_to(); + handle_go_to(LLToolPie::instance().getPick().mPosGlobal); + return true; } }; -class LLAvatarReportAbuse : public view_listener_t +class LLAvatarReportAbuse final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); if(avatar) @@ -2896,9 +2918,9 @@ class LLAvatarReportAbuse : public view_listener_t // Object backup //--------------------------------------------------------------------------- -class LLObjectEnableExport : public view_listener_t +class LLObjectEnableExport final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { ExportPolicy export_policy = LFSimFeatureHandler::instance().exportPolicy(); bool can_export_any = false; @@ -2916,36 +2938,36 @@ class LLObjectEnableExport : public view_listener_t } }; -class LLObjectExport : public view_listener_t +class LLObjectExport final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLObjectBackup::getInstance()->exportObject(); return true; } }; -class LLObjectEnableImport : public view_listener_t +class LLObjectEnableImport final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { gMenuHolder->findControl(userdata["control"].asString())->setValue(TRUE); return true; } }; -class LLObjectImport : public view_listener_t +class LLObjectImport final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLObjectBackup::getInstance()->importObject(FALSE); return true; } }; -class LLObjectImportUpload : public view_listener_t +class LLObjectImportUpload final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLObjectBackup::getInstance()->importObject(TRUE); return true; @@ -2972,7 +2994,7 @@ bool callback_freeze(const LLSD& notification, const LLSD& response) void handle_avatar_freeze(const LLSD& avatar_id) { // Use avatar_id if available, otherwise default to right-click avatar - LLVOAvatar* avatar = NULL; + LLVOAvatar* avatar = nullptr; if (avatar_id.asUUID().notNull()) { avatar = find_avatar_from_object(avatar_id.asUUID()); @@ -3011,9 +3033,9 @@ void handle_avatar_freeze(const LLSD& avatar_id) } } -class LLAvatarFreeze : public view_listener_t +class LLAvatarFreeze final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { handle_avatar_freeze(LLUUID::null); return true; @@ -3031,43 +3053,43 @@ void do_script_count(bool del, LLViewerObject* object = nullptr) } } -class LLScriptCount : public view_listener_t +class LLScriptCount final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { do_script_count(false, userdata["data"].asString() == "agent" ? gAgentAvatarp : nullptr); return true; } }; -class LLScriptDelete : public view_listener_t +class LLScriptDelete final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { do_script_count(true); return true; } }; -class LLObjectVisibleScriptCount : public view_listener_t +class LLObjectVisibleScriptCount final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLViewerObject* object = userdata["data"].asString() == "agent" ? gAgentAvatarp : LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - bool new_value = (object != NULL); + bool new_value = (object != nullptr); gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); return true; } }; -class LLObjectEnableScriptDelete : public view_listener_t +class LLObjectEnableScriptDelete final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { auto objects = LLSelectMgr::getInstance()->getSelection(); LLViewerObject* object = objects->getPrimaryObject(); - bool new_value = (object != NULL); + bool new_value = (object != nullptr); if(new_value) for (LLObjectSelection::root_iterator iter = objects->root_begin(); iter != objects->root_end(); iter++) @@ -3086,18 +3108,18 @@ class LLObjectEnableScriptDelete : public view_listener_t } }; -class LLAvatarVisibleDebug : public view_listener_t +class LLAvatarVisibleDebug final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { gMenuHolder->findControl(userdata["control"].asString())->setValue(gAgent.isGodlike()); return true; } }; -class LLAvatarDebug : public view_listener_t +class LLAvatarDebug final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { if (isAgentAvatarValid()) { @@ -3165,7 +3187,7 @@ bool callback_eject(const LLSD& notification, const LLSD& response) void handle_avatar_eject(const LLSD& avatar_id) { // Use avatar_id if available, otherwise default to right-click avatar - LLVOAvatar* avatar = NULL; + LLVOAvatar* avatar = nullptr; if (avatar_id.asUUID().notNull()) { avatar = find_avatar_from_object(avatar_id.asUUID()); @@ -3234,9 +3256,9 @@ void handle_avatar_eject(const LLSD& avatar_id) } } -class LLAvatarEject : public view_listener_t +class LLAvatarEject final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { handle_avatar_eject(LLUUID::null); return true; @@ -3244,9 +3266,9 @@ class LLAvatarEject : public view_listener_t }; -class LLAvatarCopyUUID : public view_listener_t +class LLAvatarCopyUUID final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); if(!avatar) return true; @@ -3256,9 +3278,9 @@ class LLAvatarCopyUUID : public view_listener_t } }; -class LLAvatarClientUUID : public view_listener_t +class LLAvatarClientUUID final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); if(!avatar) return true; @@ -3271,7 +3293,7 @@ class LLAvatarClientUUID : public view_listener_t bool enable_freeze_eject(const LLSD& avatar_id) { // Use avatar_id if available, otherwise default to right-click avatar - LLVOAvatar* avatar = NULL; + LLVOAvatar* avatar = nullptr; if (avatar_id.asUUID().notNull()) { avatar = find_avatar_from_object(avatar_id.asUUID()); @@ -3302,18 +3324,18 @@ bool enable_freeze_eject(const LLSD& avatar_id) return new_value; } -class LLAvatarEnableFreezeEject : public view_listener_t +class LLAvatarEnableFreezeEject final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { gMenuHolder->findControl(userdata["control"].asString())->setValue(enable_freeze_eject(LLUUID::null)); return true; } }; -class LLAvatarGiveCard : public view_listener_t +class LLAvatarGiveCard final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LL_INFOS() << "handle_give_card()" << LL_ENDL; LLViewerObject* dest = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); @@ -3412,7 +3434,7 @@ bool enable_buy_object() // In order to buy, there must only be 1 purchaseable object in // the selection manager. if(LLSelectMgr::getInstance()->getSelection()->getRootObjectCount() != 1) return false; - LLViewerObject* obj = NULL; + LLViewerObject* obj = nullptr; LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); if(node) { @@ -3431,9 +3453,9 @@ bool enable_buy_object() } -class LLObjectEnableBuy : public view_listener_t +class LLObjectEnableBuy final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = enable_buy_object(); gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); @@ -3554,10 +3576,11 @@ void handle_dump_focus(void *) LL_INFOS() << "Keyboard focus " << (ctrl ? ctrl->getName() : "(none)") << LL_ENDL; } -class LLSelfSitOrStand : public view_listener_t +class LLSelfSitOrStand final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { + gAgent.stopAutoPilot(true); if (gAgentAvatarp && gAgentAvatarp->isSitting()) { gAgent.standUp(); @@ -3589,9 +3612,9 @@ bool enable_sitdown_self() // return isAgentAvatarValid() && !gAgentAvatarp->isSitting() && !gAgent.getFlying(); } -class LLSelfEnableSitOrStand : public view_listener_t +class LLSelfEnableSitOrStand final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { std::string label; std::string sit_text; @@ -3728,7 +3751,7 @@ void handle_fake_away_status(void*) // /* -class LLHaveCallingcard : public LLInventoryCollectFunctor +class LLHaveCallingcard final : public LLInventoryCollectFunctor { public: LLHaveCallingcard(const LLUUID& agent_id); @@ -3774,9 +3797,9 @@ BOOL is_agent_mappable(const LLUUID& agent_id) // Enable a menu item when you don't have someone's card. -class LLAvatarEnableAddFriend : public view_listener_t +class LLAvatarEnableAddFriend final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLVOAvatar* avatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); // bool new_value = avatar && !LLAvatarActions::isFriend(avatar->getID()); @@ -3813,9 +3836,9 @@ void request_friendship(const LLUUID& dest_id) } -class LLEditEnableCustomizeAvatar : public view_listener_t +class LLEditEnableCustomizeAvatar final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = (gAgentAvatarp && gAgentAvatarp->isFullyLoaded() && @@ -3826,9 +3849,9 @@ class LLEditEnableCustomizeAvatar : public view_listener_t }; -class LLEditEnableChangeDisplayname : public view_listener_t +class LLEditEnableChangeDisplayname final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { gMenuHolder->findControl(userdata["control"].asString())->setValue(LLAvatarName::useDisplayNames()); return true; @@ -3860,28 +3883,14 @@ bool is_object_sittable() } -// only works on pie menu -void handle_object_sit_or_stand() +void handle_object_sit(LLViewerObject* object, const LLVector3& offset = LLVector3::zero) { - LLPickInfo pick = LLToolPie::getInstance()->getPick(); - LLViewerObject *object = pick.getObject();; - if (!object || pick.mPickType == LLPickInfo::PICK_FLORA) - { - return; - } - - if (sitting_on_selection()) - { - gAgent.standUp(); - return; - } - // get object selection offset // if (object && object->getPCode() == LL_PCODE_VOLUME) // [RLVa:KB] - Checked: 2010-03-06 (RLVa-1.2.0c) | Modified: RLVa-1.2.0c if ( (object && object->getPCode() == LL_PCODE_VOLUME) && - ((!rlv_handler_t::isEnabled()) || (gRlvHandler.canSit(object, pick.mObjectOffset))) ) + ((!rlv_handler_t::isEnabled()) || (gRlvHandler.canSit(object, offset))) ) // [/RLVa:KB] { // [RLVa:KB] - Checked: 2010-08-29 (RLVa-1.2.1c) | Added: RLVa-1.2.1c @@ -3902,15 +3911,36 @@ void handle_object_sit_or_stand() gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); gMessageSystem->nextBlockFast(_PREHASH_TargetObject); gMessageSystem->addUUIDFast(_PREHASH_TargetID, object->mID); - gMessageSystem->addVector3Fast(_PREHASH_Offset, pick.mObjectOffset); + gMessageSystem->addVector3Fast(_PREHASH_Offset, offset); object->getRegion()->sendReliableMessage(); } } -class LLObjectSitOrStand : public view_listener_t +// only works on pie menu +void handle_object_sit_or_stand() { - bool handleEvent(LLPointer event, const LLSD& userdata) + LLPickInfo pick = LLToolPie::getInstance()->getPick(); + LLViewerObject *object = pick.getObject();; + if (!object || pick.mPickType == LLPickInfo::PICK_FLORA) + { + return; + } + + gAgent.stopAutoPilot(true); + + if (sitting_on_selection()) + { + gAgent.standUp(); + return; + } + + handle_object_sit(object, pick.mObjectOffset); +} + +class LLObjectSitOrStand final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override { handle_object_sit_or_stand(); return true; @@ -3930,9 +3960,9 @@ void near_sit_down_point(BOOL success, void *) } } -class LLLandSit : public view_listener_t +class LLLandSit final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { // [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.2.1f if ( (rlv_handler_t::isEnabled()) && ((!RlvActions::canStand()) || (gRlvHandler.hasBehaviour(RLV_BHVR_SIT))) ) @@ -3953,33 +3983,33 @@ class LLLandSit : public view_listener_t { target_rot = gAgent.getFrameAgent().getQuaternion(); } - gAgent.startAutoPilotGlobal(posGlobal, "Sit", &target_rot, near_sit_down_point, NULL, 0.7f); + gAgent.startAutoPilotGlobal(posGlobal, "Sit", &target_rot, near_sit_down_point, nullptr, 0.7f); return true; } }; -class LLCreateLandmarkCallback : public LLInventoryCallback +class LLCreateLandmarkCallback final : public LLInventoryCallback { public: - /*virtual*/ void fire(const LLUUID& inv_item) + void fire(const LLUUID& inv_item) override { LL_INFOS() << "Created landmark with inventory id " << inv_item << LL_ENDL; } }; -class LLWorldFly : public view_listener_t +class LLWorldFly final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { gAgent.toggleFlying(); return true; } }; -class LLWorldEnableFly : public view_listener_t +class LLWorldEnableFly final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { gMenuHolder->findControl(userdata["control"].asString())->setValue(gAgent.enableFlying()); return true; @@ -4062,13 +4092,18 @@ void handle_reset_view() } else { + if (gAgent.getAutoPilot()) + { + gAgent.stopAutoPilot(true); + } + reset_view_final( true ); } } -class LLViewResetView : public view_listener_t +class LLViewResetView final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { handle_reset_view(); return true; @@ -4111,36 +4146,36 @@ void reset_view_final( BOOL proceed ) } -class LLViewResetPresetAngles : public view_listener_t +class LLViewResetPresetAngles final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { gAgentCamera.resetPresetOffsets(); return true; } }; -class LLViewLookAtLastChatter : public view_listener_t +class LLViewLookAtLastChatter final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { gAgentCamera.lookAtLastChat(); return true; } }; -class LLViewFullscreen : public view_listener_t +class LLViewFullscreen final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { gViewerWindow->toggleFullscreen(TRUE); return true; } }; -class LLViewDefaultUISize : public view_listener_t +class LLViewDefaultUISize final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { gSavedSettings.setF32("UIScaleFactor", 1.0f); gSavedSettings.setBOOL("UIAutoScale", FALSE); @@ -4149,9 +4184,9 @@ class LLViewDefaultUISize : public view_listener_t } }; -class LLEditDuplicate : public view_listener_t +class LLEditDuplicate final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { // [RLVa:KB] - Checked: 2009-07-05 (RLVa-1.0.0b) if ( (rlv_handler_t::isEnabled()) && (gRlvHandler.hasBehaviour(RLV_BHVR_REZ)) && @@ -4169,9 +4204,9 @@ class LLEditDuplicate : public view_listener_t } }; -class LLEditEnableDuplicate : public view_listener_t +class LLEditEnableDuplicate final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canDuplicate(); // [RLVa:KB] - Checked: 2009-07-05 (RLVa-1.0.0b) @@ -4348,7 +4383,6 @@ void handle_claim_public_land(void*) void handle_dump_archetype_xml(void *) { - std::string emptyname; LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); if (!avatar) @@ -4451,7 +4485,10 @@ static bool get_derezzable_objects( break; case DRD_RETURN_TO_OWNER: - can_derez_current = TRUE; + if(!object->isAttachment()) + { + can_derez_current = TRUE; + } break; default: @@ -4482,9 +4519,9 @@ static bool get_derezzable_objects( static bool can_derez(EDeRezDestination dest) { - LLViewerRegion* first_region = NULL; + LLViewerRegion* first_region = nullptr; std::string error; - return get_derezzable_objects(dest, error, first_region, NULL, true); + return get_derezzable_objects(dest, error, first_region, nullptr, true); } static void derez_objects( @@ -4559,17 +4596,13 @@ static void derez_objects( LLViewerObject* object = objectsp->at(object_index++); msg->nextBlockFast(_PREHASH_ObjectData); msg->addU32Fast(_PREHASH_ObjectLocalID, object->getLocalID()); - // if(!gSavedSettings.getBOOL("DisablePointAtAndBeam")) { - // // VEFFECT: DerezObject LLHUDEffectSpiral* effectp = (LLHUDEffectSpiral*)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE); effectp->setPositionGlobal(object->getPositionGlobal()); effectp->setColor(LLColor4U(gAgent.getEffectColor())); - // } - // } msg->sendReliable(first_region->getHost()); } @@ -4590,14 +4623,14 @@ static void derez_objects( static void derez_objects(EDeRezDestination dest, const LLUUID& dest_id) { - LLViewerRegion* first_region = NULL; + LLViewerRegion* first_region = nullptr; std::string error; - derez_objects(dest, dest_id, first_region, error, NULL); + derez_objects(dest, dest_id, first_region, error, nullptr); } -class LLToolsTakeCopy : public view_listener_t +class LLToolsTakeCopy final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { handle_take_copy(); return true; @@ -4614,7 +4647,7 @@ void handle_take_copy() // Allow only if the avie isn't sitting on any of the selected objects LLObjectSelectionHandle hSel = LLSelectMgr::getInstance()->getSelection(); RlvSelectIsSittingOn f(gAgentAvatarp); - if ( (hSel.notNull()) && (hSel->getFirstRootNode(&f, TRUE) != NULL) ) + if ( (hSel.notNull()) && (hSel->getFirstRootNode(&f, TRUE) != nullptr) ) return; } // [/RLVa:KB] @@ -4624,13 +4657,13 @@ void handle_take_copy() } // You can return an object to its owner if it is on your land. -class LLObjectReturn : public view_listener_t +class LLObjectReturn final : public view_listener_t { public: - LLObjectReturn() : mFirstRegion(NULL) {} + LLObjectReturn() : mFirstRegion(nullptr) {} private: - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return true; // [RLVa:KB] - Checked: 2010-03-24 (RLVa-1.4.0a) | Modified: RLVa-1.0.0b @@ -4657,10 +4690,10 @@ private: mReturnableObjects.clear(); mError.clear(); - mFirstRegion = NULL; + mFirstRegion = nullptr; // drop reference to current selection - mObjectSelection = NULL; + mObjectSelection = nullptr; return false; } @@ -4674,9 +4707,9 @@ private: // Allow return to owner if one or more of the selected items is // over land you own. -class LLObjectEnableReturn : public view_listener_t +class LLObjectEnableReturn final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) { @@ -4768,7 +4801,7 @@ void handle_take() // such a location and it is not in the trash or library if(!gInventory.getCategory(category_id)) { - // nope, set to NULL. + // nope, set to nullptr. category_id.setNull(); } if(category_id.notNull()) @@ -4909,9 +4942,9 @@ void handle_buy_or_take() } } -class LLToolsBuyOrTake : public view_listener_t +class LLToolsBuyOrTake final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { handle_buy_or_take(); return true; @@ -4923,9 +4956,9 @@ bool visible_take_object() return !is_selection_buy_not_take() && enable_take(); } -class LLToolsEnableBuyOrTake : public view_listener_t +class LLToolsEnableBuyOrTake final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool is_buy = is_selection_buy_not_take(); bool new_value = is_buy ? enable_buy_object() : enable_take(); @@ -5026,14 +5059,14 @@ void show_buy_currency(const char* extra) // Don't show currency web page for branded clients. std::ostringstream mesg; - if (extra != NULL) + if (extra != nullptr) { mesg << extra << "\n \n"; } mesg << "Go to " << BUY_CURRENCY_URL << "\nfor information on purchasing currency?"; LLSD args; - if (extra != NULL) + if (extra != nullptr) { args["EXTRA"] = extra; } @@ -5059,9 +5092,9 @@ void handle_buy() } } -class LLObjectBuy : public view_listener_t +class LLObjectBuy final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { handle_buy(); return true; @@ -5108,9 +5141,9 @@ BOOL sitting_on_selection() return (gAgentAvatarp->isSitting() && gAgentAvatarp->getRoot() == root_object); } -class LLToolsSaveToInventory : public view_listener_t +class LLToolsSaveToInventory final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool enable_save_into_inventory(); if(enable_save_into_inventory()) @@ -5121,9 +5154,9 @@ class LLToolsSaveToInventory : public view_listener_t } }; -class LLToolsSaveToObjectInventory : public view_listener_t +class LLToolsSaveToObjectInventory final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); if(node && (node->mValid) && (!node->mFromTaskID.isNull())) @@ -5135,27 +5168,27 @@ class LLToolsSaveToObjectInventory : public view_listener_t } }; -class LLToolsEnablePathfinding : public view_listener_t +class LLToolsEnablePathfinding final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - return (LLPathfindingManager::getInstance() != NULL) && LLPathfindingManager::getInstance()->isPathfindingEnabledForCurrentRegion(); + return (LLPathfindingManager::getInstance() != nullptr) && LLPathfindingManager::getInstance()->isPathfindingEnabledForCurrentRegion(); } }; -class LLToolsEnablePathfindingView : public view_listener_t +class LLToolsEnablePathfindingView final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - return (LLPathfindingManager::getInstance() != NULL) && LLPathfindingManager::getInstance()->isPathfindingEnabledForCurrentRegion() && LLPathfindingManager::getInstance()->isPathfindingViewEnabled(); + return (LLPathfindingManager::getInstance() != nullptr) && LLPathfindingManager::getInstance()->isPathfindingEnabledForCurrentRegion() && LLPathfindingManager::getInstance()->isPathfindingViewEnabled(); } }; -class LLToolsDoPathfindingRebakeRegion : public view_listener_t +class LLToolsDoPathfindingRebakeRegion final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - bool hasPathfinding = (LLPathfindingManager::getInstance() != NULL); + bool hasPathfinding = (LLPathfindingManager::getInstance() != nullptr); if (hasPathfinding) { @@ -5166,13 +5199,13 @@ class LLToolsDoPathfindingRebakeRegion : public view_listener_t } }; -class LLToolsEnablePathfindingRebakeRegion : public view_listener_t +class LLToolsEnablePathfindingRebakeRegion final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool returnValue = false; - if (LLPathfindingManager::getInstance() != NULL) + if (LLPathfindingManager::getInstance() != nullptr) { LLMenuOptionPathfindingRebakeNavmesh *rebakeInstance = LLMenuOptionPathfindingRebakeNavmesh::getInstance(); returnValue = (rebakeInstance->canRebakeRegion() && @@ -5184,9 +5217,9 @@ class LLToolsEnablePathfindingRebakeRegion : public view_listener_t }; // Round the position of all root objects to the grid -class LLToolsSnapObjectXY : public view_listener_t +class LLToolsSnapObjectXY final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { F64 snap_size = (F64)gSavedSettings.getF32("GridResolution"); @@ -5231,9 +5264,9 @@ class LLToolsSnapObjectXY : public view_listener_t }; // Determine if the option to cycle between linked prims is shown -class LLToolsEnableSelectNextPart : public view_listener_t +class LLToolsEnableSelectNextPart final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = (gSavedSettings.getBOOL("EditLinkedParts") && !LLSelectMgr::getInstance()->getSelection()->isEmpty()); @@ -5245,9 +5278,9 @@ class LLToolsEnableSelectNextPart : public view_listener_t // Cycle selection through linked children in selected object. // FIXME: Order of children list is not always the same as sim's idea of link order. This may confuse // resis. Need link position added to sim messages to address this. -class LLToolsSelectNextPart : public view_listener_t +class LLToolsSelectNextPart final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { S32 object_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount(); if (gSavedSettings.getBOOL("EditLinkedParts") && object_count) @@ -5259,7 +5292,7 @@ class LLToolsSelectNextPart : public view_listener_t bool prev = (userdata.asString() == "previous"); bool ifwd = (userdata.asString() == "includenext"); bool iprev = (userdata.asString() == "includeprevious"); - LLViewerObject* to_select = NULL; + LLViewerObject* to_select = nullptr; LLViewerObject::child_list_t children = selected->getRootEdit()->getChildren(); children.push_front(selected->getRootEdit()); // need root in the list too @@ -5306,7 +5339,7 @@ class LLToolsSelectNextPart : public view_listener_t { if (gFocusMgr.childHasKeyboardFocus(gFloaterTools)) { - gFocusMgr.setKeyboardFocus(NULL); // force edit toolbox to commit any changes + gFocusMgr.setKeyboardFocus(nullptr); // force edit toolbox to commit any changes } if (fwd || prev) { @@ -5329,9 +5362,9 @@ class LLToolsSelectNextPart : public view_listener_t // otherwise. this allows the handle_link method to more finely check // the selection and give an error message when the uer has a // reasonable expectation for the link to work, but it will fail. -class LLToolsEnableLink : public view_listener_t +class LLToolsEnableLink final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = LLSelectMgr::getInstance()->enableLinkObjects(); gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); @@ -5339,17 +5372,17 @@ class LLToolsEnableLink : public view_listener_t } }; -class LLToolsLink : public view_listener_t +class LLToolsLink final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { return LLSelectMgr::getInstance()->linkObjects(); } }; -class LLToolsEnableUnlink : public view_listener_t +class LLToolsEnableUnlink final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = LLSelectMgr::getInstance()->enableUnlinkObjects(); gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); @@ -5357,9 +5390,9 @@ class LLToolsEnableUnlink : public view_listener_t } }; -class LLToolsUnlink : public view_listener_t +class LLToolsUnlink final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLSelectMgr::getInstance()->unlinkObjects(); return true; @@ -5367,18 +5400,18 @@ class LLToolsUnlink : public view_listener_t }; -class LLToolsStopAllAnimations : public view_listener_t +class LLToolsStopAllAnimations final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { gAgent.stopCurrentAnimations(); return true; } }; -class LLToolsReleaseKeys : public view_listener_t +class LLToolsReleaseKeys final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { // [RLVa:KB] - Checked: 2010-04-19 (RLVa-1.2.0f) | Modified: RLVa-1.0.5a | OK if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_REMOVE)) ) @@ -5390,9 +5423,9 @@ class LLToolsReleaseKeys : public view_listener_t } }; -class LLToolsEnableReleaseKeys : public view_listener_t +class LLToolsEnableReleaseKeys final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { // [RLVa:KB] - Checked: 2010-04-19 (RLVa-1.2.0f) | Modified: RLVa-1.0.5a gMenuHolder->findControl(userdata["control"].asString())->setValue(gAgent.anyControlGrabbed() && @@ -5404,9 +5437,9 @@ class LLToolsEnableReleaseKeys : public view_listener_t }; -class LLEditEnableCut : public view_listener_t +class LLEditEnableCut final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canCut(); gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); @@ -5414,9 +5447,9 @@ class LLEditEnableCut : public view_listener_t } }; -class LLEditCut : public view_listener_t +class LLEditCut final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { if( LLEditMenuHandler::gEditMenuHandler ) { @@ -5426,9 +5459,9 @@ class LLEditCut : public view_listener_t } }; -class LLEditEnableCopy : public view_listener_t +class LLEditEnableCopy final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canCopy(); gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); @@ -5436,9 +5469,9 @@ class LLEditEnableCopy : public view_listener_t } }; -class LLEditCopy : public view_listener_t +class LLEditCopy final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { if( LLEditMenuHandler::gEditMenuHandler ) { @@ -5448,9 +5481,9 @@ class LLEditCopy : public view_listener_t } }; -class LLEditEnablePaste : public view_listener_t +class LLEditEnablePaste final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canPaste(); gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); @@ -5458,9 +5491,9 @@ class LLEditEnablePaste : public view_listener_t } }; -class LLEditPaste : public view_listener_t +class LLEditPaste final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { if( LLEditMenuHandler::gEditMenuHandler ) { @@ -5470,9 +5503,9 @@ class LLEditPaste : public view_listener_t } }; -class LLEditEnableDelete : public view_listener_t +class LLEditEnableDelete final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canDoDelete(); @@ -5489,9 +5522,9 @@ class LLEditEnableDelete : public view_listener_t } }; -class LLEditDelete : public view_listener_t +class LLEditDelete final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { // [RLVa:KB] - Checked: 2009-07-05 (RLVa-1.0.0b) // NOTE: we want to disable delete on objects but not disable delete on text @@ -5525,9 +5558,9 @@ bool enable_object_return() (gAgent.isGodlike() || can_derez(DRD_RETURN_TO_OWNER))); } -class LLObjectEnableDelete : public view_listener_t +class LLObjectEnableDelete final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { gMenuHolder->findControl(userdata["control"].asString())->setValue(enable_object_delete()); return true; @@ -5558,13 +5591,13 @@ bool enable_object_delete() class LLObjectsReturnPackage { public: - LLObjectsReturnPackage() : mObjectSelection(), mReturnableObjects(), mError(), mFirstRegion(NULL) {}; + LLObjectsReturnPackage() : mObjectSelection(), mReturnableObjects(), mError(), mFirstRegion(nullptr) {}; ~LLObjectsReturnPackage() { mObjectSelection.clear(); mReturnableObjects.clear(); mError.clear(); - mFirstRegion = NULL; + mFirstRegion = nullptr; }; LLObjectSelectionHandle mObjectSelection; @@ -5598,9 +5631,9 @@ void handle_object_return() } } -class LLObjectDelete : public view_listener_t +class LLObjectDelete final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { // [RLVa:KB] - Checked: 2009-07-05 (RLVa-1.0.0b) if ( (rlv_handler_t::isEnabled()) && (!rlvCanDeleteOrReturn()) ) @@ -5634,9 +5667,9 @@ void handle_force_delete(void*) LLSelectMgr::getInstance()->selectForceDelete(); } -class LLViewEnableJoystickFlycam : public view_listener_t +class LLViewEnableJoystickFlycam final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = (gSavedSettings.getBOOL("JoystickEnabled") && gSavedSettings.getBOOL("JoystickFlycamEnabled")); gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); @@ -5644,9 +5677,9 @@ class LLViewEnableJoystickFlycam : public view_listener_t } }; -class LLViewEnableLastChatter : public view_listener_t +class LLViewEnableLastChatter final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { // *TODO: add check that last chatter is in range bool new_value = (gAgentCamera.cameraThirdPerson() && gAgent.getLastChatter().notNull()); @@ -5655,9 +5688,9 @@ class LLViewEnableLastChatter : public view_listener_t } }; -class LLEditEnableDeselect : public view_listener_t +class LLEditEnableDeselect final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canDeselect(); gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); @@ -5665,9 +5698,9 @@ class LLEditEnableDeselect : public view_listener_t } }; -class LLEditDeselect : public view_listener_t +class LLEditDeselect final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { if( LLEditMenuHandler::gEditMenuHandler ) { @@ -5677,9 +5710,9 @@ class LLEditDeselect : public view_listener_t } }; -class LLEditEnableSelectAll : public view_listener_t +class LLEditEnableSelectAll final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canSelectAll(); gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); @@ -5688,9 +5721,9 @@ class LLEditEnableSelectAll : public view_listener_t }; -class LLEditSelectAll : public view_listener_t +class LLEditSelectAll final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { if( LLEditMenuHandler::gEditMenuHandler ) { @@ -5701,9 +5734,9 @@ class LLEditSelectAll : public view_listener_t }; -class LLEditEnableUndo : public view_listener_t +class LLEditEnableUndo final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canUndo(); gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); @@ -5711,9 +5744,9 @@ class LLEditEnableUndo : public view_listener_t } }; -class LLEditUndo : public view_listener_t +class LLEditUndo final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { if( LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canUndo() ) { @@ -5723,9 +5756,9 @@ class LLEditUndo : public view_listener_t } }; -class LLEditEnableRedo : public view_listener_t +class LLEditEnableRedo final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canRedo(); gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); @@ -5733,9 +5766,9 @@ class LLEditEnableRedo : public view_listener_t } }; -class LLEditRedo : public view_listener_t +class LLEditRedo final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { if( LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canRedo() ) { @@ -5809,7 +5842,7 @@ void toggle_debug_menus(void*) // LLUUID gExporterRequestID; // std::string gExportDirectory; -// LLUploadDialog *gExportDialog = NULL; +// LLUploadDialog *gExportDialog = nullptr; // void handle_export_selected( void * ) // { @@ -5862,9 +5895,9 @@ void handle_reload_settings(void*) gColors.loadFromFileLegacy(color_file, FALSE, TYPE_COL4U); } -class LLWorldSetHomeLocation : public view_listener_t +class LLWorldSetHomeLocation final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { // we just send the message and let the server check for failure cases // server will echo back a "Home position set." alert if it succeeds @@ -5874,9 +5907,9 @@ class LLWorldSetHomeLocation : public view_listener_t } }; -class LLWorldTeleportHome : public view_listener_t +class LLWorldTeleportHome final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { gAgent.teleportHome(); return true; @@ -5889,27 +5922,27 @@ void toggle_sit() gAgent.setControlFlags(gAgentAvatarp->isSitting() ? AGENT_CONTROL_STAND_UP : AGENT_CONTROL_SIT_ON_GROUND); } -class LLWorldSitOnGround : public view_listener_t +class LLWorldSitOnGround final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { toggle_sit(); return true; } }; -class LLWorldFakeAway : public view_listener_t +class LLWorldFakeAway final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - handle_fake_away_status(NULL); + handle_fake_away_status(nullptr); return true; } }; -class LLWorldEnableSitOnGround : public view_listener_t +class LLWorldEnableSitOnGround final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = (gAgentAvatarp); gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); @@ -5917,9 +5950,9 @@ class LLWorldEnableSitOnGround : public view_listener_t } }; -class LLWorldSetAway : public view_listener_t +class LLWorldSetAway final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { if (gAgent.getAFK()) { @@ -5933,9 +5966,9 @@ class LLWorldSetAway : public view_listener_t } }; -class LLWorldSetBusy : public view_listener_t +class LLWorldSetBusy final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool busy = !gAgent.isDoNotDisturb(); gAgent.setDoNotDisturb(busy); @@ -5945,9 +5978,9 @@ class LLWorldSetBusy : public view_listener_t } }; -class LLWorldCreateLandmark : public view_listener_t +class LLWorldCreateLandmark final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { // [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.4.5) | Added: RLVa-1.0.0 if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) @@ -5989,9 +6022,9 @@ class LLWorldCreateLandmark : public view_listener_t } }; -class LLToolsLookAtSelection : public view_listener_t +class LLToolsLookAtSelection final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { handle_look_at_selection(userdata); return true; @@ -6036,9 +6069,9 @@ void handle_look_at_selection(const LLSD& param) } } -class LLAvatarInviteToGroup : public view_listener_t +class LLAvatarInviteToGroup final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); // if(avatar) @@ -6052,9 +6085,9 @@ class LLAvatarInviteToGroup : public view_listener_t } }; -class LLAvatarAddFriend : public view_listener_t +class LLAvatarAddFriend final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); // if(avatar && !LLAvatarActions::isFriend(avatar->getID())) @@ -6068,9 +6101,9 @@ class LLAvatarAddFriend : public view_listener_t } }; -class LLAvatarResetSkeleton: public view_listener_t +class LLAvatarResetSkeleton final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLVOAvatar* avatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); if (avatar) @@ -6081,9 +6114,9 @@ class LLAvatarResetSkeleton: public view_listener_t } }; -class LLAvatarEnableResetSkeleton: public view_listener_t +class LLAvatarEnableResetSkeleton final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLVOAvatar* avatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); return avatar != nullptr; @@ -6091,9 +6124,9 @@ class LLAvatarEnableResetSkeleton: public view_listener_t }; -class LLAvatarResetSkeletonAndAnimations : public view_listener_t +class LLAvatarResetSkeletonAndAnimations final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLVOAvatar* avatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); if (avatar) @@ -6105,7 +6138,7 @@ class LLAvatarResetSkeletonAndAnimations : public view_listener_t }; -bool complete_give_money(const LLSD& notification, const LLSD& response, LLObjectSelectionHandle selection) +bool complete_give_money(const LLSD& notification, const LLSD& response, LLViewerObject* objectp) { S32 option = LLNotification::getSelectedOption(notification, response); if (option == 0) @@ -6113,8 +6146,6 @@ bool complete_give_money(const LLSD& notification, const LLSD& response, LLObjec gAgent.setDoNotDisturb(false); } - LLViewerObject* objectp = selection->getPrimaryObject(); - // Show avatar's name if paying attachment if (objectp && objectp->isAttachment()) { @@ -6141,10 +6172,10 @@ bool complete_give_money(const LLSD& notification, const LLSD& response, LLObjec return false; } -void handle_give_money_dialog() +void handle_give_money_dialog(LLViewerObject* obj) { LLNotification::Params params("BusyModePay"); - params.functor(boost::bind(complete_give_money, _1, _2, LLSelectMgr::getInstance()->getSelection())); + params.functor(boost::bind(complete_give_money, _1, _2, obj)); if (gAgent.isDoNotDisturb()) { @@ -6157,11 +6188,11 @@ void handle_give_money_dialog() } } -class LLPayObject : public view_listener_t +class LLPayObject final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - handle_give_money_dialog(); + handle_give_money_dialog(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); return true; } }; @@ -6170,15 +6201,14 @@ bool enable_pay_avatar() { LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); LLVOAvatar* avatar = find_avatar_from_object(obj); -// return (avatar != NULL); +// return (avatar != nullptr); // [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) | Added: RLVa-1.2.1b - return (avatar != NULL) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES) && !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS)); + return (avatar != nullptr) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES) && !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS)); // [/RLVa:KB] } -bool enable_pay_object() +bool enable_pay_object(LLViewerObject* object) { - LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); if( object ) { LLViewerObject *parent = (LLViewerObject *)object->getParent(); @@ -6237,9 +6267,9 @@ bool enable_object_sit(/*LLUICtrl* ctrl*/) return !sitting_on_sel && is_object_sittable(); } -class LLObjectEnableSitOrStand : public view_listener_t +class LLObjectEnableSitOrStand final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value; @@ -6280,11 +6310,11 @@ class LLObjectEnableSitOrStand : public view_listener_t } }; -class LLEnablePayObject : public view_listener_t +class LLEnablePayObject final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - gMenuHolder->findControl(userdata["control"].asString())->setValue(enable_pay_avatar() || enable_pay_object()); + gMenuHolder->findControl(userdata["control"].asString())->setValue(enable_pay_avatar() || enable_pay_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject())); return true; } }; @@ -6322,9 +6352,9 @@ void handle_viewer_disable_message_log(void*) // TomY TODO: Move! void show_floater(const std::string& floater_name); -class LLShowFloater : public view_listener_t +class LLShowFloater final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { show_floater(userdata.asString()); return true; @@ -6332,9 +6362,9 @@ class LLShowFloater : public view_listener_t }; bool floater_visible(const std::string& floater_name); -class LLFloaterVisible : public view_listener_t +class LLFloaterVisible final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { gMenuHolder->findControl(userdata["control"].asString())->setValue(floater_visible(userdata["data"].asString())); return true; @@ -6352,9 +6382,9 @@ bool callback_show_url(const LLSD& notification, const LLSD& response) return false; } -class LLPromptShowURL : public view_listener_t +class LLPromptShowURL final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { std::string param = userdata.asString(); std::string::size_type offset = param.find(","); @@ -6392,9 +6422,9 @@ bool callback_show_file(const LLSD& notification, const LLSD& response) return false; } -class LLPromptShowFile : public view_listener_t +class LLPromptShowFile final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { std::string param = userdata.asString(); std::string::size_type offset = param.find(","); @@ -6415,9 +6445,9 @@ class LLPromptShowFile : public view_listener_t } }; -class LLShowAgentProfile : public view_listener_t +class LLShowAgentProfile final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLUUID agent_id; if (userdata.asString() == "agent") @@ -6449,9 +6479,9 @@ class LLShowAgentProfile : public view_listener_t } }; -class LLLandEdit : public view_listener_t +class LLLandEdit final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { // [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0b) if ( (rlv_handler_t::isEnabled()) && (gRlvHandler.hasBehaviour(RLV_BHVR_EDIT)) ) @@ -6486,9 +6516,9 @@ class LLLandEdit : public view_listener_t } }; -class LLWorldEnableBuyLand : public view_listener_t +class LLWorldEnableBuyLand final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = LLViewerParcelMgr::getInstance()->canAgentBuyParcel( LLViewerParcelMgr::getInstance()->selectionEmpty() @@ -6506,9 +6536,9 @@ BOOL enable_buy_land(void*) LLViewerParcelMgr::getInstance()->getParcelSelection()->getParcel(), false); } -class LLWorldVisibleDestinations : public view_listener_t +class LLWorldVisibleDestinations final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool visible(!LFSimFeatureHandler::instance().destinationGuideURL().empty()); gMenuHolder->findControl(userdata["control"].asString())->setValue(visible); @@ -6516,23 +6546,23 @@ class LLWorldVisibleDestinations : public view_listener_t } }; -class LLObjectAttachToAvatar : public view_listener_t +class LLObjectAttachToAvatar final : public view_listener_t { public: LLObjectAttachToAvatar(bool replace) : mReplace(replace) {} static void setObjectSelection(LLObjectSelectionHandle selection) { sObjectSelection = selection; } private: - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { setObjectSelection(LLSelectMgr::getInstance()->getSelection()); LLViewerObject* selectedObject = sObjectSelection->getFirstRootObject(); if (selectedObject) { S32 index = userdata.asInteger(); - LLViewerJointAttachment* attachment_point = NULL; + LLViewerJointAttachment* attachment_point = nullptr; if (index > 0) - attachment_point = get_if_there(gAgentAvatarp->mAttachmentPoints, index, (LLViewerJointAttachment*)NULL); + attachment_point = get_if_there(gAgentAvatarp->mAttachmentPoints, index, (LLViewerJointAttachment*)nullptr); // [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.2.1f // RELEASE-RLVa: [SL-2.2.0] If 'index != 0' then the object will be "add attached" [see LLSelectMgr::sendAttach()] @@ -6541,7 +6571,7 @@ private: ((index) && ((RLV_WEAR_ADD & gRlvAttachmentLocks.canAttach(attachment_point)) == 0)) || // or non-attachable attachpt (gRlvHandler.hasBehaviour(RLV_BHVR_REZ)) ) ) // Attach on object == "Take" { - setObjectSelection(NULL); // Clear the selection or it'll get stuck + setObjectSelection(nullptr); // Clear the selection or it'll get stuck return true; } // [/RLVa:KB] @@ -6599,7 +6629,7 @@ void LLObjectAttachToAvatar::onNearAttachObject(BOOL success, void *user_data) } LLSelectMgr::getInstance()->sendAttach(attachment_id, cb_data->mReplace); } - LLObjectAttachToAvatar::setObjectSelection(NULL); + LLObjectAttachToAvatar::setObjectSelection(nullptr); delete cb_data; } @@ -6632,7 +6662,7 @@ void LLObjectAttachToAvatar::confirmReplaceAttachment(S32 option, LLViewerJointA // The callback will be called even if avatar fails to get close enough to the object, so we won't get a memory leak. CallbackData* user_data = new CallbackData(attachment_point, mReplace); - gAgent.startAutoPilotGlobal(gAgent.getPosGlobalFromAgent(walkToSpot), "Attach", NULL, onNearAttachObject, user_data, stop_distance); + gAgent.startAutoPilotGlobal(gAgent.getPosGlobalFromAgent(walkToSpot), "Attach", nullptr, onNearAttachObject, user_data, stop_distance); gAgentCamera.clearFocusObject(); } } @@ -6686,9 +6716,9 @@ void callback_attachment_drop(const LLSD& notification, const LLSD& response) return; } -class LLAttachmentDrop : public view_listener_t +class LLAttachmentDrop final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { // [RLVa:KB] - Checked: 2010-03-15 (RLVa-1.2.0e) | Modified: RLVa-1.0.5 if (rlv_handler_t::isEnabled()) @@ -6698,7 +6728,7 @@ class LLAttachmentDrop : public view_listener_t // NOTE: copy/paste of the code in enable_detach() LLObjectSelectionHandle hSelect = LLSelectMgr::getInstance()->getSelection(); RlvSelectHasLockedAttach f; - if ( (hSelect->isAttachment()) && (hSelect->getFirstRootNode(&f, FALSE) != NULL) ) + if ( (hSelect->isAttachment()) && (hSelect->getFirstRootNode(&f, FALSE) != nullptr) ) return true; } if (gRlvHandler.hasBehaviour(RLV_BHVR_REZ)) @@ -6803,9 +6833,9 @@ void detach_label(std::string& label, void* user_data) } } -class LLAttachmentDetach : public view_listener_t +class LLAttachmentDetach final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { // Called when the user clicked on an object attached to them // and selected "Detach". @@ -6845,7 +6875,7 @@ class LLAttachmentDetach : public view_listener_t { LLObjectSelectionHandle hSelect = LLSelectMgr::getInstance()->getSelection(); RlvSelectHasLockedAttach f; - if ( (hSelect->isAttachment()) && (hSelect->getFirstRootNode(&f, FALSE) != NULL) ) + if ( (hSelect->isAttachment()) && (hSelect->getFirstRootNode(&f, FALSE) != nullptr) ) return true; } // [/RLVa:KB] @@ -6858,7 +6888,7 @@ class LLAttachmentDetach : public view_listener_t //Adding an observer for a Jira 2422 and needs to be a fetch observer //for Jira 3119 -class LLWornItemFetchedObserver : public LLInventoryFetchItemsObserver +class LLWornItemFetchedObserver final : public LLInventoryFetchItemsObserver { public: LLWornItemFetchedObserver(const LLUUID& worn_item_id) : @@ -6876,9 +6906,9 @@ protected: }; // You can only drop items on parcels where you can build. -class LLAttachmentEnableDrop : public view_listener_t +class LLAttachmentEnableDrop final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { BOOL can_build = gAgent.isGodlike() || (LLViewerParcelMgr::getInstance()->allowAgentBuild()); @@ -6893,14 +6923,14 @@ class LLAttachmentEnableDrop : public view_listener_t // item is in your inventory LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - LLViewerJointAttachment* attachment = NULL; - LLInventoryItem* item = NULL; + LLViewerJointAttachment* attachment = nullptr; + LLInventoryItem* item = nullptr; // Do not enable drop if all faces of object are not enabled if (object && LLSelectMgr::getInstance()->getSelection()->contains(object,SELECT_ALL_TES )) { S32 attachmentID = ATTACHMENT_ID_FROM_STATE(object->getAttachmentState()); - attachment = get_if_there(gAgentAvatarp->mAttachmentPoints, attachmentID, (LLViewerJointAttachment*)NULL); + attachment = get_if_there(gAgentAvatarp->mAttachmentPoints, attachmentID, (LLViewerJointAttachment*)nullptr); if (attachment) { @@ -6962,7 +6992,7 @@ BOOL enable_detach(const LLSD&) { LLObjectSelectionHandle hSelect = LLSelectMgr::getInstance()->getSelection(); RlvSelectHasLockedAttach f; - if ( (hSelect->isAttachment()) && (hSelect->getFirstRootNode(&f, FALSE) != NULL) ) + if ( (hSelect->isAttachment()) && (hSelect->getFirstRootNode(&f, FALSE) != nullptr) ) return FALSE; } // [/RLVa:KB] @@ -6975,9 +7005,9 @@ BOOL enable_detach(const LLSD&) return FALSE; } -class LLAttachmentEnableDetach : public view_listener_t +class LLAttachmentEnableDetach final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = enable_detach(); gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); @@ -6996,8 +7026,8 @@ BOOL object_selected_and_point_valid(void *user_data) // RELEASE-RLVa: look at the caller graph for this function on every new release // -> 1.22.11 and 1.23.4 - // - object_is_wearable() => dead code [user_data == NULL => default attach point => OK!] - // - LLObjectEnableWear::handleEvent() => Rezzed prim / right-click / "Wear" [user_data == NULL => see above] + // - object_is_wearable() => dead code [user_data == nullptr => default attach point => OK!] + // - LLObjectEnableWear::handleEvent() => Rezzed prim / right-click / "Wear" [user_data == nullptr => see above] // - enabler set up in LLVOAvatar::buildCharacter() => Rezzed prim / right-click / "Attach >" [user_data == pAttachPt] // - enabler set up in LLVOAvatar::buildCharacter() => Rezzed prim / Edit menu / "Attach Object" [user_data == pAttachPt] const LLViewerJointAttachment* pAttachPt = (const LLViewerJointAttachment*)user_data; @@ -7033,7 +7063,7 @@ BOOL object_selected_and_point_valid(void *user_data) selection->getFirstRootObject()->permYouOwner() && !selection->getFirstRootObject()->flagObjectPermanent() && !((LLViewerObject*)selection->getFirstRootObject()->getRoot())->isAvatar() && - (selection->getFirstRootObject()->getNVPair("AssetContainer") == NULL); + (selection->getFirstRootObject()->getNVPair("AssetContainer") == nullptr); } @@ -7041,7 +7071,7 @@ BOOL object_selected_and_point_valid(void *user_data) /* BOOL object_is_wearable() { - if (!object_selected_and_point_valid(NULL)) + if (!object_selected_and_point_valid(nullptr)) { return FALSE; } @@ -7066,11 +7096,11 @@ BOOL object_is_wearable() // Also for seeing if object can be attached. See above. -class LLObjectEnableWear : public view_listener_t +class LLObjectEnableWear final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - bool is_wearable = object_selected_and_point_valid(NULL); + bool is_wearable = object_selected_and_point_valid(nullptr); gMenuHolder->findControl(userdata["control"].asString())->setValue(is_wearable); return TRUE; } @@ -7090,9 +7120,9 @@ BOOL object_attached(void *user_data) // return attachment->getNumObjects() > 0; } -class LLAvatarSendIM : public view_listener_t +class LLAvatarSendIM final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); // if(avatar) @@ -7108,14 +7138,18 @@ class LLAvatarSendIM : public view_listener_t namespace { - struct QueueObjects : public LLSelectedObjectFunctor + struct QueueObjects final : public LLSelectedObjectFunctor { BOOL scripted; BOOL modifiable; LLFloaterScriptQueue* mQueue; QueueObjects(LLFloaterScriptQueue* q) : mQueue(q), scripted(FALSE), modifiable(FALSE) {} - virtual bool apply(LLViewerObject* obj) + bool apply(LLViewerObject* obj) override { + if (!obj) + { + return true; + } scripted = obj->flagScripted(); modifiable = obj->permModify(); @@ -7164,9 +7198,9 @@ void queue_actions(LLFloaterScriptQueue* q, const std::string& msg) } } -class LLToolsSelectedScriptAction : public view_listener_t +class LLToolsSelectedScriptAction final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { // [RLVa:KB] - Checked: 2010-04-19 (RLVa-1.2.0f) | Modified: RLVa-1.0.5a // We'll allow resetting the scripts of objects on a non-attachable attach point since they wouldn't be able to circumvent anything @@ -7174,13 +7208,13 @@ class LLToolsSelectedScriptAction : public view_listener_t { LLObjectSelectionHandle hSel = LLSelectMgr::getInstance()->getSelection(); RlvSelectHasLockedAttach f; - if ( (hSel->isAttachment()) && (hSel->getFirstNode(&f) != NULL) ) + if ( (hSel->isAttachment()) && (hSel->getFirstNode(&f) != nullptr) ) return true; } // [/RLVa:KB] std::string action = userdata.asString(); - LLFloaterScriptQueue* queue = NULL; + LLFloaterScriptQueue* queue = nullptr; std::string msg; if (action == "compile mono") { @@ -7327,7 +7361,7 @@ void handle_toggle_pg(void*) { gAgent.setTeen( !gAgent.isTeen() ); - LLFloaterWorldMap::reloadIcons(NULL); + LLFloaterWorldMap::reloadIcons(nullptr); LL_INFOS() << "PG status set to " << gAgent.isTeen() << LL_ENDL; } @@ -7347,7 +7381,7 @@ void handle_dump_attachments(void*) ++attachment_iter) { LLViewerObject *attached_object = (*attachment_iter); - BOOL visible = (attached_object != NULL && + BOOL visible = (attached_object != nullptr && attached_object->mDrawable.notNull() && !attached_object->mDrawable->isRenderType(0)); LLVector3 pos; @@ -7389,9 +7423,9 @@ void menu_toggle_double_click_control(void* user_data) // these are used in the gl menus to set control values, generically. -class LLToggleControl : public view_listener_t +class LLToggleControl final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLControlVariable* control(gSavedSettings.getControl(userdata.asString())); control->set(!control->get()); @@ -7399,9 +7433,9 @@ class LLToggleControl : public view_listener_t } }; -class LLTogglePerAccountControl : public view_listener_t +class LLTogglePerAccountControl final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLControlVariable* control(gSavedPerAccountSettings.getControl(userdata.asString())); control->set(!control->get()); @@ -7444,9 +7478,9 @@ void menu_toggle_attached_particles(void* user_data) LLPipeline::sRenderAttachedParticles = gSavedSettings.getBOOL("RenderAttachedParticles"); } -class LLSomethingSelected : public view_listener_t +class LLSomethingSelected final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = !(LLSelectMgr::getInstance()->getSelection()->isEmpty()); gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); @@ -7454,9 +7488,9 @@ class LLSomethingSelected : public view_listener_t } }; -class LLSomethingSelectedNoHUD : public view_listener_t +class LLSomethingSelectedNoHUD final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); bool new_value = !(selection->isEmpty()) && !(selection->getSelectType() == SELECT_TYPE_HUD); @@ -7488,21 +7522,21 @@ static bool is_editable_selected() } // [/RLVa:KB] - return (LLSelectMgr::getInstance()->getSelection()->getFirstEditableObject() != NULL); + return (LLSelectMgr::getInstance()->getSelection()->getFirstEditableObject() != nullptr); } -class LLEditableSelected : public view_listener_t +class LLEditableSelected final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { gMenuHolder->findControl(userdata["control"].asString())->setValue(is_editable_selected()); return true; } }; -class LLEditableSelectedMono : public view_listener_t +class LLEditableSelectedMono final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLViewerRegion* region = gAgent.getRegion(); if(region && gMenuHolder && gMenuHolder->findControl(userdata["control"].asString())) @@ -7516,9 +7550,9 @@ class LLEditableSelectedMono : public view_listener_t } }; -class LLToolsEnableTakeCopy : public view_listener_t +class LLToolsEnableTakeCopy final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { gMenuHolder->findControl(userdata["control"].asString())->setValue(enable_object_take_copy()); return true; @@ -7539,9 +7573,9 @@ bool enable_object_take_copy() || !gAgent.isGodlike()) # endif { - struct f : public LLSelectedObjectFunctor + struct f final : public LLSelectedObjectFunctor { - virtual bool apply(LLViewerObject* obj) + bool apply(LLViewerObject* obj) override { // return (!obj->permCopy() || obj->isAttachment()); // [RLVa:KB] - Checked: 2010-04-01 (RLVa-1.2.0c) | Modified: RLVa-1.0.0g @@ -7562,17 +7596,17 @@ bool enable_object_take_copy() } // -class LLToolsEnableAdminDelete : public view_listener_t +class LLToolsEnableAdminDelete final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - return (object != NULL); + return (object != nullptr); } }; -class LLToolsAdminDelete : public view_listener_t +class LLToolsAdminDelete final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLSelectMgr::getInstance()->selectForceDelete(); return true; @@ -7584,9 +7618,9 @@ BOOL enable_selection_you_own_all(void*) { if (LLSelectMgr::getInstance()) { - struct f : public LLSelectedObjectFunctor + struct f final : public LLSelectedObjectFunctor { - virtual bool apply(LLViewerObject* obj) + bool apply(LLViewerObject* obj) override { return (!obj->permYouOwner()); } @@ -7605,9 +7639,9 @@ BOOL enable_selection_you_own_one(void*) { if (LLSelectMgr::getInstance()) { - struct f : public LLSelectedObjectFunctor + struct f final : public LLSelectedObjectFunctor { - virtual bool apply(LLViewerObject* obj) + virtual bool apply(LLViewerObject* obj) override { return (obj->permYouOwner()); } @@ -7622,7 +7656,7 @@ BOOL enable_selection_you_own_one(void*) return TRUE; } -class LLHasAsset : public LLInventoryCollectFunctor +class LLHasAsset final : public LLInventoryCollectFunctor { public: LLHasAsset(const LLUUID& id) : mAssetID(id), mHasAsset(FALSE) {} @@ -7650,7 +7684,7 @@ bool enable_save_into_inventory() { // *TODO: clean this up // find the last root - LLSelectNode* last_node = NULL; + LLSelectNode* last_node = nullptr; for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin(); iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++) { @@ -7670,7 +7704,7 @@ bool enable_save_into_inventory() // check all pre-req's for save into inventory. if(last_node && last_node->mValid && !last_node->mItemID.isNull() && (last_node->mPermissions->getOwner() == gAgent.getID()) - && (gInventory.getItem(last_node->mItemID) != NULL)) + && (gInventory.getItem(last_node->mItemID) != nullptr)) { LLViewerObject* obj = last_node->getObject(); if( obj && !obj->isAttachment() ) @@ -7697,20 +7731,20 @@ BOOL enable_save_into_task_inventory(void*) return FALSE; } -class LLToolsEnableSaveToObjectInventory : public view_listener_t +class LLToolsEnableSaveToObjectInventory final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - bool new_value = enable_save_into_task_inventory(NULL); + bool new_value = enable_save_into_task_inventory(nullptr); gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); return true; } }; -class LLViewEnableMouselook : public view_listener_t +class LLViewEnableMouselook final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { // You can't go directly from customize avatar to mouselook. // TODO: write code with appropriate dialogs to handle this transition. @@ -7720,9 +7754,9 @@ class LLViewEnableMouselook : public view_listener_t } }; -class LLToolsEnableToolNotPie : public view_listener_t +class LLToolsEnableToolNotPie final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = ( LLToolMgr::getInstance()->getBaseTool() != LLToolPie::getInstance() ); gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); @@ -7730,9 +7764,9 @@ class LLToolsEnableToolNotPie : public view_listener_t } }; -class LLWorldEnableCreateLandmark : public view_listener_t +class LLWorldEnableCreateLandmark final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = gAgent.isGodlike() || (gAgent.getRegion() && gAgent.getRegion()->getAllowLandmark()); @@ -7744,9 +7778,9 @@ class LLWorldEnableCreateLandmark : public view_listener_t } }; -class LLWorldEnableSetHomeLocation : public view_listener_t +class LLWorldEnableSetHomeLocation final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = gAgent.isGodlike() || (gAgent.getRegion() && gAgent.getRegion()->getAllowSetHome()); @@ -7755,9 +7789,9 @@ class LLWorldEnableSetHomeLocation : public view_listener_t } }; -class LLWorldEnableTeleportHome : public view_listener_t +class LLWorldEnableTeleportHome final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLViewerRegion* regionp = gAgent.getRegion(); bool agent_on_prelude = (regionp && regionp->isPrelude()); @@ -7802,9 +7836,9 @@ BOOL check_show_xui_names(void *) return gSavedSettings.getBOOL("ShowXUINames"); } -class LLToolsSelectOnlyMyObjects : public view_listener_t +class LLToolsSelectOnlyMyObjects final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { BOOL cur_val = gSavedSettings.getBOOL("SelectOwnedOnly"); @@ -7814,9 +7848,9 @@ class LLToolsSelectOnlyMyObjects : public view_listener_t } }; -class LLToolsSelectOnlyMovableObjects : public view_listener_t +class LLToolsSelectOnlyMovableObjects final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { BOOL cur_val = gSavedSettings.getBOOL("SelectMovableOnly"); @@ -7826,9 +7860,9 @@ class LLToolsSelectOnlyMovableObjects : public view_listener_t } }; -class LLToolsSelectBySurrounding : public view_listener_t +class LLToolsSelectBySurrounding final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLSelectMgr::sRectSelectInclusive = !LLSelectMgr::sRectSelectInclusive; @@ -7837,9 +7871,9 @@ class LLToolsSelectBySurrounding : public view_listener_t } }; -class LLToolsShowSelectionHighlights : public view_listener_t +class LLToolsShowSelectionHighlights final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLControlVariable *ctrl = gSavedSettings.getControl("RenderHighlightSelections"); ctrl->setValue(!ctrl->getValue().asBoolean()); @@ -7847,9 +7881,9 @@ class LLToolsShowSelectionHighlights : public view_listener_t } }; -class LLToolsShowHiddenSelection : public view_listener_t +class LLToolsShowHiddenSelection final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { // TomY TODO Merge these LLSelectMgr::sRenderHiddenSelections = !LLSelectMgr::sRenderHiddenSelections; @@ -7859,9 +7893,9 @@ class LLToolsShowHiddenSelection : public view_listener_t } }; -class LLToolsShowSelectionLightRadius : public view_listener_t +class LLToolsShowSelectionLightRadius final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { // TomY TODO merge these LLSelectMgr::sRenderLightRadius = !LLSelectMgr::sRenderLightRadius; @@ -7871,9 +7905,9 @@ class LLToolsShowSelectionLightRadius : public view_listener_t } }; -class LLToolsEditLinkedParts : public view_listener_t +class LLToolsEditLinkedParts final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { BOOL select_individuals = gSavedSettings.getBOOL("EditLinkedParts"); if (select_individuals) @@ -7999,11 +8033,10 @@ void init_meshes_and_morphs_menu() lod_menu->addSeparator(); - for(LLPolyMesh::morph_list_t::iterator morph_iter = morph_list.begin(); - morph_iter != morph_list.end(); ++morph_iter) + for(auto& morph : morph_list) { - std::string const& morph_name = morph_iter->first; - LLPolyMorphData* morph_data = morph_iter->second; + std::string const& morph_name = morph.first; + LLPolyMorphData* morph_data = morph.second; action_menu = new LLMenuGL(morph_name); @@ -8033,7 +8066,7 @@ void handle_mesh_save_llm(void* data) if (!mesh_name) { - LL_WARNS() << "LPolyMesh::getSharedMeshName returned NULL" << LL_ENDL; + LL_WARNS() << "LPolyMesh::getSharedMeshName returned nullptr" << LL_ENDL; return; } @@ -8106,7 +8139,7 @@ void handle_mesh_save_current_obj(void* data) if (!mesh_name) { - LL_WARNS() << "LPolyMesh::getSharedMeshName returned NULL" << LL_ENDL; + LL_WARNS() << "LPolyMesh::getSharedMeshName returned nullptr" << LL_ENDL; return; } @@ -8155,7 +8188,7 @@ void handle_mesh_save_obj(void* data) if (!mesh_name) { - LL_WARNS() << "LPolyMesh::getSharedMeshName returned NULL" << LL_ENDL; + LL_WARNS() << "LPolyMesh::getSharedMeshName returned nullptr" << LL_ENDL; return; } @@ -8187,7 +8220,7 @@ static void handle_mesh_save_obj_continued(void* data, AIFilePicker* filepicker) return; } - LLPolyMesh mesh(mesh_shared,NULL); + LLPolyMesh mesh(mesh_shared,nullptr); mesh.saveOBJ(fp); fclose(fp); } @@ -8201,7 +8234,7 @@ void handle_mesh_load_obj(void* data) if (!mesh_name) { - LL_WARNS() << "LPolyMesh::getSharedMeshName returned NULL" << LL_ENDL; + LL_WARNS() << "LPolyMesh::getSharedMeshName returned nullptr" << LL_ENDL; return; } @@ -8230,7 +8263,7 @@ static void handle_mesh_load_obj_continued(void* data, AIFilePicker* filepicker) return; } - LLPolyMesh mesh(mesh_shared,NULL); + LLPolyMesh mesh(mesh_shared,nullptr); mesh.loadOBJ(fp); mesh.setSharedFromCurrent(); fclose(fp); @@ -8246,7 +8279,7 @@ void handle_morph_save_obj(void* data) if (!mesh_name) { - LL_WARNS() << "LPolyMesh::getSharedMeshName returned NULL" << LL_ENDL; + LL_WARNS() << "LPolyMesh::getSharedMeshName returned nullptr" << LL_ENDL; return; } @@ -8294,7 +8327,7 @@ void handle_morph_load_obj(void* data) if (!mesh_name) { - LL_WARNS() << "LPolyMesh::getSharedMeshName returned NULL" << LL_ENDL; + LL_WARNS() << "LPolyMesh::getSharedMeshName returned nullptr" << LL_ENDL; return; } @@ -8325,7 +8358,7 @@ static void handle_morph_load_obj_continued(void* data, AIFilePicker* filepicker return; } - LLPolyMesh mesh(mesh_shared,NULL); + LLPolyMesh mesh(mesh_shared,nullptr); mesh.loadOBJ(fp); fclose(fp); @@ -8333,7 +8366,7 @@ static void handle_morph_load_obj_continued(void* data, AIFilePicker* filepicker } // Returns a pointer to the avatar give the UUID of the avatar OR of an attachment the avatar is wearing. -// Returns NULL on failure. +// Returns nullptr on failure. LLVOAvatar* find_avatar_from_object( LLViewerObject* object ) { if (object) @@ -8348,7 +8381,7 @@ LLVOAvatar* find_avatar_from_object( LLViewerObject* object ) } else if( !object->isAvatar() ) { - object = NULL; + object = nullptr; } } @@ -8357,7 +8390,7 @@ LLVOAvatar* find_avatar_from_object( LLViewerObject* object ) // Returns a pointer to the avatar give the UUID of the avatar OR of an attachment the avatar is wearing. -// Returns NULL on failure. +// Returns nullptr on failure. LLVOAvatar* find_avatar_from_object( const LLUUID& object_id ) { return find_avatar_from_object( gObjectList.findObject(object_id) ); @@ -8399,14 +8432,14 @@ void force_error_driver_crash(void *) LLAppViewer::instance()->forceErrorDriverCrash(); } -class LLToolsUseSelectionForGrid : public view_listener_t +class LLToolsUseSelectionForGrid final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLSelectMgr::getInstance()->clearGridObjects(); - struct f : public LLSelectedObjectFunctor + struct f final : public LLSelectedObjectFunctor { - virtual bool apply(LLViewerObject* objectp) + bool apply(LLViewerObject* objectp) override { LLSelectMgr::getInstance()->addGridObject(objectp); return true; @@ -8449,8 +8482,8 @@ BOOL LLViewerMenuHolderGL::hideMenus() } // drop pie menu selection - mParcelSelection = NULL; - mObjectSelection = NULL; + mParcelSelection = nullptr; + mObjectSelection = nullptr; if (gMenuBarView) { @@ -8564,6 +8597,7 @@ void handle_rebake_textures(void*) { LLAppearanceMgr::instance().requestServerAppearanceUpdate(); } + gAgent.setIsCrossingRegion(false); // Attachments getting lost on TP } void toggle_visibility(void* user_data) @@ -8579,18 +8613,18 @@ BOOL get_visibility(void* user_data) } // TomY TODO: Get rid of these? -class LLViewShowHoverTips : public view_listener_t +class LLViewShowHoverTips final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLHoverView::sShowHoverTips = !LLHoverView::sShowHoverTips; return true; } }; -class LLViewCheckShowHoverTips : public view_listener_t +class LLViewCheckShowHoverTips final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = LLHoverView::sShowHoverTips; gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); @@ -8599,9 +8633,9 @@ class LLViewCheckShowHoverTips : public view_listener_t }; // TomY TODO: Get rid of these? -class LLViewHighlightTransparent : public view_listener_t +class LLViewHighlightTransparent final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { // [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Modified: RLVa-1.0.0b | OK if ( (gRlvHandler.hasBehaviour(RLV_BHVR_EDIT)) && (!LLDrawPoolAlpha::sShowDebugAlpha)) @@ -8613,9 +8647,9 @@ class LLViewHighlightTransparent : public view_listener_t } }; -class LLViewCheckHighlightTransparent : public view_listener_t +class LLViewCheckHighlightTransparent final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = LLDrawPoolAlpha::sShowDebugAlpha; gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); @@ -8623,9 +8657,9 @@ class LLViewCheckHighlightTransparent : public view_listener_t } }; -class LLViewToggleRenderType : public view_listener_t +class LLViewToggleRenderType final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { std::string type = userdata.asString(); if (type == "hideparticles") @@ -8636,9 +8670,9 @@ class LLViewToggleRenderType : public view_listener_t } }; -class LLViewCheckRenderType : public view_listener_t +class LLViewCheckRenderType final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { std::string type = userdata["data"].asString(); bool new_value = false; @@ -8651,9 +8685,9 @@ class LLViewCheckRenderType : public view_listener_t } }; -class LLViewShowHUDAttachments : public view_listener_t +class LLViewShowHUDAttachments final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { // [RLVa:KB] - Checked: 2010-04-19 (RLVa-1.2.1a) | Modified: RLVa-1.0.0c if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedHUD()) && (LLPipeline::sShowHUDAttachments) ) @@ -8665,9 +8699,9 @@ class LLViewShowHUDAttachments : public view_listener_t } }; -class LLViewCheckHUDAttachments : public view_listener_t +class LLViewCheckHUDAttachments final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = LLPipeline::sShowHUDAttachments; gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); @@ -8675,9 +8709,9 @@ class LLViewCheckHUDAttachments : public view_listener_t } }; -class LLEditEnableTakeOff : public view_listener_t +class LLEditEnableTakeOff final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = false; std::string control_name = userdata["control"].asString(); @@ -8697,9 +8731,9 @@ class LLEditEnableTakeOff : public view_listener_t } }; -class LLEditTakeOff : public view_listener_t +class LLEditTakeOff final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { std::string clothing = userdata.asString(); if (clothing == "all") @@ -8737,9 +8771,9 @@ class LLEditTakeOff : public view_listener_t } }; -class LLToolsSelectTool : public view_listener_t +class LLToolsSelectTool final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { std::string tool_name = userdata.asString(); if (tool_name == "focus") @@ -8767,9 +8801,9 @@ class LLToolsSelectTool : public view_listener_t }; /// WINDLIGHT callbacks -class LLWorldEnvSettings : public view_listener_t +class LLWorldEnvSettings final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { // [RLVa:KB] - Checked: 2010-03-18 (RLVa-1.2.0a) | Modified: RLVa-1.0.0g if (gRlvHandler.hasBehaviour(RLV_BHVR_SETENV)) @@ -8803,9 +8837,9 @@ class LLWorldEnvSettings : public view_listener_t } }; -class LLWorldEnableEnvSettings : public view_listener_t +class LLWorldEnableEnvSettings final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool result = false; std::string tod = userdata.asString(); @@ -8842,56 +8876,56 @@ class LLWorldEnableEnvSettings : public view_listener_t } }; -class SinguCloseAllDialogs : public view_listener_t +class SinguCloseAllDialogs final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { gNotifyBoxView->deleteAllChildren(); return true; } }; -class SinguEnableStreamingAudioDisplay : public view_listener_t +class SinguEnableStreamingAudioDisplay final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - return handle_ticker_enabled(NULL); + return handle_ticker_enabled(nullptr); } }; -class SinguPoseStand : public view_listener_t +class SinguPoseStand final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { if (current_pose.isNull()) set_current_pose("038fcec9-5ebd-8a8e-0e2e-6e71a0a1ac53"); else - handle_pose_stand_stop(NULL); + handle_pose_stand_stop(nullptr); return true; } }; -class SinguCheckPoseStand : public view_listener_t +class SinguCheckPoseStand final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - gMenuHolder->findControl(userdata["control"].asString())->setValue(handle_check_pose(NULL)); + gMenuHolder->findControl(userdata["control"].asString())->setValue(handle_check_pose(nullptr)); return true; } }; -class SinguRebake : public view_listener_t +class SinguRebake final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - handle_rebake_textures(NULL); + handle_rebake_textures(nullptr); return true; } }; -class SinguVisibleDebugConsole : public view_listener_t +class SinguVisibleDebugConsole final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLViewerRegion* region = gAgent.getRegion(); gMenuHolder->findControl(userdata["control"].asString())->setValue(region && !(region->getCapability("SimConsoleAsync").empty() || region->getCapability("SimConsole").empty())); @@ -8899,9 +8933,9 @@ class SinguVisibleDebugConsole : public view_listener_t } }; -class SinguUrlAction : public view_listener_t +class SinguUrlAction final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLUrlAction::clickAction(userdata.asStringRef(), true); return true; @@ -8918,54 +8952,54 @@ static void visible_inv_floater(const LLSD& userdata, const std::string& field) gMenuHolder->findControl(userdata["control"].asString())->setValue(!!LFFloaterInvPanel::getInstance(LLSD().with(field, userdata["data"]))); } -class ShowInvFloaterID : public view_listener_t +class ShowInvFloaterID final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { show_inv_floater(userdata, "id"); return true; } }; -class VisibleInvFloaterID : public view_listener_t +class VisibleInvFloaterID final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { visible_inv_floater(userdata, "id"); return true; } }; -class ShowInvFloaterName : public view_listener_t +class ShowInvFloaterName final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { show_inv_floater(userdata, "name"); return true; } }; -class VisibleInvFloaterName : public view_listener_t +class VisibleInvFloaterName final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { visible_inv_floater(userdata, "name"); return true; } }; -class ShowInvFloaterType : public view_listener_t +class ShowInvFloaterType final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { show_inv_floater(userdata, "type"); return true; } }; -class VisibleInvFloaterType : public view_listener_t +class VisibleInvFloaterType final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { visible_inv_floater(userdata, "type"); return true; @@ -8994,27 +9028,27 @@ void show_web_floater(const std::string& type) LLFloaterWebContent::showInstance(type, p); } -class ShowWebFloater : public view_listener_t +class ShowWebFloater final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { show_web_floater(userdata.asStringRef()); return true; } }; -class VisibleSecondLife : public view_listener_t +class VisibleSecondLife final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { gMenuHolder->findControl(userdata["control"].asString())->setValue(gHippoGridManager->getCurrentGrid()->isSecondLife()); return true; } }; -class VisibleNotSecondLife : public view_listener_t +class VisibleNotSecondLife final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { gMenuHolder->findControl(userdata["control"].asString())->setValue(!gHippoGridManager->getConnectedGrid()->isSecondLife()); return true; @@ -9034,97 +9068,199 @@ template T* get_focused() return t; } -const LLWString get_slurl_for(const LLUUID& id, bool group) +const JCFloaterAreaSearch::ObjectData* get_obj_data(const LLUUID& id) { - std::string str("secondlife:///app/"); - str += group ? "group/" : "agent/"; - return utf8str_to_wstring(str + id.asString() + "/about"); + auto areasearch = JCFloaterAreaSearch::findInstance(); + return areasearch ? areasearch->getObjectData(id) : nullptr; } -void copy_profile_uri(const LLUUID& id, bool group) +const LLUUID& get_obj_owner(const LLUUID& id, const JCFloaterAreaSearch::ObjectData* obj_data = nullptr, const LLViewerObject* objp = nullptr) { - gViewerWindow->getWindow()->copyTextToClipboard(get_slurl_for(id, group)); + if (const auto& obj = objp ? objp : gObjectList.findObject(id)) // Viewer Object is more likely to be up to date + return obj->mOwnerID; + if (const auto& obj = obj_data ? obj_data : get_obj_data(id)) // Fall back on Object Data + return obj->owner_id; + return LLUUID::null; } -class ListEnableAnySelected : public view_listener_t +const std::string get_obj_owner_slurl(const LLUUID& obj_id, const std::string& name = LLStringUtil::null, bool* group_ownedp = nullptr) { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool group_owned; + LLUUID owner; + if (!group_ownedp) { - gMenuHolder->findControl(userdata["control"].asString())->setValue(LFIDBearer::getActiveNumSelected()); + if (const auto& obj = gObjectList.findObject(obj_id)) // Viewer Object is more likely to be up to date + { + owner = obj->mOwnerID; + group_owned = obj->flagObjectGroupOwned(); + } + else if (const auto& obj = get_obj_data(obj_id)) // Fall back on Object Data + { + owner = obj->owner_id; + group_owned = owner == obj->group_id; + } + else return name; + } + else + { + owner = get_obj_owner(obj_id); + group_owned = *group_ownedp; + } + return owner.isNull() ? name + : group_owned ? LLGroupActions::getSLURL(owner) + : LLAvatarActions::getSLURL(owner); +} + +const std::string get_obj_slurl(const LLUUID& id, const std::string& name = LLStringUtil::null) +{ + const auto& obj_data = get_obj_data(id); // Needed for object name + const auto& obj = gObjectList.findObject(id); // Has all the other object data + if (!obj_data && !obj && name.empty()) + return name; // Not enough data to show, empty string to show failure, if we had a name we could pair it with the ID at least + + LLSD sdQuery; + + sdQuery["name"] = !name.empty() ? name : + obj_data ? obj_data->name : LLTrans::getString("land_type_unknown"); + + const auto& owner = get_obj_owner(id, obj_data, obj); + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES) && (owner != gAgentID)) + sdQuery["rlv_shownames"] = true; + + sdQuery["owner"] = owner; + sdQuery["group_owned"] = obj ? obj->flagObjectGroupOwned() : obj_data && obj_data->group_id == owner; + + if (const auto region = obj ? obj->getRegion() : nullptr) + sdQuery["slurl"] = LLSLURL(region->getName(), obj->getPositionAgent()).getLocationString(); + + return LLSLURL("objectim", id, LLURI::mapToQueryString(sdQuery)).getSLURLString(); +} + +const std::string get_slurl_for(const LLUUID& id, const LFIDBearer::Type& type) +{ + switch (type) + { + case LFIDBearer::GROUP: return LLGroupActions::getSLURL(id); + case LFIDBearer::AVATAR: return LLAvatarActions::getSLURL(id); + case LFIDBearer::OBJECT: return get_obj_slurl(id); + case LFIDBearer::EXPERIENCE: return LLSLURL("experience", id, "profile").getSLURLString(); + default: return LLStringUtil::null; + } +} + +const LLWString get_wslurl_for(const LLUUID& id, const LFIDBearer::Type& type) +{ + return utf8str_to_wstring(get_slurl_for(id, type)); +} + +void copy_profile_uri(const LLUUID& id, const LFIDBearer::Type& type) +{ + gViewerWindow->getWindow()->copyTextToClipboard(get_wslurl_for(id, type)); +} + +class ListEnableAnySelected final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + gMenuHolder->findControl(userdata["control"].asString())->setValue(LFIDBearer::getActiveNumSelected() != 0); return true; } }; -class ListEnableMultipleSelected : public view_listener_t +class ListEnableMultipleSelected final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { gMenuHolder->findControl(userdata["control"].asString())->setValue(LFIDBearer::getActiveNumSelected() > 1); return true; } }; -class ListEnableSingleSelected : public view_listener_t +class ListEnableSingleSelected final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { gMenuHolder->findControl(userdata["control"].asString())->setValue(LFIDBearer::getActiveNumSelected() == 1); return true; } }; -class ListEnableCall : public view_listener_t +class ListEnableCall final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { gMenuHolder->findControl(userdata["control"].asString())->setValue(LLAvatarActions::canCall()); return true; } }; -class ListEnableIsFriend : public view_listener_t +class ListEnableIsFriend final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { gMenuHolder->findControl(userdata["control"].asString())->setValue(LLAvatarActions::isFriend(LFIDBearer::getActiveSelectedID())); return true; } }; -class ListEnableIsNotFriend : public view_listener_t +class ListEnableIsNotFriend final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { gMenuHolder->findControl(userdata["control"].asString())->setValue(!LLAvatarActions::isFriend(LFIDBearer::getActiveSelectedID())); return true; } }; -class ListEnableMute : public view_listener_t +class ListEnableUnmute final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - const uuid_vec_t& ids = LFIDBearer::getActiveSelectedIDs(); - bool can_block = true; - for (uuid_vec_t::const_iterator it = ids.begin(); can_block && it != ids.end(); ++it) - can_block = LLAvatarActions::canBlock(*it); - gMenuHolder->findControl(userdata["control"].asString())->setValue(can_block); + bool are_blocked = false; + for (const auto& id : LFIDBearer::getActiveSelectedIDs()) + if (are_blocked = LLAvatarActions::isBlocked(id)) // If any are blocked, allow unblocking + break; + + gMenuHolder->findControl(userdata["control"].asString())->setValue(are_blocked); return true; } }; -class ListEnableOfferTeleport : public view_listener_t +class ListEnableMute final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + bool blockable = false; + for (const auto& id : LFIDBearer::getActiveSelectedIDs()) + { + if (!LLAvatarActions::canBlock(id)) // Exit early only when someone is unblockable + { + blockable = false; + break; + } + else if (blockable) // At least one is unblocked, keep looking for unblockables + continue; + + blockable = !LLAvatarActions::isBlocked(id); + } + + gMenuHolder->findControl(userdata["control"].asString())->setValue(blockable); + return true; + } +}; + +class ListEnableOfferTeleport final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override { gMenuHolder->findControl(userdata["control"].asString())->setValue(LLAvatarActions::canOfferTeleport(LFIDBearer::getActiveSelectedIDs())); return true; } }; -class ListVisibleWebProfile : public view_listener_t +class ListVisibleWebProfile final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { gMenuHolder->findControl(userdata["control"].asString())->setValue(LFIDBearer::getActiveNumSelected() && !(gSavedSettings.getBOOL("UseWebProfiles") || gSavedSettings.getString("WebProfileURL").empty())); return true; @@ -9132,92 +9268,158 @@ class ListVisibleWebProfile : public view_listener_t }; void ban_from_group(const uuid_vec_t& ids); -class ListBanFromGroup : public view_listener_t +class ListBanFromGroup final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { ban_from_group(LFIDBearer::getActiveSelectedIDs()); return true; } }; -class ListCopySLURL : public view_listener_t +void copy_from_ids(const uuid_vec_t & ids, std::function func); + +uuid_vec_t get_active_owner_ids() { - bool handleEvent(LLPointer event, const LLSD& userdata) + uuid_vec_t ret; + for (const auto& id : LFIDBearer::getActiveSelectedIDs()) { - copy_profile_uri(LFIDBearer::getActiveSelectedID(), false); + const auto& owner_id = get_obj_owner(id); + if (owner_id.notNull()) ret.push_back(owner_id); + } + return ret; +} + +const LLUUID& get_active_owner_id() +{ + return get_obj_owner(LFIDBearer::getActiveSelectedID()); +} + +class ListCopyNames final : public view_listener_t +{ + static std::string getGroupName(const LLUUID& id) + { + std::string ret; + gCacheName->getGroupName(id, ret); + return ret; + } + + static std::string getAvatarName(const LLUUID& id) + { + std::string ret; + LLAvatarNameCache::getNSName(id, ret); + return ret; + } + + static std::string getObjectName(const LLUUID& id) + { + const auto& obj_data = get_obj_data(id); + return obj_data ? obj_data->name : LLStringUtil::null; + } + + static std::string getExperienceName(const LLUUID& id) + { + return LLExperienceCache::instance().get(id)[LLExperienceCache::NAME]; + } + + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + LLWString str; + const auto& type = LFIDBearer::getActiveType(); + bool owner = !userdata.asBoolean(); + copy_from_ids(owner ? get_active_owner_ids() : LFIDBearer::getActiveSelectedIDs(), type == LFIDBearer::GROUP ? getGroupName : + type == LFIDBearer::OBJECT ? owner ? getAvatarName : getObjectName : + type == LFIDBearer::EXPERIENCE ? getExperienceName : + getAvatarName); + if (!str.empty()) LLView::getWindow()->copyTextToClipboard(str); + return true; + } +}; +class ListCopySLURL final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + bool owner = !userdata.asBoolean(); + copy_profile_uri(owner ? get_active_owner_id() : LFIDBearer::getActiveSelectedID(), owner ? LFIDBearer::AVATAR : LFIDBearer::getActiveType()); return true; } }; -class ListCopyUUIDs : public view_listener_t +const LLUUID& active_owner_or_id(const LLSD& userdata) { - bool handleEvent(LLPointer event, const LLSD& userdata) + return !userdata.asBoolean() ? get_active_owner_id() : LFIDBearer::getActiveSelectedID(); +} + +#define active_owners_or_ids(userdata) !userdata.asBoolean() ? get_active_owner_ids() : LFIDBearer::getActiveSelectedIDs() + +class ListCopyUUIDs final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override { - LLAvatarActions::copyUUIDs(LFIDBearer::getActiveSelectedIDs()); + LLAvatarActions::copyUUIDs(active_owners_or_ids(userdata)); return true; } }; -class ListInviteToGroup : public view_listener_t +class ListInviteToGroup final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - LLAvatarActions::inviteToGroup(LFIDBearer::getActiveSelectedIDs()); + LLAvatarActions::inviteToGroup(active_owners_or_ids(userdata)); return true; } }; -class ListOfferTeleport : public view_listener_t +class ListOfferTeleport final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - LLAvatarActions::offerTeleport(LFIDBearer::getActiveSelectedIDs()); + LLAvatarActions::offerTeleport(active_owners_or_ids(userdata)); return true; } }; -class ListPay : public view_listener_t +class ListPay final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - LLAvatarActions::pay(LFIDBearer::getActiveSelectedID()); + LLAvatarActions::pay(active_owner_or_id(userdata)); return true; } }; -class ListRemoveFriend : public view_listener_t +class ListRemoveFriend final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - LLAvatarActions::removeFriendDialog(LFIDBearer::getActiveSelectedID()); + LLAvatarActions::removeFriendDialog(active_owner_or_id(userdata)); return true; } }; -class ListRequestFriendship : public view_listener_t +class ListRequestFriendship final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - LLAvatarActions::requestFriendshipDialog(LFIDBearer::getActiveSelectedID()); + LLAvatarActions::requestFriendshipDialog(active_owner_or_id(userdata)); return true; } }; -class ListRequestTeleport : public view_listener_t +class ListRequestTeleport final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - LLAvatarActions::teleportRequest(LFIDBearer::getActiveSelectedID()); + LLAvatarActions::teleportRequest(active_owner_or_id(userdata)); return true; } }; -class ListShare : public view_listener_t +class ListShare final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - LLAvatarActions::share(LFIDBearer::getActiveSelectedID()); + LLAvatarActions::share(active_owner_or_id(userdata)); return true; } }; @@ -9227,76 +9429,178 @@ bool can_show_web_profile() return !gSavedSettings.getString("WebProfileURL").empty(); } -void show_log_browser(const LLUUID& id); -class ListShowLog : public view_listener_t +void show_log_browser(const LLUUID& id, const LFIDBearer::Type& type); +class ListShowLog final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - for (const LLUUID& id : LFIDBearer::getActiveSelectedIDs()) - show_log_browser(id); + const auto& type = userdata.asBoolean() ? LFIDBearer::getActiveType() : LFIDBearer::AVATAR; + for (const LLUUID& id : active_owners_or_ids(userdata)) + show_log_browser(id, type); return true; } }; -class ListShowProfile : public view_listener_t +class ListShowProfile final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - LLAvatarActions::showProfiles(LFIDBearer::getActiveSelectedIDs()); + switch (LFIDBearer::getActiveType()) + { + case LFIDBearer::AVATAR: LLAvatarActions::showProfiles(LFIDBearer::getActiveSelectedIDs()); break; + case LFIDBearer::GROUP: LLGroupActions::showProfiles(LFIDBearer::getActiveSelectedIDs()); break; + case LFIDBearer::OBJECT: + if (userdata.asBoolean()) + for (const auto& id : LFIDBearer::getActiveSelectedIDs()) LLUrlAction::openURL(get_slurl_for(id, LFIDBearer::OBJECT)); + else // Owners + LLAvatarActions::showProfiles(get_active_owner_ids()); + break; + case LFIDBearer::EXPERIENCE: for (const auto& id : LFIDBearer::getActiveSelectedIDs()) LLFloaterExperienceProfile::showInstance(id); break; + default: break; + } return true; } }; -class ListShowWebProfile : public view_listener_t +class ListShowWebProfile final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - LLAvatarActions::showProfiles(LFIDBearer::getActiveSelectedIDs(), true); + LLAvatarActions::showProfiles(active_owners_or_ids(userdata), true); return true; } }; -class ListStartAdhocCall : public view_listener_t +class ListStartAdhocCall final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - LLAvatarActions::startAdhocCall(LFIDBearer::getActiveSelectedIDs()); + LLAvatarActions::startAdhocCall(active_owners_or_ids(userdata)); return true; } }; -class ListStartCall : public view_listener_t +class ListStartCall final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - LLAvatarActions::startCall(LFIDBearer::getActiveSelectedID()); + (LFIDBearer::getActiveType() == LFIDBearer::GROUP ? LLGroupActions::startCall : LLAvatarActions::startCall)(active_owner_or_id(userdata)); return true; } }; -class ListStartConference : public view_listener_t +class ListStartConference final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - LLAvatarActions::startConference(LFIDBearer::getActiveSelectedIDs()); + LLAvatarActions::startConference(active_owners_or_ids(userdata)); return true; } }; -class ListStartIM : public view_listener_t +class ListStartIM final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - LLAvatarActions::startIM(LFIDBearer::getActiveSelectedID()); + const auto&& im = LFIDBearer::getActiveType() == LFIDBearer::GROUP ? [](const LLUUID& id) { LLGroupActions::startIM(id); } : LLAvatarActions::startIM; + for (const auto& id : active_owners_or_ids(userdata)) + im(id); return true; } }; -class ListAbuseReport : public view_listener_t +const LLVector3d& get_av_pos(const LLUUID& id); +const LLVector3d get_obj_pos(const LLUUID& id) { - bool handleEvent(LLPointer event, const LLSD& userdata) + if (const auto& obj = gObjectList.findObject(id)) + return obj->getPositionGlobal(); + return LLVector3d::zero; +} +static const LLVector3d get_active_pos(const LLSD& userdata) +{ + const auto& id = active_owner_or_id(userdata); + if (userdata.asBoolean() && LFIDBearer::getActiveType() == LFIDBearer::OBJECT) + return get_obj_pos(id); + return get_av_pos(id); +} + +class ListTeleportTo final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override { - LLFloaterReporter::showFromObject(LFIDBearer::getActiveSelectedID()); + const auto& pos = get_active_pos(userdata); + if (!pos.isExactlyZero()) + gAgent.teleportViaLocation(pos); + return true; + } +}; + +class ListStalk final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + LLAvatarActions::showOnMap(active_owner_or_id(userdata)); + return true; + } +}; + +class ListStalkable final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + BOOL is_agent_mappable(const LLUUID& agent_id); + const auto& ids = active_owners_or_ids(userdata["data"]); + gMenuHolder->findControl(userdata["control"].asString())->setValue(ids.size() == 1 && is_agent_mappable(ids[0])); + return true; + } +}; + +class ListAbuseReport final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + if (LFIDBearer::getActiveType() == LFIDBearer::EXPERIENCE) + LLFloaterReporter::showFromExperience(LFIDBearer::getActiveSelectedID()); + else + LLFloaterReporter::showFromObject(active_owner_or_id(userdata)); + return true; + } +}; + +void set_experience_permission(const char* perm, const uuid_vec_t& ids) +{ + if (!gAgent.getRegion()) return; + auto& cache = LLExperienceCache::instance(); + for (const auto& id : ids) + cache.setExperiencePermission(id, perm, boost::bind(LLFloaterExperienceProfile::experiencePermissionResults, id, _1)); +} + +class ListExperienceAllow final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + set_experience_permission("Allow", LFIDBearer::getActiveSelectedIDs()); + return true; + } +}; + +class ListExperienceForget final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + if (!gAgent.getRegion()) return true; + auto& cache = LLExperienceCache::instance(); + for (const auto& id : LFIDBearer::getActiveSelectedIDs()) + cache.forgetExperiencePermission(id, boost::bind(LLFloaterExperienceProfile::experiencePermissionResults, id, _1)); + return true; + } +}; + +class ListExperienceBlock final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + set_experience_permission("Block", LFIDBearer::getActiveSelectedIDs()); return true; } }; @@ -9320,21 +9624,43 @@ void parcel_mod_notice_callback(const uuid_vec_t& ids, S32 choice, boost::functi } bool is_nearby(const LLUUID& id); -class ListIsNearby : public view_listener_t +class ListIsNearby final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - gMenuHolder->findControl(userdata["control"].asString())->setValue(is_nearby(LFIDBearer::getActiveSelectedID())); + const auto& data = userdata["data"]; + const auto& id = active_owner_or_id(data); + gMenuHolder->findControl(userdata["control"].asString())->setValue(!data.asBoolean() && LFIDBearer::getActiveType() == LFIDBearer::OBJECT ? !!gObjectList.findObject(id) : is_nearby(id)); + return true; + } +}; + +class ListFollow final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + gAgent.startFollowPilot(active_owner_or_id(userdata), true, gSavedSettings.getF32("SinguFollowDistance")); + return true; + } +}; + +class ListGoTo final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + const auto& pos = get_active_pos(userdata); + if (!pos.isExactlyZero()) + handle_go_to(pos); return true; } }; void track_av(const LLUUID& id); -class ListTrack : public view_listener_t +class ListTrack final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - track_av(LFIDBearer::getActiveSelectedID()); + track_av(active_owner_or_id(userdata)); return true; } }; @@ -9344,11 +9670,11 @@ void confirm_eject(const uuid_vec_t& ids) { LLNotificationsUtil::add("EjectAvatarFullname", create_args(ids, "AVATAR_NAME"), LLSD(), boost::bind(parcel_mod_notice_callback, ids, boost::bind(LLNotificationsUtil::getSelectedOption, _1, _2), send_eject)); } -class ListEject : public view_listener_t +class ListEject final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - confirm_eject(LFIDBearer::getActiveSelectedIDs()); + confirm_eject(active_owners_or_ids(userdata)); return true; } }; @@ -9358,11 +9684,11 @@ void confirm_freeze(const uuid_vec_t& ids) { LLNotificationsUtil::add("FreezeAvatarFullname", create_args(ids, "AVATAR_NAME"), LLSD(), boost::bind(parcel_mod_notice_callback, ids, boost::bind(LLNotificationsUtil::getSelectedOption, _1, _2), send_freeze)); } -class ListFreeze : public view_listener_t +class ListFreeze final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - confirm_freeze(LFIDBearer::getActiveSelectedIDs()); + confirm_freeze(active_owners_or_ids(userdata)); return true; } }; @@ -9397,11 +9723,11 @@ void confirm_estate_ban(const uuid_vec_t& ids) { LLNotificationsUtil::add("EstateBanUser", create_args(ids, "EVIL_USER"), LLSD(), boost::bind(estate_bulk_eject, ids, true, boost::bind(LLNotificationsUtil::getSelectedOption, _1, _2))); } -class ListEstateBan : public view_listener_t +class ListEstateBan final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - confirm_estate_ban(LFIDBearer::getActiveSelectedIDs()); + confirm_estate_ban(active_owners_or_ids(userdata)); return true; } }; @@ -9410,118 +9736,249 @@ void confirm_estate_kick(const uuid_vec_t& ids) { LLNotificationsUtil::add("EstateKickUser", create_args(ids, "EVIL_USER"), LLSD(), boost::bind(estate_bulk_eject, ids, false, boost::bind(LLNotificationsUtil::getSelectedOption, _1, _2))); } -class ListEstateEject : public view_listener_t +class ListEstateEject final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - confirm_estate_kick(LFIDBearer::getActiveSelectedIDs()); + confirm_estate_kick(active_owners_or_ids(userdata)); return true; } }; -class ListToggleMute : public view_listener_t +class ListToggleMute final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - const uuid_vec_t& ids = LFIDBearer::getActiveSelectedIDs(); - for (const auto& id : ids) + for (const auto& id : active_owners_or_ids(userdata)) LLAvatarActions::toggleBlock(id); return true; } }; -struct MenuSLURLDict : public LLSingleton +class ListIsInGroup final : public view_listener_t { - typedef std::function cb; - typedef std::function vcb; - typedef std::map> slurl_menu_map; - slurl_menu_map mEntries; - MenuSLURLDict() + bool handleEvent(LLPointer event, const LLSD& userdata) override { - // Text Editor menus - LLTextEditor::setIsObjectBlockedCallback(boost::bind(&LLMuteList::isMuted, LLMuteList::getInstance(), _1, _2, 0)); - LLTextEditor::setIsFriendCallback(LLAvatarActions::isFriend); - LLTextEditor::addMenuListeners(boost::bind(&MenuSLURLDict::action, this, _1, _2), boost::bind(&MenuSLURLDict::visible, this, _1, _2)); - - // Add the entries - insert("ShowWebProfile", boost::bind(LLAvatarActions::showProfile, _1, true), boost::bind(can_show_web_profile)); - insert("Pay", LLAvatarActions::pay); - insert("Call", LLAvatarActions::startCall); - insert("Share", LLAvatarActions::share); - insert("AbuseReport", LLFloaterReporter::showFromObject); - insert("InviteToGroup", [](const LLUUID& id) { LLAvatarActions::inviteToGroup(id); }); - insert("BanFromGroup", [](const LLUUID& id) { ban_from_group(uuid_vec_t(1, id)); }); - insert("ShowLog", [](const LLUUID& id) { show_log_browser(id); }); - insert("OfferTeleport", [](const LLUUID& id) { LLAvatarActions::offerTeleport(id); }, [](const LLUUID& id) { return LLAvatarActions::canOfferTeleport(id); }); - insert("RequestTeleport", LLAvatarActions::teleportRequest); - void teleport_to(const LLUUID& id); - insert("TeleportTo", teleport_to, is_nearby); - insert("Focus", LLFloaterAvatarList::setFocusAvatar, is_nearby); - insert("ParcelEject", [](const LLUUID& id) { confirm_eject(uuid_vec_t(1, id)); }, is_nearby); - insert("Freeze", [](const LLUUID& id) { confirm_freeze(uuid_vec_t(1, id)); }, is_nearby); - insert("EstateBan", [](const LLUUID& id) { confirm_estate_ban(uuid_vec_t(1, id)); }, is_nearby); - insert("EstateEject", [](const LLUUID & id) { confirm_estate_kick(uuid_vec_t(1, id)); }, is_nearby); - insert("Mute", LLAvatarActions::toggleBlock, [](const LLUUID& id) { return LLAvatarActions::canBlock(id) && !LLAvatarActions::isBlocked(id); }); - insert("Unmute", LLAvatarActions::toggleBlock, LLAvatarActions::isBlocked); - } - - void insert(const std::string& key, cb callback, vcb vcallback = nullptr) - { - mEntries[key] = std::make_pair(callback, vcallback); - } - - void action(const std::string& cmd, LLUUID id) const - { - auto it = mEntries.find(cmd); - if (it != mEntries.end()) - (*it).second.first(id); - } - bool visible(const std::string& cmd, LLUUID id) const - { - auto it = mEntries.find(cmd); - return it == mEntries.end() || !(*it).second.second || (*it).second.second(id); + auto in_group = false; + for (const auto& id : LFIDBearer::getActiveSelectedIDs()) + if (!(in_group = LLGroupActions::isInGroup(id))) + break; + gMenuHolder->findControl(userdata["control"].asString())->setValue(in_group); + return true; } }; -class MediaCtrlCopyURL : public view_listener_t +class ListNotInGroup final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + auto in_group = true; + for (const auto& id : LFIDBearer::getActiveSelectedIDs()) + if (in_group = LLGroupActions::isInGroup(id)) + break; + gMenuHolder->findControl(userdata["control"].asString())->setValue(!in_group); + return true; + } +}; + +class ListLeave final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + for (const auto& id : LFIDBearer::getActiveSelectedIDs()) + LLGroupActions::leave(id); + return true; + } +}; + +class ListJoin final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + for (const auto& id : LFIDBearer::getActiveSelectedIDs()) + LLGroupActions::join(id); + return true; + } +}; + +class ListActivate final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + for (const auto& id : LFIDBearer::getActiveSelectedIDs()) + LLGroupActions::activate(id); + return true; + } +}; + +class ListObjectCamTo final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + gAgentCamera.lookAtObject(LFIDBearer::getActiveSelectedID(), false); + return true; + } +}; + +class ListObjectSit final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + gAgent.stopAutoPilot(true); + handle_object_sit(gObjectList.findObject(LFIDBearer::getActiveSelectedID())); + return true; + } +}; + +class ListObjectPay final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + handle_give_money_dialog(gObjectList.findObject(LFIDBearer::getActiveSelectedID())); + return true; + } +}; + +class ListObjectEnablePay final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + const auto& ids = LFIDBearer::getActiveSelectedIDs(); + gMenuHolder->findControl(userdata["control"].asString())->setValue(ids.size() == 1 && enable_pay_object(gObjectList.findObject(ids[0]))); + return true; + } +}; + +void list_for_each_object(std::function func) +{ + for (const auto& id : LFIDBearer::getActiveSelectedIDs()) + if (auto obj = gObjectList.findObject(id)) + func(obj); +} + +class ListObjectTouch final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + list_for_each_object([](LLViewerObject* obj) { if (enable_object_touch(obj)) handle_object_touch(obj); }); + return true; + } +}; + +bool list_has_valid_object(std::function func) +{ + for (const auto& id : LFIDBearer::getActiveSelectedIDs()) + if (func(gObjectList.findObject(id))) + return true; // First is fine enough, we'll use all we can + return false; +} + +// One object must have touch sensor +class ListObjectEnableTouch final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + gMenuHolder->findControl(userdata["control"].asString())->setValue(list_has_valid_object([](LLViewerObject* obj){ return enable_object_touch(obj); })); + return true; + } +}; + +class ListObjectEdit final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + std::vector objs; + auto func = rlv_handler_t::isEnabled() ? static_cast>([&objs](LLViewerObject* obj) { if (gRlvHandler.canEdit(obj)) objs.push_back(obj); }) : [&objs](LLViewerObject* obj) { if (obj) objs.push_back(obj); }; + list_for_each_object(func); + + if (objs.empty()) return true; + + bool new_selection = userdata.asBoolean(); + + auto& selmgr = LLSelectMgr::instance(); + if (new_selection) selmgr.deselectAll(); + + auto selection = new_selection ? nullptr : selmgr.getSelection(); + auto old_primary = selection ? selection->getPrimaryObject() : nullptr; + for (const auto& obj : objs) + selmgr.selectObjectAndFamily(obj, true); + + if (old_primary) selmgr.selectObjectAndFamily(old_primary); + + if (new_selection) handle_object_edit(); + return true; + } +}; + +class ListObjectCanEdit final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + bool new_selection = userdata["data"].asBoolean(); + auto& selmgr = LLSelectMgr::instance(); + auto selection = new_selection ? nullptr : selmgr.getSelection(); + bool has_old_selection = selection && !selection->isEmpty() && !selection->isAttachment(); + auto func = rlv_handler_t::isEnabled() ? static_cast>([](LLViewerObject* obj) { return !!gRlvHandler.canEdit(obj); }) : [](LLViewerObject* obj) { return !!obj; }; + gMenuHolder->findControl(userdata["control"].asString()) + ->setValue((new_selection || has_old_selection) && list_has_valid_object(func)); + return true; + } +}; + +class ListObjectDerender final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + const std::string& unknown = LLTrans::getString("land_type_unknown"); + for (const auto& id : LFIDBearer::getActiveSelectedIDs()) + { + const auto& obj_data = get_obj_data(id); // Needed for object name + add_object_to_blacklist(id, obj_data ? obj_data->name : unknown); + } + + return true; + } +}; + +class MediaCtrlCopyURL final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override { get_focused()->onCopyURL(); return true; } }; -class MediaCtrlWebInspector : public view_listener_t +class MediaCtrlWebInspector final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { get_focused()->onOpenWebInspector(); return true; } }; -class MediaCtrlViewSource : public view_listener_t +class MediaCtrlViewSource final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { get_focused()->onShowSource(); return true; } }; -struct MarketplaceViewSortAction : view_listener_t +struct MarketplaceViewSortAction final : view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLFloaterMarketplaceListings::findInstance()->mPanelListings->onViewSortMenuItemClicked(userdata); return true; } }; -struct MarketplaceViewSortCheckItem : view_listener_t +struct MarketplaceViewSortCheckItem final : view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { gMenuHolder->findControl(userdata["control"].asString()) ->setValue(LLFloaterMarketplaceListings::findInstance()->mPanelListings->onViewSortMenuItemCheck(userdata["data"])); @@ -9538,12 +9995,12 @@ void addMenu(view_listener_t *menu, const std::string& name) void initialize_menus() { // A parameterized event handler used as ctrl-8/9/0 zoom controls below. - class LLZoomer : public view_listener_t + class LLZoomer final : public view_listener_t { public: // The "mult" parameter says whether "val" is a multiplier or used to set the value. LLZoomer(F32 val, bool mult=true) : mVal(val), mMult(mult) {} - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLViewerCamera& inst(LLViewerCamera::instance()); F32 new_fov_rad = mMult ? inst.getDefaultFOV() * mVal : mVal; @@ -9729,6 +10186,7 @@ void initialize_menus() addMenu(new LLOHGOD(), "Object.EnableExplode"); add_wave_listeners(); add_dae_listeners(); + addMenu(new LLObjectFollow(), "Object.Follow"); // addMenu(new LLObjectMute(), "Object.Mute"); addMenu(new LLObjectBuy(), "Object.Buy"); @@ -9836,10 +10294,12 @@ void initialize_menus() addMenu(new ListEnableCall(), "List.EnableCall"); addMenu(new ListEnableIsFriend(), "List.EnableIsFriend"); addMenu(new ListEnableIsNotFriend(), "List.EnableIsNotFriend"); + addMenu(new ListEnableUnmute(), "List.EnableUnmute"); addMenu(new ListEnableMute(), "List.EnableMute"); addMenu(new ListEnableOfferTeleport(), "List.EnableOfferTeleport"); addMenu(new ListVisibleWebProfile(), "List.VisibleWebProfile"); addMenu(new ListBanFromGroup(), "List.BanFromGroup"); + addMenu(new ListCopyNames(), "List.CopyNames"); addMenu(new ListCopySLURL(), "List.CopySLURL"); addMenu(new ListCopyUUIDs(), "List.CopyUUIDs"); addMenu(new ListInviteToGroup(), "List.InviteToGroup"); @@ -9856,18 +10316,40 @@ void initialize_menus() addMenu(new ListStartCall(), "List.StartCall"); addMenu(new ListStartConference(), "List.StartConference"); addMenu(new ListStartIM(), "List.StartIM"); + addMenu(new ListStalk, "List.Stalk"); + addMenu(new ListStalkable, "List.Stalkable"); + addMenu(new ListTeleportTo, "List.TeleportTo"); addMenu(new ListAbuseReport(), "List.AbuseReport"); addMenu(new ListIsNearby, "List.IsNearby"); + addMenu(new ListFollow, "List.Follow"); + addMenu(new ListGoTo, "List.GoTo"); addMenu(new ListTrack, "List.Track"); addMenu(new ListEject(), "List.ParcelEject"); addMenu(new ListFreeze(), "List.Freeze"); addMenu(new ListEstateBan(), "List.EstateBan"); addMenu(new ListEstateEject(), "List.EstateEject"); addMenu(new ListToggleMute(), "List.ToggleMute"); + addMenu(new ListIsInGroup, "List.IsInGroup"); + addMenu(new ListNotInGroup, "List.NotInGroup"); + addMenu(new ListLeave, "List.Leave"); + addMenu(new ListJoin, "List.Join"); + addMenu(new ListActivate, "List.Activate"); + addMenu(new ListObjectCamTo, "List.Object.CamTo"); + addMenu(new ListObjectSit, "List.Object.Sit"); + addMenu(new ListObjectPay, "List.Object.Pay"); + addMenu(new ListObjectEnablePay, "List.Object.EnablePay"); + addMenu(new ListObjectTouch, "List.Object.Touch"); + addMenu(new ListObjectEnableTouch, "List.Object.EnableTouch"); + addMenu(new ListObjectEdit, "List.Object.Edit"); + addMenu(new ListObjectCanEdit, "List.Object.CanEdit"); + addMenu(new ListObjectDerender, "List.Object.Derender"); + addMenu(new ListExperienceAllow, "List.Experience.Allow"); + addMenu(new ListExperienceForget, "List.Experience.Forget"); + addMenu(new ListExperienceBlock, "List.Experience.Block"); add_radar_listeners(); - MenuSLURLDict::getInstance(); + LLTextEditor::addMenuListeners(); // Media Ctrl menus addMenu(new MediaCtrlCopyURL(), "Copy.PageURL"); @@ -9877,17 +10359,17 @@ void initialize_menus() addMenu(new MarketplaceViewSortAction, "Marketplace.ViewSort.Action"); addMenu(new MarketplaceViewSortCheckItem, "Marketplace.ViewSort.CheckItem"); - class LLViewBuildMode : public view_listener_t + class LLViewBuildMode final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLToolMgr::getInstance()->toggleBuildMode(); return true; } }; - class LLViewCheckBuildMode : public view_listener_t + class LLViewCheckBuildMode final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { gMenuHolder->findControl(userdata["control"].asString())->setValue(LLToolMgr::getInstance()->inEdit()); return true; @@ -9900,9 +10382,8 @@ void initialize_menus() void region_change() { // Remove current dynamic items - for (custom_menu_item_list_t::iterator i = gCustomMenuItems.begin(); i != gCustomMenuItems.end(); ++i) + for (auto item : gCustomMenuItems) { - LLMenuItemCallGL* item = (*i); item->getParent()->removeChild(item); delete item; } @@ -9941,7 +10422,7 @@ void parse_simulator_features() LLMenuGL* menu = dynamic_cast(marker->getParent()); if (!menu) continue; - std::list::iterator it = menu->find(marker); + auto it = menu->find(marker); for (LLSD::map_iterator j = i->second.beginMap(); j != i->second.endMap(); ++j) { diff --git a/indra/newview/llviewermenu.h b/indra/newview/llviewermenu.h index a52f8682f..35aa88984 100644 --- a/indra/newview/llviewermenu.h +++ b/indra/newview/llviewermenu.h @@ -38,8 +38,10 @@ class LLUICtrl; class LLView; class LLParcelSelection; +class LLPickInfo; class LLObjectSelection; class LLSelectNode; +class LLViewerObject; void pre_init_menus(); void init_menus(); @@ -88,14 +90,14 @@ BOOL enable_god_full(void* user_data); BOOL enable_god_liaison(void* user_data); BOOL enable_god_basic(void* user_data); void set_underclothes_menu_options(); -void check_merchant_status(); +void check_merchant_status(bool force = false); void exchange_callingcard(const LLUUID& dest_id); void handle_gestures(void*); void handle_sit_down(void*); void handle_object_build(void*); -void handle_object_touch(); +void handle_object_touch(LLViewerObject*, const LLPickInfo* const = nullptr); bool enable_object_open(); void handle_object_open(); @@ -133,10 +135,10 @@ void handle_toggle_flycam(); void handle_fake_away_status(void*); void handle_object_sit_or_stand(); -void handle_give_money_dialog(); -bool enable_pay_object(); +void handle_give_money_dialog(LLViewerObject*); +bool enable_pay_object(LLViewerObject*); bool enable_buy_object(); -bool handle_go_to(); +void handle_go_to(const LLVector3d& pos); // Export to XML or Collada void handle_export_selected( void * ); diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 5ef9afe22..76a707bec 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -38,7 +38,7 @@ #include "llaudioengine.h" #include "llavataractions.h" #include "llavatarnamecache.h" -#include "llbase64.h" +#include "llcororesponder.h" #include "../lscript/lscript_byteformat.h" //Need LSCRIPTRunTimePermissionBits and SCRIPT_PERMISSION_* #include "lleconomy.h" #include "llfocusmgr.h" @@ -62,6 +62,7 @@ #include "llfloaterbuycurrency.h" #include "llfloaterbuyland.h" #include "llfloaterchat.h" +#include "llfloaterexperienceprofile.h" #include "llfloaterland.h" #include "llfloaterregioninfo.h" #include "llfloaterlandholdings.h" @@ -73,7 +74,7 @@ #include "llgroupactions.h" #include "llhudeffecttrail.h" #include "llhudmanager.h" -#include "llimpanel.h" +#include "llimprocessing.h" #include "llinventorybridge.h" #include "llinventorymodel.h" #include "llinventorypanel.h" @@ -94,7 +95,6 @@ #include "llspeakers.h" #include "lltrans.h" #include "llviewerfoldertype.h" -#include "llviewergenericmessage.h" #include "llviewermenu.h" #include "llviewerinventory.h" #include "llviewerjoystick.h" @@ -113,6 +113,7 @@ #include "llkeythrottle.h" #include "llagentui.h" #include "llviewerregion.h" +#include "llexperiencecache.h" // [RLVa:KB] - Checked: 2010-03-09 (RLVa-1.2.0a) #include "rlvactions.h" @@ -121,18 +122,22 @@ #include "rlvui.h" // [/RLVa:KB] +#include + +//#include "llnotificationmanager.h" // +#include "llexperiencecache.h" + #if SHY_MOD //Command handler # include "shcommandhandler.h" #endif //shy_mod #include "hippogridmanager.h" #include "hippolimits.h" -#include "hippofloaterxml.h" -#include "llversioninfo.h" #include "m7wlinterface.h" #include "llgiveinventory.h" +#include #include #if LL_WINDOWS // For Windows specific error handler @@ -143,10 +148,11 @@ #include "NACLantispam.h" bool can_block(const LLUUID& id); // NaCl - Newline flood protection -#include static const boost::regex NEWLINES("\\n{1}"); // NaCl End + + extern AIHTTPTimeoutPolicy authHandler_timeout; // @@ -169,6 +175,7 @@ extern bool gShiftFrame; bool check_offer_throttle(const std::string& from_name, bool check_only); bool check_asset_previewable(const LLAssetType::EType asset_type); static void process_money_balance_reply_extended(LLMessageSystem* msg); +bool handle_trusted_experiences_notification(const LLSD&); //inventory offer throttle globals LLFrameTimer gThrottleTimer; @@ -196,35 +203,83 @@ const std::string SCRIPT_QUESTIONS[SCRIPT_PERMISSION_EOF] = "ScriptReturnObjects" }; -const BOOL SCRIPT_QUESTION_IS_CAUTION[SCRIPT_PERMISSION_EOF] = +constexpr bool SCRIPT_QUESTION_IS_CAUTION[SCRIPT_PERMISSION_EOF] = { - TRUE, // ScriptTakeMoney, - FALSE, // ActOnControlInputs - FALSE, // RemapControlInputs - FALSE, // AnimateYourAvatar - FALSE, // AttachToYourAvatar - FALSE, // ReleaseOwnership, - FALSE, // LinkAndDelink, - FALSE, // AddAndRemoveJoints - FALSE, // ChangePermissions - FALSE, // TrackYourCamera, - FALSE, // ControlYourCamera - FALSE, // TeleportYourAgent - FALSE, // JoinAnExperience - FALSE, // SilentlyManageEstateAccess - FALSE, // OverrideYourAnimations - FALSE, // ScriptReturnObjects + true, // ScriptTakeMoney, + false, // ActOnControlInputs + false, // RemapControlInputs + false, // AnimateYourAvatar + false, // AttachToYourAvatar + false, // ReleaseOwnership, + false, // LinkAndDelink, + false, // AddAndRemoveJoints + false, // ChangePermissions + false, // TrackYourCamera, + false, // ControlYourCamera + false, // TeleportYourAgent + false, // JoinAnExperience + false, // SilentlyManageEstateAccess + false, // OverrideYourAnimations + false, // ScriptReturnObjects }; +void accept_friendship_coro(const LLCoroResponder& responder, const LLSD& notification) +{ + const auto& status = responder.getStatus(); + + if (!responder.isGoodStatus(status)) + { + LL_WARNS("Friendship") << "HTTP status " << status << ": " << responder.getReason() << + ". friendship offer accept failed." << LL_ENDL; + } + else + { + { + LLSD payload = notification["payload"]; + LL_DEBUGS("Friendship") << "Adding friend to list" << responder.getContent() << LL_ENDL; + // add friend to recent people list + //LLRecentPeople::instance().add(payload["from_id"]); + + LLNotificationsUtil::add("FriendshipAcceptedByMe", + notification["substitutions"], payload); + } + } +} + +void decline_friendship_coro(const LLCoroResponder& responder, const LLSD& notification, S32 option) +{ + const auto& status = responder.getStatus(); + + if (!responder.isGoodStatus(status)) + { + LL_WARNS("Friendship") << "HTTP status " << status << ": " << responder.getReason() << + ". friendship offer decline failed." << LL_ENDL; + } + else + { + { + const auto& payload = notification["payload"]; + LL_DEBUGS("Friendship") << "Friendship declined" << responder.getContent() << LL_ENDL; + if (option == 1) + { + LLNotificationsUtil::add("FriendshipDeclinedByMe", + notification["substitutions"], payload); + } + else if (option == 2) + { + // start IM session + LLAvatarActions::startIM(payload["from_id"].asUUID()); + } + } + } +} + bool friendship_offer_callback(const LLSD& notification, const LLSD& response) { S32 option = LLNotificationsUtil::getSelectedOption(notification, response); LLMessageSystem* msg = gMessageSystem; const LLSD& payload = notification["payload"]; - // add friend to recent people list - //LLRecentPeople::instance().add(payload["from_id"]); - switch(option) { case 0: @@ -235,40 +290,111 @@ bool friendship_offer_callback(const LLSD& notification, const LLSD& response) const LLUUID fid = gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD); // This will also trigger an onlinenotification if the user is online - msg->newMessageFast(_PREHASH_AcceptFriendship); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_TransactionBlock); - msg->addUUIDFast(_PREHASH_TransactionID, payload["session_id"]); - msg->nextBlockFast(_PREHASH_FolderData); - msg->addUUIDFast(_PREHASH_FolderID, fid); - msg->sendReliable(LLHost(payload["sender"].asString())); + std::string url = gAgent.getRegionCapability("AcceptFriendship"); + LL_DEBUGS("Friendship") << "Cap string: " << url << LL_ENDL; + if (!url.empty() && payload.has("online") && payload["online"].asBoolean() == false) + { + LL_DEBUGS("Friendship") << "Accepting friendship via capability" << LL_ENDL; + url += "?from=" + payload["from_id"].asString(); + url += "&agent_name=\"" + LLURI::escape(gAgentAvatarp->getFullname()) + '"'; + LLHTTPClient::post(url, LLSD(), new LLCoroResponder( + boost::bind(accept_friendship_coro, _1, notification))); + } + else if (payload.has("session_id") && payload["session_id"].asUUID().notNull()) + { + LL_DEBUGS("Friendship") << "Accepting friendship via viewer message" << LL_ENDL; + msg->newMessageFast(_PREHASH_AcceptFriendship); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_TransactionBlock); + msg->addUUIDFast(_PREHASH_TransactionID, payload["session_id"]); + msg->nextBlockFast(_PREHASH_FolderData); + msg->addUUIDFast(_PREHASH_FolderID, fid); + msg->sendReliable(LLHost(payload["sender"].asString())); + + // add friend to recent people list + //LLRecentPeople::instance().add(payload["from_id"]); + LLNotificationsUtil::add("FriendshipAcceptedByMe", + notification["substitutions"], payload); + } + else + { + LL_WARNS("Friendship") << "Failed to accept friendship offer, neither capability nor transaction id are accessible" << LL_ENDL; + } break; } - case 1: + case 1: // Decline + // fall-through + //case 3: // Send IM - decline and start IM session + { // decline // We no longer notify other viewers, but we DO still send // the rejection to the simulator to delete the pending userop. - msg->newMessageFast(_PREHASH_DeclineFriendship); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_TransactionBlock); - msg->addUUIDFast(_PREHASH_TransactionID, payload["session_id"]); - msg->sendReliable(LLHost(payload["sender"].asString())); - break; - case 3: - // profile - LLAvatarActions::showProfile(payload["from_id"]); - LLNotificationsUtil::add(notification["name"], notification["substitutions"], payload); //Respawn! + std::string url = gAgent.getRegionCapability("DeclineFriendship"); + LL_DEBUGS("Friendship") << "Cap string: " << url << LL_ENDL; + if (!url.empty() && payload.has("online") && payload["online"].asBoolean() == false) + { + LL_DEBUGS("Friendship") << "Declining friendship via capability" << LL_ENDL; + url += "?from=" + payload["from_id"].asString(); + LLHTTPClient::del(url, new LLCoroResponder( + boost::bind(decline_friendship_coro, _1, notification, option))); + } + else if (payload.has("session_id") && payload["session_id"].asUUID().notNull()) + { + LL_DEBUGS("Friendship") << "Declining friendship via viewer message" << LL_ENDL; + msg->newMessageFast(_PREHASH_DeclineFriendship); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_TransactionBlock); + msg->addUUIDFast(_PREHASH_TransactionID, payload["session_id"]); + msg->sendReliable(LLHost(payload["sender"].asString())); + + if (option == 1) // due to fall-through + { + LLNotificationsUtil::add("FriendshipDeclinedByMe", + notification["substitutions"], payload); + } + /*else if (option == 3) + { + // start IM session + LLAvatarActions::startIM(payload["from_id"].asUUID()); + }*/ + } + else + { + LL_WARNS("Friendship") << "Failed to decline friendship offer, neither capability nor transaction id are accessible" << LL_ENDL; + } + } default: // close button probably, possibly timed out break; } + // TODO: this set of calls has undesirable behavior under Windows OS (CHUI-985): + // here appears three additional toasts instead one modified + // need investigation and fix + + // LLNotificationFormPtr modified_form(new LLNotificationForm(*notification_ptr->getForm())); + // modified_form->setElementEnabled("Accept", false); + // modified_form->setElementEnabled("Decline", false); + // notification_ptr->updateForm(modified_form); +// [SL:KB] - Patch: UI-Notifications | Checked: 2013-05-09 (Catznip-3.5) +// // Assume that any offer notification with "getCanBeStored() == true" is the result of RLVa routing it to the notifcation syswell +// /*const*/ LLNotificationsUI::LLScreenChannel* pChannel = LLNotificationsUI::LLChannelManager::instance().getNotificationScreenChannel(); +// /*const*/ LLNotificationsUI::LLToast* pToast = (pChannel) ? pChannel->getToastByNotificationID(notification["id"].asUUID()) : NULL; +// if ( (!pToast) || (!pToast->getCanBeStored()) ) +// { +// [/SL:KB] +// notification_ptr->repost(); +// [SL:KB] - Patch: UI-Notifications | Checked: 2013-05-09 (Catznip-3.5) +// } +// [/SL:KB] + return false; } + static LLNotificationFunctorRegistration friendship_offer_callback_reg("OfferFriendship", friendship_offer_callback); static LLNotificationFunctorRegistration friendship_offer_callback_reg_nm("OfferFriendshipNoMessage", friendship_offer_callback); @@ -278,25 +404,25 @@ static LLNotificationFunctorRegistration friendship_offer_callback_reg_nm("Offer void give_money(const LLUUID& uuid, LLViewerRegion* region, S32 amount, BOOL is_group, S32 trx_type, const std::string& desc) { - if(0 == amount || !region) return; + if (0 == amount || !region) return; amount = abs(amount); - LL_INFOS("Messaging") << "give_money(" << uuid << "," << amount << ")"<< LL_ENDL; - if(can_afford_transaction(amount)) + LL_INFOS("Messaging") << "give_money(" << uuid << "," << amount << ")" << LL_ENDL; + if (can_afford_transaction(amount)) { -// gStatusBar->debitBalance(amount); + // gStatusBar->debitBalance(amount); LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_MoneyTransferRequest); msg->nextBlockFast(_PREHASH_AgentData); msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); msg->nextBlockFast(_PREHASH_MoneyData); - msg->addUUIDFast(_PREHASH_SourceID, gAgent.getID() ); + msg->addUUIDFast(_PREHASH_SourceID, gAgent.getID()); msg->addUUIDFast(_PREHASH_DestID, uuid); msg->addU8Fast(_PREHASH_Flags, pack_transaction_flags(FALSE, is_group)); msg->addS32Fast(_PREHASH_Amount, amount); msg->addU8Fast(_PREHASH_AggregatePermNextOwner, (U8)LLAggregatePermissions::AP_EMPTY); msg->addU8Fast(_PREHASH_AggregatePermInventory, (U8)LLAggregatePermissions::AP_EMPTY); - msg->addS32Fast(_PREHASH_TransactionType, trx_type ); + msg->addS32Fast(_PREHASH_TransactionType, trx_type); msg->addStringFast(_PREHASH_Description, desc); msg->sendReliable(region->getHost()); } @@ -328,19 +454,19 @@ void process_logout_reply(LLMessageSystem* msg, void**) msg->getUUID("AgentData", "AgentID", agent_id); LLUUID session_id; msg->getUUID("AgentData", "SessionID", session_id); - if((agent_id != gAgent.getID()) || (session_id != gAgent.getSessionID())) + if ((agent_id != gAgent.getID()) || (session_id != gAgent.getSessionID())) { LL_WARNS("Messaging") << "Bogus Logout Reply" << LL_ENDL; } LLInventoryModel::update_map_t parents; - S32 count = msg->getNumberOfBlocksFast( _PREHASH_InventoryData ); - for(S32 i = 0; i < count; ++i) + S32 count = msg->getNumberOfBlocksFast(_PREHASH_InventoryData); + for (S32 i = 0; i < count; ++i) { LLUUID item_id; msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_ItemID, item_id, i); - if( (1 == count) && item_id.isNull() ) + if ((1 == count) && item_id.isNull()) { // Detect dummy item. Indicates an empty list. break; @@ -349,8 +475,8 @@ void process_logout_reply(LLMessageSystem* msg, void**) // We do not need to track the asset ids, just account for an // updated inventory version. LL_INFOS("Messaging") << "process_logout_reply itemID=" << item_id << LL_ENDL; - LLInventoryItem* item = gInventory.getItem( item_id ); - if( item ) + LLInventoryItem* item = gInventory.getItem(item_id); + if (item) { parents[item->getParentUUID()] = 0; gInventory.addChangedMask(LLInventoryObserver::INTERNAL, item_id); @@ -363,11 +489,13 @@ void process_logout_reply(LLMessageSystem* msg, void**) LLAppViewer::instance()->forceQuit(); } -void process_layer_data(LLMessageSystem *mesgsys, void **user_data) +void process_layer_data(LLMessageSystem* mesgsys, void** user_data) { - LLViewerRegion *regionp = LLWorld::getInstance()->getRegion(mesgsys->getSender()); + LLViewerRegion* regionp = LLWorld::getInstance()->getRegion(mesgsys->getSender()); - if(!regionp || gNoRender) + LL_DEBUGS_ONCE("SceneLoadTiming") << "Received layer data" << LL_ENDL; + + if (!regionp || gNoRender) { LL_WARNS() << "Invalid region for layer data." << LL_ENDL; return; @@ -390,9 +518,9 @@ void process_layer_data(LLMessageSystem *mesgsys, void **user_data) << LL_ENDL; return; } - U8 *datap = new U8[size]; + U8* datap = new U8[size]; mesgsys->getBinaryDataFast(_PREHASH_LayerData, _PREHASH_Data, datap, size); - LLVLData *vl_datap = new LLVLData(regionp, type, datap, size); + LLVLData* vl_datap = new LLVLData(regionp, type, datap, size); if (mesgsys->getReceiveCompressedSize()) { gVLManager.addLayerData(vl_datap, mesgsys->getReceiveCompressedSize()); @@ -403,195 +531,9 @@ void process_layer_data(LLMessageSystem *mesgsys, void **user_data) } } -// S32 exported_object_count = 0; -// S32 exported_image_count = 0; -// S32 current_object_count = 0; -// S32 current_image_count = 0; - -// extern LLNotifyBox *gExporterNotify; -// extern LLUUID gExporterRequestID; -// extern std::string gExportDirectory; - -// extern LLUploadDialog *gExportDialog; - -// std::string gExportedFile; - -// std::map gImageChecksums; - -// void export_complete() -// { -// LLUploadDialog::modalUploadFinished(); -// gExporterRequestID.setNull(); -// gExportDirectory = ""; - -// LLFILE* fXML = LLFile::fopen(gExportedFile, "rb"); /* Flawfinder: ignore */ -// fseek(fXML, 0, SEEK_END); -// long length = ftell(fXML); -// fseek(fXML, 0, SEEK_SET); -// U8 *buffer = new U8[length + 1]; -// size_t nread = fread(buffer, 1, length, fXML); -// if (nread < (size_t) length) -// { -// LL_WARNS("Messaging") << "Short read" << LL_ENDL; -// } -// buffer[nread] = '\0'; -// fclose(fXML); - -// char *pos = (char *)buffer; -// while ((pos = strstr(pos+1, ""); - -// if (pos_uuid) -// { -// char image_uuid_str[UUID_STR_SIZE]; /* Flawfinder: ignore */ -// memcpy(image_uuid_str, pos_uuid+2, UUID_STR_SIZE-1); /* Flawfinder: ignore */ -// image_uuid_str[UUID_STR_SIZE-1] = 0; - -// LLUUID image_uuid(image_uuid_str); - -// LL_INFOS("Messaging") << "Found UUID: " << image_uuid << LL_ENDL; - -// std::map::iterator itor = gImageChecksums.find(image_uuid); -// if (itor != gImageChecksums.end()) -// { -// LL_INFOS("Messaging") << "Replacing with checksum: " << itor->second << LL_ENDL; -// if (!itor->second.empty()) -// { -// memcpy(&pos_check[10], itor->second.c_str(), 32); /* Flawfinder: ignore */ -// } -// } -// } -// } -// } - -// LLFILE* fXMLOut = LLFile::fopen(gExportedFile, "wb"); /* Flawfinder: ignore */ -// if (fwrite(buffer, 1, length, fXMLOut) != length) -// { -// LL_WARNS("Messaging") << "Short write" << LL_ENDL; -// } -// fclose(fXMLOut); - -// delete [] buffer; -// } - - -// void exported_item_complete(const LLTSCode status, void *user_data) -// { -// //std::string *filename = (std::string *)user_data; - -// if (status < LLTS_OK) -// { -// LL_WARNS("Messaging") << "Export failed!" << LL_ENDL; -// } -// else -// { -// ++current_object_count; -// if (current_image_count == exported_image_count && current_object_count == exported_object_count) -// { -// LL_INFOS("Messaging") << "*** Export complete ***" << LL_ENDL; - -// export_complete(); -// } -// else -// { -// gExportDialog->setMessage(llformat("Exported %d/%d object files, %d/%d textures.", current_object_count, exported_object_count, current_image_count, exported_image_count)); -// } -// } -// } - -// struct exported_image_info -// { -// LLUUID image_id; -// std::string filename; -// U32 image_num; -// }; - -// void exported_j2c_complete(const LLTSCode status, void *user_data) -// { -// exported_image_info *info = (exported_image_info *)user_data; -// LLUUID image_id = info->image_id; -// U32 image_num = info->image_num; -// std::string filename = info->filename; -// delete info; - -// if (status < LLTS_OK) -// { -// LL_WARNS("Messaging") << "Image download failed!" << LL_ENDL; -// } -// else -// { -// LLFILE* fIn = LLFile::fopen(filename, "rb"); /* Flawfinder: ignore */ -// if (fIn) -// { -// LLPointer ImageUtility = new LLImageJ2C; -// LLPointer TargaUtility = new LLImageTGA; - -// fseek(fIn, 0, SEEK_END); -// S32 length = ftell(fIn); -// fseek(fIn, 0, SEEK_SET); -// U8 *buffer = ImageUtility->allocateData(length); -// if (fread(buffer, 1, length, fIn) != length) -// { -// LL_WARNS("Messaging") << "Short read" << LL_ENDL; -// } -// fclose(fIn); -// LLFile::remove(filename); - -// // Convert to TGA -// LLPointer image = new LLImageRaw(); - -// ImageUtility->updateData(); -// ImageUtility->decode(image, 100000.0f); - -// TargaUtility->encode(image); -// U8 *data = TargaUtility->getData(); -// S32 data_size = TargaUtility->getDataSize(); - -// std::string file_path = gDirUtilp->getDirName(filename); - -// std::string output_file = llformat("%s/image-%03d.tga", file_path.c_str(), image_num);//filename; -// //S32 name_len = output_file.length(); -// //strcpy(&output_file[name_len-3], "tga"); -// LLFILE* fOut = LLFile::fopen(output_file, "wb"); /* Flawfinder: ignore */ -// char md5_hash_string[33]; /* Flawfinder: ignore */ -// strcpy(md5_hash_string, "00000000000000000000000000000000"); /* Flawfinder: ignore */ -// if (fOut) -// { -// if (fwrite(data, 1, data_size, fOut) != data_size) -// { -// LL_WARNS("Messaging") << "Short write" << LL_ENDL; -// } -// fseek(fOut, 0, SEEK_SET); -// fclose(fOut); -// fOut = LLFile::fopen(output_file, "rb"); /* Flawfinder: ignore */ -// LLMD5 my_md5_hash(fOut); -// my_md5_hash.hex_digest(md5_hash_string); -// } - -// gImageChecksums.insert(std::pair(image_id, md5_hash_string)); -// } -// } - -// ++current_image_count; -// if (current_image_count == exported_image_count && current_object_count == exported_object_count) -// { -// LL_INFOS("Messaging") << "*** Export textures complete ***" << LL_ENDL; -// export_complete(); -// } -// else -// { -// gExportDialog->setMessage(llformat("Exported %d/%d object files, %d/%d textures.", current_object_count, exported_object_count, current_image_count, exported_image_count)); -// } -//} - void process_derez_ack(LLMessageSystem*, void**) { - if(gViewerWindow) gViewerWindow->getWindow()->decBusyCount(); + if (gViewerWindow) gViewerWindow->getWindow()->decBusyCount(); } void process_places_reply(LLMessageSystem* msg, void** data) @@ -603,7 +545,7 @@ void process_places_reply(LLMessageSystem* msg, void** data) { LLFloaterLandHoldings::processPlacesReply(msg, data); } - else if(gAgent.isInGroup(query_id)) + else if (gAgent.isInGroup(query_id)) { LLPanelGroupLandMoney::processPlacesReply(msg, data); } @@ -615,7 +557,7 @@ void process_places_reply(LLMessageSystem* msg, void** data) void send_sound_trigger(const LLUUID& sound_id, F32 gain) { - if (sound_id.isNull() || gAgent.getRegion() == NULL) + if (sound_id.isNull() || gAgent.getRegion() == nullptr) { // disconnected agent or zero guids don't get sent (no sound) return; @@ -626,9 +568,9 @@ void send_sound_trigger(const LLUUID& sound_id, F32 gain) msg->nextBlockFast(_PREHASH_SoundData); msg->addUUIDFast(_PREHASH_SoundID, sound_id); // Client untrusted, ids set on sim - msg->addUUIDFast(_PREHASH_OwnerID, LLUUID::null ); - msg->addUUIDFast(_PREHASH_ObjectID, LLUUID::null ); - msg->addUUIDFast(_PREHASH_ParentID, LLUUID::null ); + msg->addUUIDFast(_PREHASH_OwnerID, LLUUID::null); + msg->addUUIDFast(_PREHASH_ObjectID, LLUUID::null); + msg->addUUIDFast(_PREHASH_ParentID, LLUUID::null); msg->addU64Fast(_PREHASH_Handle, gAgent.getRegion()->getHandle()); @@ -639,33 +581,163 @@ void send_sound_trigger(const LLUUID& sound_id, F32 gain) gAgent.sendMessage(); } +static LLSD sSavedGroupInvite; +static LLSD sSavedResponse; + +void response_group_invitation_coro(const LLCoroResponder& responder, const LLUUID& group_id, bool notify_and_update) +{ + const auto& status = responder.getStatus(); + + if (!responder.isGoodStatus(status)) + { + LL_WARNS("GroupInvite") << "HTTP status " << status << ": " << responder.getReason() << + ". Group " << group_id << " invitation response processing failed." << LL_ENDL; + } + else + { + { + LL_DEBUGS("GroupInvite") << "Successfully sent response to group " << group_id << " invitation" << LL_ENDL; + if (notify_and_update) + { + LLNotificationsUtil::add("JoinGroupSuccess"); + gAgent.sendAgentDataUpdateRequest(); + + LLGroupMgr::getInstance()->clearGroupData(group_id); + // refresh the floater for this group, if any. + LLGroupActions::refresh(group_id); + } + } + } +} + +void send_join_group_response(const LLUUID& group_id, const LLUUID& transaction_id, bool accept_invite, S32 fee, bool use_offline_cap, LLSD& payload) +{ + if (accept_invite && fee > 0) + { + // If there is a fee to join this group, make + // sure the user is sure they want to join. + LLSD args; + args["COST"] = llformat("%d", fee); + // Set the fee for next time to 0, so that we don't keep + // asking about a fee. + LLSD next_payload = payload; + next_payload["fee"] = 0; + LLNotificationsUtil::add("JoinGroupCanAfford", + args, + next_payload); + } + else if (use_offline_cap) + { + std::string url; + if (accept_invite) + { + url = gAgent.getRegionCapability("AcceptGroupInvite"); + } + else + { + url = gAgent.getRegionCapability("DeclineGroupInvite"); + } + + if (!url.empty()) + { + LL_DEBUGS("GroupInvite") << "Capability url: " << url << LL_ENDL; + LLSD payload; + payload["group"] = group_id; + LLHTTPClient::post(url, payload, new LLCoroResponder( + boost::bind(response_group_invitation_coro, _1, group_id, accept_invite))); + } + else + { + // if sim has no this cap, we can do nothing - regular request will fail + LL_WARNS("GroupInvite") << "No capability, can't reply to offline invitation!" << LL_ENDL; + } + } + else + { + LL_DEBUGS("GroupInvite") << "Replying to group invite via IM message" << LL_ENDL; + + EInstantMessage type = accept_invite ? IM_GROUP_INVITATION_ACCEPT : IM_GROUP_INVITATION_DECLINE; + + send_improved_im(group_id, + std::string("name"), + std::string("message"), + IM_ONLINE, + type, + transaction_id); + } +} + +void send_join_group_response(const LLUUID& group_id, const LLUUID& transaction_id, bool accept_invite, S32 fee, bool use_offline_cap) +{ + LLSD payload; + if (accept_invite) + { + payload["group_id"] = group_id; + payload["transaction_id"] = transaction_id; + payload["fee"] = fee; + payload["use_offline_cap"] = use_offline_cap; + } + send_join_group_response(group_id, transaction_id, accept_invite, fee, use_offline_cap, payload); +} + bool join_group_response(const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + // A bit of variable saving and restoring is used to deal with the case where your group list is full and you + // receive an invitation to another group. The data from that invitation is stored in the sSaved + // variables. If you then drop a group and click on the Join button the stored data is restored and used + // to join the group. + LLSD notification_adjusted = notification; + LLSD response_adjusted = response; + + std::string action = notification["name"]; + + // Storing all the information by group id allows for the rare case of being at your maximum + // group count and receiving more than one invitation. + std::string id = notification_adjusted["payload"]["group_id"].asString(); + + if ("JoinGroup" == action || "JoinGroupCanAfford" == action) + { + sSavedGroupInvite[id] = notification; + sSavedResponse[id] = response; + } + else if ("JoinedTooManyGroupsMember" == action) + { + S32 opt = LLNotificationsUtil::getSelectedOption(notification, response); + if (0 == opt) // Join button pressed + { + notification_adjusted = sSavedGroupInvite[id]; + response_adjusted = sSavedResponse[id]; + } + sSavedGroupInvite.erase(id); + sSavedResponse.erase(id); + } + + S32 option = LLNotificationsUtil::getSelectedOption(notification_adjusted, response_adjusted); bool accept_invite = false; - LLUUID group_id = notification["payload"]["group_id"].asUUID(); - LLUUID transaction_id = notification["payload"]["transaction_id"].asUUID(); - std::string name = notification["payload"]["name"].asString(); - std::string message = notification["payload"]["message"].asString(); - S32 fee = notification["payload"]["fee"].asInteger(); + LLUUID group_id = notification_adjusted["payload"]["group_id"].asUUID(); + LLUUID transaction_id = notification_adjusted["payload"]["transaction_id"].asUUID(); + std::string name = notification_adjusted["payload"]["name"].asString(); + std::string message = notification_adjusted["payload"]["message"].asString(); + S32 fee = notification_adjusted["payload"]["fee"].asInteger(); + U8 use_offline_cap = notification_adjusted["payload"]["use_offline_cap"].asInteger(); if (option == 2 && !group_id.isNull()) { LLGroupActions::show(group_id); LLSD args; args["MESSAGE"] = message; - LLNotificationsUtil::add("JoinGroup", args, notification["payload"]); + LLNotificationsUtil::add("JoinGroup", args, notification_adjusted["payload"]); return false; } - if(option == 0 && !group_id.isNull()) + if (option == 0 && !group_id.isNull()) { // check for promotion or demotion. S32 max_groups = gHippoLimits->getMaxAgentGroups(); - if(gAgent.isInGroup(group_id)) ++max_groups; + if (gAgent.isInGroup(group_id)) ++max_groups; - if((S32)gAgent.mGroups.size() < max_groups) + if ((S32)gAgent.mGroups.size() < max_groups) { accept_invite = true; } @@ -678,63 +750,29 @@ bool join_group_response(const LLSD& notification, const LLSD& response) return false; } } + send_join_group_response(group_id, transaction_id, accept_invite, fee, use_offline_cap, notification_adjusted["payload"]); - if (accept_invite) - { - // If there is a fee to join this group, make - // sure the user is sure they want to join. - if (fee > 0) - { - LLSD args; - args["COST"] = llformat("%d", fee); - // Set the fee for next time to 0, so that we don't keep - // asking about a fee. - LLSD next_payload = notification["payload"]; - next_payload["fee"] = 0; - LLNotificationsUtil::add("JoinGroupCanAfford", - args, - next_payload); - } - else - { - send_improved_im(group_id, - std::string("name"), - std::string("message"), - IM_ONLINE, - IM_GROUP_INVITATION_ACCEPT, - transaction_id); - } - } - else - { - send_improved_im(group_id, - std::string("name"), - std::string("message"), - IM_ONLINE, - IM_GROUP_INVITATION_DECLINE, - transaction_id); - } + sSavedGroupInvite[id] = LLSD::emptyMap(); + sSavedResponse[id] = LLSD::emptyMap(); return false; } static void highlight_inventory_objects_in_panel(const uuid_vec_t& items, LLInventoryPanel *inventory_panel) { - if (NULL == inventory_panel) return; + if (nullptr == inventory_panel) return; - for (auto item_iter = items.begin(); - item_iter != items.end(); - ++item_iter) + for (auto item_id : items) { - const LLUUID& item_id = (*item_iter); - if(!highlight_offered_object(item_id)) + if (!highlight_offered_object(item_id)) { continue; } LLInventoryObject* item = gInventory.getObject(item_id); llassert(item); - if (!item) { + if (!item) + { continue; } @@ -771,14 +809,18 @@ static LLNotificationFunctorRegistration jgr_3("JoinGroupCanAfford", join_group_ //----------------------------------------------------------------------------- // Instant Message //----------------------------------------------------------------------------- -class LLOpenAgentOffer : public LLInventoryFetchItemsObserver +class LLOpenAgentOffer final : public LLInventoryFetchItemsObserver { public: LLOpenAgentOffer(const LLUUID& object_id, const std::string& from_name) : LLInventoryFetchItemsObserver(object_id), - mFromName(from_name) {} - /*virtual*/ void startFetch() + mFromName(from_name) + { + } + + /*virtual*/ + void startFetch() override { for (uuid_vec_t::const_iterator it = mIDs.begin(); it < mIDs.end(); ++it) { @@ -790,12 +832,15 @@ public: } LLInventoryFetchItemsObserver::startFetch(); } - /*virtual*/ void done() + + /*virtual*/ + void done() override { open_inventory_offer(mComplete, mFromName); gInventory.removeObserver(this); delete this; } + private: std::string mFromName; }; @@ -806,19 +851,19 @@ private: * We can't create it each time items are moved because "drop" event is sent separately for each * element even while multi-dragging. We have to have the only instance of the observer. See EXT-4347. */ -class LLViewerInventoryMoveFromWorldObserver : public LLInventoryAddItemByAssetObserver +class LLViewerInventoryMoveFromWorldObserver final : public LLInventoryAddItemByAssetObserver { public: LLViewerInventoryMoveFromWorldObserver() : LLInventoryAddItemByAssetObserver() { - } - void setMoveIntoFolderID(const LLUUID& into_folder_uuid) {mMoveIntoFolderID = into_folder_uuid; } + void setMoveIntoFolderID(const LLUUID& into_folder_uuid) { mMoveIntoFolderID = into_folder_uuid; } private: - /*virtual */void onAssetAdded(const LLUUID& asset_id) + /*virtual */ + void onAssetAdded(const LLUUID& asset_id) override { // Store active Inventory panel. if (LLInventoryPanel::getActiveInventoryPanel()) @@ -839,7 +884,7 @@ private: * Selects added inventory items watched by their Asset UUIDs if selection was not changed since * all items were started to watch (dropped into a folder). */ - void done() + void done() override { LLInventoryPanel* active_panel = dynamic_cast(mActivePanel.get()); @@ -859,7 +904,7 @@ private: { LLInventoryPanel* active_panel = dynamic_cast(mActivePanel.get()); - if (NULL == active_panel) + if (nullptr == active_panel) { return true; } @@ -876,7 +921,7 @@ private: LL_DEBUGS("Inventory_Move") << "Selected firstly: " << mSelectedItems.size() << ", now: " << selected_items.size() << ", difference: " << different_items.size() << LL_ENDL; - return different_items.size() > 0; + return !different_items.empty(); } LLHandle mActivePanel; @@ -898,7 +943,7 @@ private: LLUUID mMoveIntoFolderID; }; -LLViewerInventoryMoveFromWorldObserver* gInventoryMoveObserver = NULL; +LLViewerInventoryMoveFromWorldObserver* gInventoryMoveObserver = nullptr; void set_dad_inventory_item(LLInventoryItem* inv_item, const LLUUID& into_folder_uuid) { @@ -915,7 +960,7 @@ void set_dad_inventory_item(LLInventoryItem* inv_item, const LLUUID& into_folder * Used currently for dragging from inbox to regular inventory folders */ -class LLViewerInventoryMoveObserver : public LLInventoryObserver +class LLViewerInventoryMoveObserver final : public LLInventoryObserver { public: @@ -929,26 +974,26 @@ public: } } - virtual ~LLViewerInventoryMoveObserver() {} - virtual void changed(U32 mask); + virtual ~LLViewerInventoryMoveObserver() = default; + + void changed(U32 mask) override; private: LLUUID mObjectID; LLHandle mActivePanel; - }; void LLViewerInventoryMoveObserver::changed(U32 mask) { LLInventoryPanel* active_panel = dynamic_cast(mActivePanel.get()); - if (NULL == active_panel) + if (nullptr == active_panel) { gInventory.removeObserver(this); return; } - if((mask & (LLInventoryObserver::STRUCTURE)) != 0) + if ((mask & (STRUCTURE)) != 0) { const uuid_set_t& changed_items = gInventory.getChangedIDs(); @@ -980,15 +1025,16 @@ void set_dad_inbox_object(const LLUUID& object_id) //and it never dies. We do this because we don't know the UUID of //task offers until they are accepted, so we don't wouldn't //know what to watch for, so instead we just watch for all additions. -class LLOpenTaskOffer : public LLInventoryAddedObserver +class LLOpenTaskOffer final : public LLInventoryAddedObserver { protected: - /*virtual*/ void done() + /*virtual*/ + void done() override { uuid_vec_t added; - for(uuid_set_t::const_iterator it = gInventory.getAddedIDs().begin(); it != gInventory.getAddedIDs().end(); ++it) + for (auto it : gInventory.getAddedIDs()) { - added.push_back(*it); + added.push_back(it); } for (uuid_vec_t::iterator it = added.begin(); it != added.end();) { @@ -1019,17 +1065,18 @@ protected: open_inventory_offer(added, ""); } - }; +}; -class LLOpenTaskGroupOffer : public LLInventoryAddedObserver +class LLOpenTaskGroupOffer final : public LLInventoryAddedObserver { protected: - /*virtual*/ void done() + /*virtual*/ + void done() override { uuid_vec_t added; - for(uuid_set_t::const_iterator it = gInventory.getAddedIDs().begin(); it != gInventory.getAddedIDs().end(); ++it) + for (auto it : gInventory.getAddedIDs()) { - added.push_back(*it); + added.push_back(it); } open_inventory_offer(added, "group_offer"); gInventory.removeObserver(this); @@ -1038,17 +1085,19 @@ protected: }; //one global instance to bind them -LLOpenTaskOffer* gNewInventoryObserver=NULL; -class LLNewInventoryHintObserver : public LLInventoryAddedObserver +LLOpenTaskOffer* gNewInventoryObserver = nullptr; + +class LLNewInventoryHintObserver final : public LLInventoryAddedObserver { protected: - /*virtual*/ void done() + /*virtual*/ + void done() override { //LLFirstUse::newInventory(); } }; -LLNewInventoryHintObserver* gNewInventoryHintObserver=NULL; +LLNewInventoryHintObserver* gNewInventoryHintObserver = nullptr; void start_new_inventory_observer() { @@ -1074,7 +1123,7 @@ void start_new_inventory_observer() } } -class LLDiscardAgentOffer : public LLInventoryFetchItemsObserver +class LLDiscardAgentOffer final : public LLInventoryFetchItemsObserver { LOG_CLASS(LLDiscardAgentOffer); @@ -1082,9 +1131,11 @@ public: LLDiscardAgentOffer(const LLUUID& folder_id, const LLUUID& object_id) : LLInventoryFetchItemsObserver(object_id), mFolderID(folder_id), - mObjectID(object_id) {} + mObjectID(object_id) + { + } - virtual void done() + void done() override { LL_DEBUGS("Messaging") << "LLDiscardAgentOffer::done()" << LL_ENDL; @@ -1094,7 +1145,7 @@ public: // So defer moving the item to trash until viewer gets idle (in a moment). // Use removeObject() rather than removeItem() because at this level, // the object could be either an item or a folder. - LLAppViewer::instance()->addOnIdleCallback(boost::bind(&LLInventoryModel::removeObject, &gInventory, mObjectID)); + LLAppViewer::instance()->addOnIdleCallback(std::bind(&LLInventoryModel::removeObject, &gInventory, mObjectID)); gInventory.removeObserver(this); delete this; } @@ -1113,7 +1164,6 @@ bool check_offer_throttle(const std::string& from_name, bool check_only) static U32 throttle_count; static bool throttle_logged; LLChat chat; - std::string log_message; if (!gSavedSettings.getBOOL("ShowNewInventory")) return false; @@ -1123,58 +1173,53 @@ bool check_offer_throttle(const std::string& from_name, bool check_only) return gThrottleTimer.hasExpired(); } - if(gThrottleTimer.checkExpirationAndReset(OFFER_THROTTLE_TIME)) + if (gThrottleTimer.checkExpirationAndReset(OFFER_THROTTLE_TIME)) { LL_DEBUGS("Messaging") << "Throttle Expired" << LL_ENDL; - throttle_count=1; - throttle_logged=false; + throttle_count = 1; + throttle_logged = false; return true; } - else //has not expired + //has not expired + LL_DEBUGS("Messaging") << "Throttle Not Expired, Count: " << throttle_count << LL_ENDL; + // When downloading the initial inventory we get a lot of new items + // coming in and can't tell that from spam. + if (LLStartUp::getStartupState() >= STATE_STARTED + && throttle_count >= OFFER_THROTTLE_MAX_COUNT) { - LL_DEBUGS("Messaging") << "Throttle Not Expired, Count: " << throttle_count << LL_ENDL; - // When downloading the initial inventory we get a lot of new items - // coming in and can't tell that from spam. - if (LLStartUp::getStartupState() >= STATE_STARTED - && throttle_count >= OFFER_THROTTLE_MAX_COUNT) + if (!throttle_logged) { - if (!throttle_logged) + // Use the name of the last item giver, who is probably the person + // spamming you. + + LLStringUtil::format_map_t arg; + std::string log_msg; + std::ostringstream time; + time << OFFER_THROTTLE_TIME; + + arg["APP_NAME"] = LLAppViewer::instance()->getSecondLifeTitle(); + arg["TIME"] = time.str(); + + if (!from_name.empty()) { - // Use the name of the last item giver, who is probably the person - // spamming you. - - LLStringUtil::format_map_t arg; - std::string log_msg; - std::ostringstream time ; - time<getSecondLifeTitle(); - arg["TIME"] = time.str(); - - if (!from_name.empty()) - { - arg["FROM_NAME"] = from_name; - log_msg = LLTrans::getString("ItemsComingInTooFastFrom", arg); - } - else - { - log_msg = LLTrans::getString("ItemsComingInTooFast", arg); - } - - //this is kinda important, so actually put it on screen - chat.mText = log_msg; - LLFloaterChat::addChat(chat, FALSE, FALSE); - - throttle_logged=true; + arg["FROM_NAME"] = from_name; + log_msg = LLTrans::getString("ItemsComingInTooFastFrom", arg); } - return false; - } - else - { - throttle_count++; - return true; + else + { + log_msg = LLTrans::getString("ItemsComingInTooFast", arg); + } + + //this is kinda important, so actually put it on screen + chat.mText = log_msg; + LLFloaterChat::addChat(chat, FALSE, FALSE); + + throttle_logged = true; } + return false; } + throttle_count++; + return true; } // Return "true" if we have a preview method for that asset type, "false" otherwise @@ -1191,17 +1236,14 @@ bool check_asset_previewable(const LLAssetType::EType asset_type) void open_inventory_offer(const uuid_vec_t& objects, const std::string& from_name) { if (gAgent.isDoNotDisturb()) return; - for (uuid_vec_t::const_iterator obj_iter = objects.begin(); - obj_iter != objects.end(); - ++obj_iter) + for (auto obj_id : objects) { - const LLUUID& obj_id = (*obj_iter); - if(!highlight_offered_object(obj_id)) + if (!highlight_offered_object(obj_id)) { continue; } - const LLInventoryObject *obj = gInventory.getObject(obj_id); + const LLInventoryObject* obj = gInventory.getObject(obj_id); if (!obj) { LL_WARNS() << "Cannot find object [ itemID:" << obj_id << " ] to open." << LL_ENDL; @@ -1290,7 +1332,7 @@ void open_inventory_offer(const uuid_vec_t& objects, const std::string& from_nam bool highlight_offered_object(const LLUUID& obj_id) { const LLInventoryObject* obj = gInventory.getObject(obj_id); - if(!obj) + if (!obj) { LL_WARNS("Messaging") << "Unable to show inventory item: " << obj_id << LL_ENDL; return false; @@ -1299,9 +1341,9 @@ bool highlight_offered_object(const LLUUID& obj_id) //////////////////////////////////////////////////////////////////////////////// // Don't highlight if it's in certain "quiet" folders which don't need UI // notification (e.g. trash, cof, lost-and-found). - if(!gAgent.getAFK()) + if (!gAgent.getAFK()) { - const LLViewerInventoryCategory *parent = gInventory.getFirstNondefaultParent(obj_id); + const LLViewerInventoryCategory* parent = gInventory.getFirstNondefaultParent(obj_id); if (parent) { const LLFolderType::EType parent_type = parent->getPreferredType(); @@ -1330,11 +1372,14 @@ void inventory_offer_mute_callback(const LLUUID& blocked_id, } // purge the message queue of any previously queued inventory offers from the same source. - class OfferMatcher : public LLNotifyBoxView::Matcher + class OfferMatcher final : public LLNotifyBoxView::Matcher { public: - OfferMatcher(const LLUUID& to_block) : blocked_id(to_block) {} - bool matches(const LLNotificationPtr notification) const + OfferMatcher(const LLUUID& to_block) : blocked_id(to_block) + { + } + + bool matches(const LLNotificationPtr notification) const override { if(notification->getName() == "ObjectGiveItem" || notification->getName() == "ObjectGiveItemUnknownUser" @@ -1344,6 +1389,7 @@ void inventory_offer_mute_callback(const LLUUID& blocked_id, } return FALSE; } + private: const LLUUID& blocked_id; }; @@ -1419,6 +1465,8 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& return false; } + chat.mSourceType = CHAT_SOURCE_SYSTEM; // There's a slim potential of a user-editable field being a url here? + LLViewerInventoryCategory* catp = NULL; catp = gInventory.getCategory(mObjectID); LLViewerInventoryItem* itemp = NULL; @@ -1564,8 +1612,11 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& //don't spam them if they are getting flooded if (check_offer_throttle(mFromName, true)) { - log_message = chatHistory_string + " " + LLTrans::getString("InvOfferGaveYou") + " " + mDesc + LLTrans::getString("."); + log_message = chatHistory_string + ' ' + LLTrans::getString("InvOfferGaveYou") + ' ' + mDesc + LLTrans::getString("."); chat.mText = log_message; + if (mFromObject || !mFromGroup) + chat.mURL = mFromGroup ? LLGroupActions::getSLURL(mFromID) : LLAvatarActions::getSLURL(mFromID); + chat.mFromName = mFromName; LLFloaterChat::addChatHistory(chat); } @@ -1733,7 +1784,6 @@ bool has_spam_bypass(bool is_friend, bool is_owned_by_me) return (antispam_not_mine && is_owned_by_me) || (antispam_not_friend && is_friend); } -void script_msg_api(const std::string& msg); bool is_spam_filtered(const EInstantMessage& dialog, bool is_friend, bool is_owned_by_me) { // First, check that this doesn't bypass. @@ -1749,225 +1799,51 @@ bool is_spam_filtered(const EInstantMessage& dialog, bool is_friend, bool is_own case IM_GROUP_NOTICE: case IM_GROUP_NOTICE_REQUESTED: { - static LLCachedControl filter(gSavedSettings, "AntiSpamGroupNotices"); - if (!filter) return false; - break; + static const LLCachedControl filter("AntiSpamGroupNotices"); + return filter; } case IM_GROUP_INVITATION: { - static LLCachedControl filter(gSavedSettings, "AntiSpamGroupInvites"); - if (!filter) return false; - break; + static const LLCachedControl filter("AntiSpamGroupInvites"); + return filter; } case IM_INVENTORY_OFFERED: case IM_TASK_INVENTORY_OFFERED: { - static LLCachedControl filter(gSavedSettings, "AntiSpamItemOffers"); - if (!filter) return false; - break; + static const LLCachedControl filter("AntiSpamItemOffers"); + return filter; } case IM_FROM_TASK_AS_ALERT: { - static LLCachedControl filter(gSavedSettings, "AntiSpamAlerts"); - if (!filter) return false; - break; + static const LLCachedControl filter("AntiSpamAlerts"); + return filter; } case IM_LURE_USER: { - static LLCachedControl filter(gSavedSettings, "AntiSpamTeleports"); - if (!filter) return false; - break; + static const LLCachedControl filter("AntiSpamTeleports"); + return filter; } case IM_TELEPORT_REQUEST: { - static LLCachedControl filter(gSavedSettings, "AntiSpamTeleportRequests"); - if (!filter) return false; - break; + static const LLCachedControl filter("AntiSpamTeleportRequests"); + return filter; } case IM_FRIENDSHIP_OFFERED: { - static LLCachedControl filter(gSavedSettings, "AntiSpamFriendshipOffers"); - if (!filter) return false; - break; + static const LLCachedControl filter("AntiSpamFriendshipOffers"); + return filter; } case IM_COUNT: { // Bit of a hack, we should never get here unless we did this on purpose, though, doesn't matter because we'd do nothing anyway - static LLCachedControl filter(gSavedSettings, "AntiSpamScripts"); - if (!filter) return false; - break; + static const LLCachedControl filter( "AntiSpamScripts"); + return filter; } default: return false; } - - // Last, definitely filter - return true; } -void inventory_offer_handler(LLOfferInfo* info, bool is_friend, bool is_owned_by_me) -{ - static const LLCachedControl no_landmarks(gSavedSettings, "AntiSpamItemOffersLandmarks"); - // NaCl - Antispam Registry - if (NACLAntiSpamRegistry::checkQueue((U32)NACLAntiSpamRegistry::QUEUE_INVENTORY,info->mFromID) - || (!has_spam_bypass(is_friend, is_owned_by_me) - && (no_landmarks && info->mType == LLAssetType::AT_LANDMARK))) - { - delete info; - return; - } - // NaCl End - //If muted, don't even go through the messaging stuff. Just curtail the offer here. - if (LLMuteList::getInstance()->isMuted(info->mFromID, info->mFromName)) - { - info->forceResponse(IOR_MUTE); - return; - } - - if (!info->mFromGroup) script_msg_api(info->mFromID.asString() + ", 1"); - - // If the user wants to, accept all offers of any kind - if (gSavedSettings.getBOOL("AutoAcceptAllNewInventory")) - { - info->forceResponse(IOR_ACCEPT); - return; - } - - // Avoid the Accept/Discard dialog if the user so desires. JC - if (gSavedSettings.getBOOL("AutoAcceptNewInventory") - && (info->mType == LLAssetType::AT_NOTECARD - || info->mType == LLAssetType::AT_LANDMARK - || info->mType == LLAssetType::AT_TEXTURE)) - { - // For certain types, just accept the items into the inventory, - // and possibly open them on receipt depending upon "ShowNewInventory". - info->forceResponse(IOR_ACCEPT); - return; - } - - if (gAgent.isDoNotDisturb() && info->mIM != IM_TASK_INVENTORY_OFFERED) // busy mode must not affect interaction with objects (STORM-565) - { - // Until throttling is implemented, busy mode should reject inventory instead of silently - // accepting it. SEE SL-39554 - info->forceResponse(IOR_DECLINE); - return; - } - - // Strip any SLURL from the message display. (DEV-2754) - std::string msg = info->mDesc; - int indx = msg.find(" ( http://slurl.com/secondlife/"); - if(indx == std::string::npos) - { - // try to find new slurl host - indx = msg.find(" ( http://maps.secondlife.com/secondlife/"); - } - if(indx >= 0) - { - LLStringUtil::truncate(msg, indx); - } - - LLSD args; - args["[OBJECTNAME]"] = msg; - - LLSD payload; - - // must protect against a NULL return from lookupHumanReadable() - std::string typestr = ll_safe_string(LLAssetType::lookupHumanReadable(info->mType)); - if (!typestr.empty()) - { - // human readable matches string name from strings.xml - // lets get asset type localized name - args["OBJECTTYPE"] = LLTrans::getString(typestr); - } - else - { - LL_WARNS("Messaging") << "LLAssetType::lookupHumanReadable() returned NULL - probably bad asset type: " << info->mType << LL_ENDL; - args["OBJECTTYPE"] = ""; - - // This seems safest, rather than propagating bogosity - LL_WARNS("Messaging") << "Forcing an inventory-decline for probably-bad asset type." << LL_ENDL; - info->forceResponse(IOR_DECLINE); - return; - } - - // Name cache callbacks don't store userdata, so can't save - // off the LLOfferInfo. Argh. - BOOL name_found = FALSE; - payload["from_id"] = info->mFromID; - args["OBJECTFROMNAME"] = info->mFromName; - args["NAME"] = info->mFromName; - if (info->mFromGroup) - { - std::string group_name; - if (gCacheName->getGroupName(info->mFromID, group_name)) - { - args["NAME"] = group_name; - name_found = TRUE; - } - } - else - { - std::string full_name; - if (gCacheName->getFullName(info->mFromID, full_name)) - { -// [RLVa:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a - // Only filter if the object owner is a nearby agent - if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (RlvUtil::isNearbyAgent(info->mFromID)) ) - { - full_name = RlvStrings::getAnonym(full_name); - } -// [/RLVa:KB] - args["NAME"] = full_name; - name_found = TRUE; - } - } - - - LLNotification::Params p("ObjectGiveItem"); - p.substitutions(args).payload(payload).functor(boost::bind(&LLOfferInfo::inventory_offer_callback, info, _1, _2)); - - // Object -> Agent Inventory Offer - if (info->mFromObject) - { - p.name = name_found ? "ObjectGiveItem" : "ObjectGiveItemUnknownUser"; - } - else // Agent -> Agent Inventory Offer - { -// [RLVa:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a - // Only filter if the offer is from a nearby agent and if there's no open IM session (doesn't necessarily have to be focused) - if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (RlvUtil::isNearbyAgent(info->mFromID)) && - (!RlvUIEnabler::hasOpenIM(info->mFromID)) ) - { - args["NAME"] = RlvStrings::getAnonym(info->mFromName); - } -// [/RLVa:KB] - p.name = "UserGiveItem"; - } - - LLNotifications::instance().add(p); -} - - -bool group_vote_callback(const LLSD& notification, const LLSD& response) -{ - LLUUID group_id = notification["payload"]["group_id"].asUUID(); - S32 option = LLNotification::getSelectedOption(notification, response); - switch(option) - { - case 0: - // Vote Now - // Open up the voting tab - LLGroupActions::showTab(group_id, "voting_tab"); - break; - default: - // Vote Later or - // close button - break; - } - return false; -} -static LLNotificationFunctorRegistration group_vote_callback_reg("GroupVote", group_vote_callback); - bool lure_callback(const LLSD& notification, const LLSD& response) { S32 option = 0; @@ -1984,7 +1860,7 @@ bool lure_callback(const LLSD& notification, const LLSD& response) LLUUID lure_id = notification["payload"]["lure_id"].asUUID(); BOOL godlike = notification["payload"]["godlike"].asBoolean(); - switch(option) + switch (option) { case 0: { @@ -1992,11 +1868,6 @@ bool lure_callback(const LLSD& notification, const LLSD& response) gAgent.teleportViaLure(lure_id, godlike); } break; - case 3: - // profile - LLAvatarActions::showProfile(from_id); - LLNotificationsUtil::add(notification["name"], notification["substitutions"], notification["payload"]); //Respawn! - break; case 1: default: // decline @@ -2021,246 +1892,6 @@ bool goto_url_callback(const LLSD& notification, const LLSD& response) return false; } static LLNotificationFunctorRegistration goto_url_callback_reg("GotoURL", goto_url_callback); -static bool parse_lure_bucket(const std::string& bucket, - U64& region_handle, - LLVector3& pos, - LLVector3& look_at, - U8& region_access) -{ - // tokenize the bucket - typedef boost::tokenizer > tokenizer; - boost::char_separator sep("|", "", boost::keep_empty_tokens); - tokenizer tokens(bucket, sep); - tokenizer::iterator iter = tokens.begin(); - - S32 gx,gy,rx,ry,rz,lx,ly,lz; - try - { - gx = std::stoi(*(iter)); - gy = std::stoi(*(++iter)); - rx = std::stoi(*(++iter)); - ry = std::stoi(*(++iter)); - rz = std::stoi(*(++iter)); - lx = std::stoi(*(++iter)); - ly = std::stoi(*(++iter)); - lz = std::stoi(*(++iter)); - } - catch( const std::invalid_argument& ) - { - LL_WARNS("parse_lure_bucket") - << "Couldn't parse lure bucket." - << LL_ENDL; - return false; - } - catch( const std::out_of_range& ) - { - LL_WARNS("parse_lure_bucket") - << "Couldn't parse lure bucket." - << LL_ENDL; - return false; - } - // Grab region access - region_access = SIM_ACCESS_MIN; - if (++iter != tokens.end()) - { - std::string access_str((*iter).c_str()); - LLStringUtil::trim(access_str); - if ( access_str == "A" ) - { - region_access = SIM_ACCESS_ADULT; - } - else if ( access_str == "M" ) - { - region_access = SIM_ACCESS_MATURE; - } - else if ( access_str == "PG" ) - { - region_access = SIM_ACCESS_PG; - } - } - - pos.setVec((F32)rx, (F32)ry, (F32)rz); - look_at.setVec((F32)lx, (F32)ly, (F32)lz); - - region_handle = to_region_handle(gx, gy); - return true; -} - -// Strip out "Resident" for display, but only if the message came from a user -// (rather than a script) -static std::string clean_name_from_im(const std::string& name, EInstantMessage type) -{ - switch(type) - { - case IM_NOTHING_SPECIAL: - case IM_MESSAGEBOX: - case IM_GROUP_INVITATION: - case IM_INVENTORY_OFFERED: - case IM_INVENTORY_ACCEPTED: - case IM_INVENTORY_DECLINED: - case IM_GROUP_VOTE: - case IM_GROUP_MESSAGE_DEPRECATED: - //IM_TASK_INVENTORY_OFFERED - //IM_TASK_INVENTORY_ACCEPTED - //IM_TASK_INVENTORY_DECLINED - case IM_NEW_USER_DEFAULT: - case IM_SESSION_INVITE: - case IM_SESSION_P2P_INVITE: - case IM_SESSION_GROUP_START: - case IM_SESSION_CONFERENCE_START: - case IM_SESSION_SEND: - case IM_SESSION_LEAVE: - //IM_FROM_TASK - case IM_BUSY_AUTO_RESPONSE: - case IM_CONSOLE_AND_CHAT_HISTORY: - case IM_LURE_USER: - case IM_LURE_ACCEPTED: - case IM_LURE_DECLINED: - case IM_GODLIKE_LURE_USER: - case IM_TELEPORT_REQUEST: - case IM_GROUP_ELECTION_DEPRECATED: - //IM_GOTO_URL - //IM_FROM_TASK_AS_ALERT - case IM_GROUP_NOTICE: - case IM_GROUP_NOTICE_INVENTORY_ACCEPTED: - case IM_GROUP_NOTICE_INVENTORY_DECLINED: - case IM_GROUP_INVITATION_ACCEPT: - case IM_GROUP_INVITATION_DECLINE: - case IM_GROUP_NOTICE_REQUESTED: - case IM_FRIENDSHIP_OFFERED: - case IM_FRIENDSHIP_ACCEPTED: - case IM_FRIENDSHIP_DECLINED_DEPRECATED: - case IM_TYPING_START: - //IM_TYPING_STOP - return LLCacheName::cleanFullName(name); - default: - return name; - } -} - -static std::string clean_name_from_task_im(const std::string& msg, - BOOL from_group) -{ - boost::smatch match; - static const boost::regex returned_exp( - "(.*been returned to your inventory lost and found folder by )(.+)( (from|near).*)"); - if (boost::regex_match(msg, match, returned_exp)) - { - // match objects are 1-based for groups - std::string final = match[1].str(); - std::string name = match[2].str(); - // Don't try to clean up group names - if (!from_group) - { - if (LLAvatarName::useDisplayNames()) - { - // ...just convert to username - final += LLCacheName::buildUsername(name); - } - else - { - // ...strip out legacy "Resident" name - final += LLCacheName::cleanFullName(name); - } - } - final += match[3].str(); - return final; - } - return msg; -} - -void notification_display_name_callback(const LLUUID& id, - const LLAvatarName& av_name, - const std::string& name, - LLSD& substitutions, - const LLSD& payload) -{ - substitutions["NAME"] = av_name.getDisplayName(); - LLNotificationsUtil::add(name, substitutions, payload); -} - -// Callback for name resolution of a god/estate message -void god_message_name_cb(const LLAvatarName& av_name, LLChat chat, std::string message) -{ - LLSD args; - args["NAME"] = av_name.getNSName(); - args["MESSAGE"] = message; - LLNotificationsUtil::add("GodMessage", args); - - // Treat like a system message and put in chat history. - chat.mText = av_name.getNSName() + ": " + message; - - // Claim to be from a local agent so it doesn't go into console. - LLFloaterChat::addChat(chat, false, true); - -} - -// Replace wild cards in message strings -std::string replace_wildcards(std::string input, const LLUUID& id, const std::string& name) -{ - boost::algorithm::replace_all(input, "#n", name); - - LLSLURL slurl; - LLAgentUI::buildSLURL(slurl); - boost::algorithm::replace_all(input, "#r", slurl.getSLURLString()); - - LLAvatarName av_name; - boost::algorithm::replace_all(input, "#d", LLAvatarNameCache::get(id, &av_name) ? av_name.getDisplayName() : name); - - if (isAgentAvatarValid()) - { - LLStringUtil::format_map_t args; - args["[MINS]"] = boost::lexical_cast(gAgentAvatarp->mIdleTimer.getElapsedTimeF32()/60); - boost::algorithm::replace_all(input, "#i", LLTrans::getString("IM_autoresponse_minutes", args)); - } - - return input; -} - -void autoresponder_finish(bool show_autoresponded, const LLUUID& session_id, const LLUUID& from_id, const std::string& name, const LLUUID& itemid, bool is_muted) -{ - void cmdline_printchat(const std::string& message); - if (show_autoresponded) - { - const std::string notice(LLTrans::getString("IM_autoresponded_to") + ' ' + LLAvatarActions::getSLURL(from_id)); - is_muted ? cmdline_printchat(notice) : gIMMgr->addMessage(session_id, from_id, name, notice); - } - if (LLViewerInventoryItem* item = gInventory.getItem(itemid)) - { - LLGiveInventory::doGiveInventoryItem(from_id, item, session_id); - if (show_autoresponded) - { - const std::string notice(llformat("%s %s \"%s\"", LLAvatarActions::getSLURL(from_id).data(), LLTrans::getString("IM_autoresponse_sent_item").c_str(), item->getName().c_str())); - is_muted ? cmdline_printchat(notice) : gIMMgr->addMessage(session_id, from_id, name, notice); - } - } -} - -#include -const std::string NOT_ONLINE_MSG("User not online - message will be stored and delivered later."); -const std::string NOT_ONLINE_INVENTORY("User not online - inventory has been saved."); -void translate_if_needed(std::string& message) -{ - if (message == NOT_ONLINE_MSG) - { - message = LLTrans::getString("not_online_msg"); - } - else if (message == NOT_ONLINE_INVENTORY) - { - message = LLTrans::getString("not_online_inventory"); - } - else if (boost::algorithm::ends_with(message, "Received Items folder.")) - { - boost::smatch match; - const boost::regex gift_exp("^You've received a gift! (.*) has given you \\\"(.*)\\\", and says \\\"(.*)\\\"\\. You can find your gift in your Received Items folder\\.$"); - bool gift = boost::regex_match(message, match, gift_exp); - if (gift || boost::regex_match(message, match, boost::regex("^Your purchase of (.*) has been delivered to your Received Items folder\\.$"))) - message = LLTrans::getString(gift ? "ReceivedGift" : "ReceivedPurchase", - gift ? LLSD().with("USER", match[1].str()).with("PRODUCT", match[2].str()).with("MESSAGE", match[3].str()) - : LLSD().with("PRODUCT", match[1].str())); - if (gSavedSettings.getBOOL("LiruReceivedItemsNotify")) LLNotificationsUtil::add("SystemMessage", LLSD().with("MESSAGE", message)); - } -} void process_improved_im(LLMessageSystem *msg, void **user_data) { @@ -2275,41 +1906,39 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) U8 d = 0; LLUUID session_id; U32 timestamp; - std::string name; + std::string agentName; std::string message; U32 parent_estate_id = 0; LLUUID region_id; LLVector3 position; U8 binary_bucket[MTUBYTES]; S32 binary_bucket_size; - LLChat chat; - std::string buffer; // *TODO: Translate - need to fix the full name to first/last (maybe) msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, from_id); msg->getBOOLFast(_PREHASH_MessageBlock, _PREHASH_FromGroup, from_group); msg->getUUIDFast(_PREHASH_MessageBlock, _PREHASH_ToAgentID, to_id); - msg->getU8Fast( _PREHASH_MessageBlock, _PREHASH_Offline, offline); - msg->getU8Fast( _PREHASH_MessageBlock, _PREHASH_Dialog, d); + msg->getU8Fast(_PREHASH_MessageBlock, _PREHASH_Offline, offline); + msg->getU8Fast(_PREHASH_MessageBlock, _PREHASH_Dialog, d); msg->getUUIDFast(_PREHASH_MessageBlock, _PREHASH_ID, session_id); - msg->getU32Fast( _PREHASH_MessageBlock, _PREHASH_Timestamp, timestamp); + msg->getU32Fast(_PREHASH_MessageBlock, _PREHASH_Timestamp, timestamp); //msg->getData("MessageBlock", "Count", &count); - msg->getStringFast(_PREHASH_MessageBlock, _PREHASH_FromAgentName, name); + msg->getStringFast(_PREHASH_MessageBlock, _PREHASH_FromAgentName, agentName); msg->getStringFast(_PREHASH_MessageBlock, _PREHASH_Message, message); // NaCl - Newline flood protection - static LLCachedControl AntiSpamEnabled(gSavedSettings,"AntiSpamEnabled",false); - if (AntiSpamEnabled && can_block(from_id)) + auto antispam = NACLAntiSpamRegistry::getIfExists(); + if (antispam && can_block(from_id)) { - static LLCachedControl SpamNewlines(gSavedSettings,"_NACL_AntiSpamNewlines"); + static const LLCachedControl SpamNewlines("_NACL_AntiSpamNewlines"); boost::sregex_iterator iter(message.begin(), message.end(), NEWLINES); if((U32)std::abs(std::distance(iter, boost::sregex_iterator())) > SpamNewlines) { - NACLAntiSpamRegistry::blockOnQueue((U32)NACLAntiSpamRegistry::QUEUE_IM,from_id); + antispam->blockOnQueue(NACLAntiSpamRegistry::QUEUE_IM, from_id); LL_INFOS() << "[antispam] blocked owner due to too many newlines: " << from_id << LL_ENDL; - if(gSavedSettings.getBOOL("AntiSpamNotify")) + if (gSavedSettings.getBOOL("AntiSpamNotify")) { LLSD args; - args["SOURCE"] = from_id.asString(); + args["SOURCE"] = from_id; args["AMOUNT"] = boost::lexical_cast(SpamNewlines); LLNotificationsUtil::add("AntiSpamNewlineFlood", args); } @@ -2320,1218 +1949,33 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) msg->getU32Fast(_PREHASH_MessageBlock, _PREHASH_ParentEstateID, parent_estate_id); msg->getUUIDFast(_PREHASH_MessageBlock, _PREHASH_RegionID, region_id); msg->getVector3Fast(_PREHASH_MessageBlock, _PREHASH_Position, position); - msg->getBinaryDataFast( _PREHASH_MessageBlock, _PREHASH_BinaryBucket, binary_bucket, 0, 0, MTUBYTES); + msg->getBinaryDataFast(_PREHASH_MessageBlock, _PREHASH_BinaryBucket, binary_bucket, 0, 0, MTUBYTES); binary_bucket_size = msg->getSizeFast(_PREHASH_MessageBlock, _PREHASH_BinaryBucket); EInstantMessage dialog = (EInstantMessage)d; // NaCl - Antispam Registry - if((dialog != IM_TYPING_START && dialog != IM_TYPING_STOP) - && NACLAntiSpamRegistry::checkQueue((U32)NACLAntiSpamRegistry::QUEUE_IM,from_id)) + if (antispam && (dialog != IM_TYPING_START && dialog != IM_TYPING_STOP) + && antispam->checkQueue(NACLAntiSpamRegistry::QUEUE_IM, from_id)) return; // NaCl End - // make sure that we don't have an empty or all-whitespace name - LLStringUtil::trim(name); - if (name.empty()) - { - name = LLTrans::getString("Unnamed"); - } - - // Preserve the unaltered name for use in group notice mute checking. - std::string original_name = name; - - // IDEVO convert new-style "Resident" names for display - name = clean_name_from_im(name, dialog); - - // - if (region_id.notNull()) - LL_INFOS() << "RegionID: " << region_id.asString() << LL_ENDL; - // - - bool is_do_not_disturb = gAgent.isDoNotDisturb(); - bool is_muted = LLMuteList::getInstance()->isMuted(from_id, name, LLMute::flagTextChat) - // object IMs contain sender object id in session_id (STORM-1209) - || (dialog == IM_FROM_TASK && LLMuteList::getInstance()->isMuted(session_id)); - bool is_owned_by_me = false; - bool is_friend = (LLAvatarTracker::instance().getBuddyInfo(from_id) == NULL) ? false : true; - bool accept_im_from_only_friend = gSavedSettings.getBOOL("InstantMessagesFriendsOnly"); - bool is_linden = chat.mSourceType != CHAT_SOURCE_OBJECT && - LLMuteList::getInstance()->isLinden(name); - - chat.mMuted = is_muted && !is_linden; - chat.mFromID = from_id; - chat.mFromName = name; - chat.mSourceType = (from_id.isNull() || (name == std::string(SYSTEM_FROM))) ? CHAT_SOURCE_SYSTEM : CHAT_SOURCE_AGENT; - - if(chat.mSourceType == CHAT_SOURCE_AGENT) - { - LLSD args; - args["NAME"] = name; - } - - // Singu TODO: LLIMProcessing goes here - if (chat.mSourceType == CHAT_SOURCE_SYSTEM) - { // Translate server message if required (MAINT-6109) - translate_if_needed(message); - } - - LLViewerObject *source = gObjectList.findObject(session_id); //Session ID is probably the wrong thing. - if (source || (source = gObjectList.findObject(from_id))) - { - is_owned_by_me = source->permYouOwner(); - } - - // NaCl - Antispam - if (is_spam_filtered(dialog, is_friend, is_owned_by_me)) return; - // NaCl End - - std::string separator_string(": "); - int message_offset = 0; - - //Handle IRC styled /me messages. - std::string prefix = message.substr(0, 4); - if (prefix == "/me " || prefix == "/me'") - { - chat.mChatStyle = CHAT_STYLE_IRC; - separator_string = ""; - message_offset = 3; - } - - // These bools are here because they would make mess of logic down below in IM_NOTHING_SPECIAL. - static LLCachedControl sAutorespond(gSavedPerAccountSettings, "AutoresponseAnyone", false); - static LLCachedControl sAutorespondFriendsOnly(gSavedPerAccountSettings, "AutoresponseAnyoneFriendsOnly", false); - static LLCachedControl sAutorespondAway(gSavedPerAccountSettings, "AutoresponseOnlyIfAway", false); - static LLCachedControl sAutorespondNonFriend(gSavedPerAccountSettings, "AutoresponseNonFriends", false); - static LLCachedControl sAutorespondMuted(gSavedPerAccountSettings, "AutoresponseMuted", false); - static LLCachedControl sAutorespondRepeat(gSavedPerAccountSettings, "AscentInstantMessageResponseRepeat", false); - static LLCachedControl sFakeAway(gSavedSettings, "FakeAway", false); - bool autorespond_status = !sAutorespondAway || sFakeAway || gAgent.getAFK(); - bool is_autorespond = !is_muted && autorespond_status && (is_friend || !sAutorespondFriendsOnly) && sAutorespond; - bool is_autorespond_muted = is_muted && sAutorespondMuted; - bool is_autorespond_nonfriends = !is_friend && !is_muted && autorespond_status && sAutorespondNonFriend; - - LLSD args; - switch(dialog) - { - case IM_CONSOLE_AND_CHAT_HISTORY: - args["MESSAGE"] = message; - - // Note: don't put the message in the IM history, even though was sent - // via the IM mechanism. - LLNotificationsUtil::add("SystemMessageTip",args); - break; - - case IM_NOTHING_SPECIAL: // p2p IM - // Don't show dialog, just do IM - if (!gAgent.isGodlike() - && gAgent.getRegion()->isPrelude() - && to_id.isNull() ) - { - // do nothing -- don't distract newbies in - // Prelude with global IMs - } -// [RLVa:KB] - Checked: 2011-05-28 (RLVa-1.4.0) - else if ( (rlv_handler_t::isEnabled()) && (offline == IM_ONLINE) && ("@version" == message) && - (!is_muted) && ((!accept_im_from_only_friend) || (is_friend)) ) - { - RlvUtil::sendBusyMessage(from_id, RlvStrings::getVersion(), session_id); - // We won't receive a typing stop message, so do that manually (see comment at the end of LLFloaterIMPanel::sendMsg) - LLPointer im_info = new LLIMInfo(gMessageSystem); - gIMMgr->processIMTypingStop(im_info); - } -// [/RLVa:KB] - else if (offline == IM_ONLINE - && is_do_not_disturb - && !is_muted // Note: Never if muted - && from_id.notNull() //not a system message - && to_id.notNull() //not global message -// [RLVa:KB] - Checked: 2010-11-30 (RLVa-1.3.0) - && RlvActions::canReceiveIM(from_id)) -// [/RLVa:KB] - { - // now store incoming IM in chat history - buffer = separator_string + message.substr(message_offset); - - LL_INFOS("Messaging") << "process_improved_im: session_id( " << session_id << " ), from_id( " << from_id << " )" << LL_ENDL; - script_msg_api(from_id.asString() + ", 0"); - - // add to IM panel, but do not bother the user - gIMMgr->addMessage( - session_id, - from_id, - name, - buffer, - name, - dialog, - parent_estate_id, - region_id, - position, - true); - - // pretend this is chat generated by self, so it does not show up on screen - chat.mText = std::string("IM: ") + name + separator_string + message.substr(message_offset); - LLFloaterChat::addChat(chat, true, true); - - if (sAutorespondRepeat || !gIMMgr->hasSession(session_id)) - { - // if the user wants to repeat responses over and over or - // if there is not a panel for this conversation (i.e. it is a new IM conversation - // initiated by the other party) then... - // return a standard "do not disturb" message, but only do it to online IM - // (i.e. not other auto responses and not store-and-forward IM) - send_do_not_disturb_message(msg, from_id, session_id); - } - - } - else if (offline == IM_ONLINE - && (is_autorespond || is_autorespond_nonfriends || is_autorespond_muted) - && from_id.notNull() //not a system message - && to_id.notNull() //not global message -// [RLVa:LF] - Same as above: Checked: 2010-11-30 (RLVa-1.3.0) - && RlvActions::canReceiveIM(from_id) && RlvActions::canSendIM(from_id)) -// [/RLVa:LF] - { - buffer = separator_string + message.substr(message_offset); - - LL_INFOS("Messaging") << "process_improved_im: session_id( " << session_id << " ), from_id( " << from_id << " )" << LL_ENDL; - if (!is_muted) script_msg_api(from_id.asString() + ", 0"); - - bool send_response = !gIMMgr->hasSession(session_id) || sAutorespondRepeat; - - // add to IM panel, but do not bother the user - gIMMgr->addMessage(session_id, - from_id, - name, - buffer, - name, - dialog, - parent_estate_id, - region_id, - position, - true); - - // pretend this is chat generated by self, so it does not show up on screen - chat.mText = std::string("IM: ") + name + separator_string + message.substr(message_offset); - LLFloaterChat::addChat( chat, TRUE, TRUE ); - - if (send_response) - { - // if there is not a panel for this conversation (i.e. it is a new IM conversation - // initiated by the other party) then... - std::string my_name; - LLAgentUI::buildFullname(my_name); - std::string response; - bool show_autoresponded = false; - LLUUID itemid; - if (is_muted) - { - response = gSavedPerAccountSettings.getString("AutoresponseMutedMessage"); - if (gSavedPerAccountSettings.getBOOL("AutoresponseMutedItem")) - itemid = static_cast(gSavedPerAccountSettings.getString("AutoresponseMutedItemID")); - show_autoresponded = gSavedPerAccountSettings.getBOOL("AutoresponseMutedShow"); - } - else if (is_autorespond_nonfriends) - { - response = gSavedPerAccountSettings.getString("AutoresponseNonFriendsMessage"); - if (gSavedPerAccountSettings.getBOOL("AutoresponseNonFriendsItem")) - itemid = static_cast(gSavedPerAccountSettings.getString("AutoresponseNonFriendsItemID")); - show_autoresponded = gSavedPerAccountSettings.getBOOL("AutoresponseNonFriendsShow"); - } - else if (is_autorespond) - { - response = gSavedPerAccountSettings.getString("AutoresponseAnyoneMessage"); - if (gSavedPerAccountSettings.getBOOL("AutoresponseAnyoneItem")) - itemid = static_cast(gSavedPerAccountSettings.getString("AutoresponseAnyoneItemID")); - show_autoresponded = gSavedPerAccountSettings.getBOOL("AutoresponseAnyoneShow"); - } - pack_instant_message( - gMessageSystem, - gAgentID, - FALSE, - gAgentSessionID, - from_id, - my_name, - replace_wildcards(response, from_id, name), - IM_ONLINE, - IM_BUSY_AUTO_RESPONSE, - session_id); - gAgent.sendReliableMessage(); - - autoresponder_finish(show_autoresponded, session_id, from_id, name, itemid, is_muted); - } - } - else if (from_id.isNull()) - { - // Messages from "Second Life" ID don't go to IM history - // messages which should be routed to IM window come from a user ID with name=SYSTEM_NAME - chat.mText = name + ": " + message; - LLFloaterChat::addChat(chat, FALSE, FALSE); - } - else if (to_id.isNull()) - { - // Message to everyone from GOD, look up the fullname since - // server always slams name to legacy names - LLAvatarNameCache::get(from_id, boost::bind(god_message_name_cb, _2, chat, message)); - } - else - { - // standard message, not from system - bool mute_im = is_muted; - if (accept_im_from_only_friend && !is_friend && !is_linden) - { - if (!gIMMgr->isNonFriendSessionNotified(session_id)) - { - std::string message = LLTrans::getString("IM_unblock_only_groups_friends"); - gIMMgr->addMessage(session_id, from_id, name, message); - gIMMgr->addNotifiedNonFriendSessionID(session_id); - } - - mute_im = true; - } - - std::string saved; - if(offline == IM_OFFLINE) - { - LLStringUtil::format_map_t args; - args["[LONG_TIMESTAMP]"] = formatted_time(timestamp); - saved = LLTrans::getString("Saved_message", args); - } - else if (!mute_im) script_msg_api(from_id.asString() + ", 0"); - buffer = separator_string + saved + message.substr(message_offset); - - LL_INFOS("Messaging") << "process_improved_im: session_id( " << session_id << " ), from_id( " << from_id << " )" << LL_ENDL; - - // Muted nonfriend code moved up - -// [RLVa:KB] - Checked: 2010-11-30 (RLVa-1.3.0) - // Don't block offline IMs, or IMs from Lindens - if ( (rlv_handler_t::isEnabled()) && (offline != IM_OFFLINE) && (!RlvActions::canReceiveIM(from_id)) && (!is_linden) ) - { - if (!mute_im) - RlvUtil::sendBusyMessage(from_id, RlvStrings::getString(RLV_STRING_BLOCKED_RECVIM_REMOTE), session_id); - buffer = RlvStrings::getString(RLV_STRING_BLOCKED_RECVIM); - } -// [/RLVa:KB] - - if (!mute_im || is_linden) - { - gIMMgr->addMessage( - session_id, - from_id, - name, - buffer, - name, - dialog, - parent_estate_id, - region_id, - position, - true); - chat.mText = std::string("IM: ") + name + separator_string + saved + message.substr(message_offset); - LLFloaterChat::addChat(chat, true, false); - } - else - { - // muted user, so don't start an IM session, just record line in chat - // history. Pretend the chat is from a local agent, - // so it will go into the history but not be shown on screen. - chat.mText = buffer; - LLFloaterChat::addChat(chat, true, true); - - // Autoresponse to muted avatars - if (!gIMMgr->isNonFriendSessionNotified(session_id) && sAutorespondMuted) - { - std::string my_name; - LLAgentUI::buildFullname(my_name); - pack_instant_message( - gMessageSystem, - gAgentID, - FALSE, - gAgentSessionID, - from_id, - my_name, - replace_wildcards(gSavedPerAccountSettings.getString("AutoresponseMutedMessage"), from_id, name), - IM_ONLINE, - IM_BUSY_AUTO_RESPONSE, - session_id); - gAgent.sendReliableMessage(); - autoresponder_finish(gSavedPerAccountSettings.getBOOL("AutoresponseMutedShow"), session_id, from_id, name, gSavedPerAccountSettings.getBOOL("AutoresponseMutedItem") ? static_cast(gSavedPerAccountSettings.getString("AutoresponseMutedItemID")) : LLUUID::null, true); - } - } - } - break; - - case IM_TYPING_START: - { - static LLCachedControl sNotifyIncomingMessage(gSavedSettings, "AscentInstantMessageAnnounceIncoming"); - // Don't announce that someone has started messaging, if they're muted or when in busy mode - if (sNotifyIncomingMessage && - ((accept_im_from_only_friend && (is_friend || is_linden)) || - (!(is_muted || is_do_not_disturb))) && - !gIMMgr->hasSession(session_id) - ) - { - LLAvatarName av_name; - std::string ns_name = LLAvatarNameCache::get(from_id, &av_name) ? av_name.getNSName() : name; - - gIMMgr->addMessage(session_id, - from_id, - name, - llformat("%s ", ns_name.c_str()) + LLTrans::getString("IM_announce_incoming"), - name, - IM_NOTHING_SPECIAL, - parent_estate_id, - region_id, - position, - false); - - - // This block is very similar to the one above, but is necessary, since a session is opened to announce incoming message.. - // In order to prevent doubling up on the first response, We neglect to send this if Repeat for each message is on. - if ((is_autorespond_nonfriends || is_autorespond) && !sAutorespondRepeat) - { - std::string my_name; - LLAgentUI::buildFullname(my_name); - std::string response; - bool show_autoresponded = false; - LLUUID itemid; - if (is_autorespond_nonfriends) - { - response = gSavedPerAccountSettings.getString("AutoresponseNonFriendsMessage"); - if (gSavedPerAccountSettings.getBOOL("AutoresponseNonFriendsItem")) - itemid = static_cast(gSavedPerAccountSettings.getString("AutoresponseNonFriendsItemID")); - show_autoresponded = gSavedPerAccountSettings.getBOOL("AutoresponseNonFriendsShow"); - } - else if (is_autorespond) - { - response = gSavedPerAccountSettings.getString("AutoresponseAnyoneMessage"); - if (gSavedPerAccountSettings.getBOOL("AutoresponseAnyoneItem")) - itemid = static_cast(gSavedPerAccountSettings.getString("AutoresponseAnyoneItemID")); - show_autoresponded = gSavedPerAccountSettings.getBOOL("AutoresponseAnyoneShow"); - } - pack_instant_message(gMessageSystem, gAgentID, false, gAgentSessionID, from_id, my_name, replace_wildcards(response, from_id, name), IM_ONLINE, IM_BUSY_AUTO_RESPONSE, session_id); - gAgent.sendReliableMessage(); - - autoresponder_finish(show_autoresponded, session_id, from_id, name, itemid, is_muted); - } - } - LLPointer im_info = new LLIMInfo(gMessageSystem); - gIMMgr->processIMTypingStart(im_info); - script_msg_api(from_id.asString() + ", 4"); - } - break; - - case IM_TYPING_STOP: - { - LLPointer im_info = new LLIMInfo(gMessageSystem); - gIMMgr->processIMTypingStop(im_info); - script_msg_api(from_id.asString() + ", 5"); - } - break; - - case IM_MESSAGEBOX: - { - // This is a block, modeless dialog. - //*TODO: Translate - args["MESSAGE"] = message; - LLNotificationsUtil::add("SystemMessageTip", args); - } - break; - case IM_GROUP_NOTICE: - case IM_GROUP_NOTICE_REQUESTED: - { - LL_INFOS("Messaging") << "Received IM_GROUP_NOTICE message." << LL_ENDL; - // Read the binary bucket for more information. - struct notice_bucket_header_t - { - U8 has_inventory; - U8 asset_type; - LLUUID group_id; - }; - struct notice_bucket_full_t - { - struct notice_bucket_header_t header; - U8 item_name[DB_INV_ITEM_NAME_BUF_SIZE]; - }* notice_bin_bucket; - - // Make sure the binary bucket is big enough to hold the header - // and a null terminated item name. - if ( (binary_bucket_size < (S32)((sizeof(notice_bucket_header_t) + sizeof(U8)))) - || (binary_bucket[binary_bucket_size - 1] != '\0') ) - { - LL_WARNS("Messaging") << "Malformed group notice binary bucket" << LL_ENDL; - break; - } - - // The group notice packet does not have an AgentID. Obtain one from the name cache. - // If last name is "Resident" strip it out so the cache name lookup works. - size_t index = original_name.find(" Resident"); - if (index != std::string::npos) - { - original_name = original_name.substr(0, index); - } - std::string legacy_name = gCacheName->buildLegacyName(original_name); - LLUUID agent_id; - gCacheName->getUUID(legacy_name, agent_id); - - if (agent_id.isNull()) - { - LL_WARNS("Messaging") << "buildLegacyName returned null while processing " << original_name << LL_ENDL; - } - else if (LLMuteList::getInstance()->isMuted(agent_id)) - { - break; - } - - notice_bin_bucket = (struct notice_bucket_full_t*) &binary_bucket[0]; - U8 has_inventory = notice_bin_bucket->header.has_inventory; - U8 asset_type = notice_bin_bucket->header.asset_type; - LLUUID group_id = notice_bin_bucket->header.group_id; - std::string item_name = ll_safe_string((const char*) notice_bin_bucket->item_name); - - // If there is inventory, give the user the inventory offer. - LLOfferInfo* info = NULL; - - if (has_inventory) - { - info = new LLOfferInfo(); - - info->mIM = IM_GROUP_NOTICE; - info->mFromID = from_id; - info->mFromGroup = from_group; - info->mTransactionID = session_id; - info->mType = (LLAssetType::EType) asset_type; - info->mFolderID = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(info->mType)); - info->mFromName = LLTrans::getString("AGroupMemberNamed", LLSD().with("GROUP_ID", group_id).with("FROM_ID", from_id)); - info->mDesc = item_name; - info->mHost = msg->getSender(); - } - - std::string str(message); - - // Tokenize the string. - // TODO: Support escaped tokens ("||" -> "|") - typedef boost::tokenizer > tokenizer; - boost::char_separator sep("|","",boost::keep_empty_tokens); - tokenizer tokens(str, sep); - tokenizer::iterator iter = tokens.begin(); - - std::string subj(*iter++); - std::string mes(*iter++); - - // Send the notification down the new path. - // For requested notices, we don't want to send the popups. - if (dialog != IM_GROUP_NOTICE_REQUESTED) - { - LLSD payload; - payload["subject"] = subj; - payload["message"] = mes; - payload["sender_name"] = name; - payload["group_id"] = group_id; - payload["inventory_name"] = item_name; - if(info && info->asLLSD()) - { - payload["inventory_offer"] = info->asLLSD(); - } - - LLSD args; - args["SUBJECT"] = subj; - args["MESSAGE"] = mes; - LLDate notice_date = LLDate(timestamp).notNull() ? LLDate(timestamp) : LLDate::now(); - LLNotifications::instance().add(LLNotification::Params("GroupNotice").substitutions(args).payload(payload).timestamp(notice_date)); - } - - // Also send down the old path for now. - if (IM_GROUP_NOTICE_REQUESTED == dialog) - { - LLGroupActions::showNotice(subj,mes,group_id,has_inventory,item_name,info); - } - else - { - delete info; - } - } - break; - case IM_GROUP_INVITATION: - { - //if (is_do_not_disturb || is_muted) - if (is_muted) return; - if (is_do_not_disturb) - { - LLMessageSystem *msg = gMessageSystem; - send_do_not_disturb_message(msg,from_id); - } - else - { - LL_INFOS("Messaging") << "Received IM_GROUP_INVITATION message." << LL_ENDL; - // Read the binary bucket for more information. - struct invite_bucket_t - { - S32 membership_fee; - LLUUID role_id; - }* invite_bucket; - - // Make sure the binary bucket is the correct size. - if (binary_bucket_size != sizeof(invite_bucket_t)) - { - LL_WARNS("Messaging") << "Malformed group invite binary bucket" << LL_ENDL; - break; - } - - invite_bucket = (struct invite_bucket_t*) &binary_bucket[0]; - S32 membership_fee = ntohl(invite_bucket->membership_fee); - // NaCl - Antispam - if (membership_fee > 0 && gSavedSettings.getBOOL("AntiSpamGroupFeeInvites")) - return; - // NaCl End - - LLSD payload; - payload["transaction_id"] = session_id; - payload["group_id"] = from_id; - payload["name"] = name; - payload["message"] = message; - payload["fee"] = membership_fee; - - LLSD args; - args["MESSAGE"] = message; - // we shouldn't pass callback functor since it is registered in LLFunctorRegistration - LLNotificationsUtil::add("JoinGroup", args, payload); - } - } - break; - - case IM_INVENTORY_OFFERED: - case IM_TASK_INVENTORY_OFFERED: - // Someone has offered us some inventory. - { - LLOfferInfo* info = new LLOfferInfo; - if (IM_INVENTORY_OFFERED == dialog) - { - struct offer_agent_bucket_t - { - S8 asset_type; - LLUUID object_id; - }* bucketp; - - if (sizeof(offer_agent_bucket_t) != binary_bucket_size) - { - LL_WARNS("Messaging") << "Malformed inventory offer from agent" << LL_ENDL; - delete info; - break; - } - bucketp = (struct offer_agent_bucket_t*) &binary_bucket[0]; - info->mType = (LLAssetType::EType) bucketp->asset_type; - info->mObjectID = bucketp->object_id; - info->mFromObject = FALSE; - } - else // IM_TASK_INVENTORY_OFFERED - { - if (sizeof(S8) != binary_bucket_size) - { - LL_WARNS("Messaging") << "Malformed inventory offer from object" << LL_ENDL; - delete info; - break; - } - info->mType = (LLAssetType::EType) binary_bucket[0]; - info->mObjectID = LLUUID::null; - info->mFromObject = TRUE; - } - - info->mIM = dialog; - info->mFromID = from_id; - info->mFromGroup = from_group; - info->mTransactionID = session_id; - info->mFolderID = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(info->mType)); - - info->mFromName = name; - info->mDesc = message; - info->mHost = msg->getSender(); - //if (((is_do_not_disturb && !is_owned_by_me) || is_muted)) - if (is_muted) - { - // Prefetch the offered item so that it can be discarded by the appropriate observer. (EXT-4331) - LLInventoryFetchItemsObserver* fetch_item = new LLInventoryFetchItemsObserver(info->mObjectID); - fetch_item->startFetch(); - delete fetch_item; - - // Same as closing window - info->forceResponse(IOR_DECLINE); - } - /* Singu Note: Handle this inside inventory_offer_handler so if the user wants to autoaccept offers, they can while busy. - // old logic: busy mode must not affect interaction with objects (STORM-565) - // new logic: inventory offers from in-world objects should be auto-declined (CHUI-519) - // Singu Note: We should use old logic - else if (is_do_not_disturb && dialog != IM_TASK_INVENTORY_OFFERED) // busy mode must not affect interaction with objects (STORM-565) - { - // Until throttling is implemented, do not disturb mode should reject inventory instead of silently - // accepting it. SEE SL-39554 - info->forceResponse(IOR_DECLINE); - } - */ - else - { - inventory_offer_handler(info, is_friend, is_owned_by_me); - } - } - break; - - case IM_INVENTORY_ACCEPTED: - { -// args["NAME"] = name; -// [RLVa:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a - // Only anonymize the name if the agent is nearby, there isn't an open IM session to them and their profile isn't open - bool fRlvFilterName = (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (RlvUtil::isNearbyAgent(from_id)) && - (!RlvUIEnabler::hasOpenProfile(from_id)) && (!RlvUIEnabler::hasOpenIM(from_id)); - args["NAME"] = (!fRlvFilterName) ? name : RlvStrings::getAnonym(name); -// [/RLVa:KB] - LLNotificationsUtil::add("InventoryAccepted", args); - break; - } - case IM_INVENTORY_DECLINED: - { -// args["NAME"] = name; -// [RLVa:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a - // Only anonymize the name if the agent is nearby, there isn't an open IM session to them and their profile isn't open - bool fRlvFilterName = (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (RlvUtil::isNearbyAgent(from_id)) && - (!RlvUIEnabler::hasOpenProfile(from_id)) && (!RlvUIEnabler::hasOpenIM(from_id)); - args["NAME"] = (!fRlvFilterName) ? name : RlvStrings::getAnonym(name); -// [/RLVa:KB] - LLNotificationsUtil::add("InventoryDeclined", args); - break; - } - case IM_GROUP_VOTE: - { - LLSD args; - args["NAME"] = name; - args["MESSAGE"] = message; - - LLSD payload; - payload["group_id"] = session_id; - LLNotificationsUtil::add("GroupVote", args, payload); - } - break; - - case IM_GROUP_ELECTION_DEPRECATED: - { - LL_WARNS("Messaging") << "Received IM: IM_GROUP_ELECTION_DEPRECATED" << LL_ENDL; - } - break; - - case IM_SESSION_SEND: - { - if (!is_linden && is_do_not_disturb) - { - return; - } - - // Only show messages if we have a session open (which - // should happen after you get an "invitation" -// if ( !gIMMgr->hasSession(session_id) ) -// { -// return; -// } -// [RLVa:KB] - Checked: 2010-11-30 (RLVa-1.3.0c) | Modified: RLVa-1.3.0c - LLFloaterIMPanel* pIMFloater = gIMMgr->findFloaterBySession(session_id); - if (!pIMFloater) - { - return; - } - - if (from_id != gAgentID && (gRlvHandler.hasBehaviour(RLV_BHVR_RECVIM) || gRlvHandler.hasBehaviour(RLV_BHVR_RECVIMFROM))) - { - switch (pIMFloater->getSessionType()) - { - case LLFloaterIMPanel::GROUP_SESSION: // Group chat - if (!RlvActions::canReceiveIM(session_id)) - return; - break; - case LLFloaterIMPanel::ADHOC_SESSION: // Conference chat - if (!RlvActions::canReceiveIM(from_id)) - message = RlvStrings::getString(RLV_STRING_BLOCKED_RECVIM); - break; - default: - RLV_ASSERT(false); - return; - } - } -// [/RLVa:KB] - - // standard message, not from system - std::string saved; - if(offline == IM_OFFLINE) - { - LLStringUtil::format_map_t args; - args["[LONG_TIMESTAMP]"] = formatted_time(timestamp); - saved = LLTrans::getString("Saved_message", args); - } - buffer = separator_string + saved + message.substr(message_offset); - gIMMgr->addMessage( - session_id, - from_id, - name, - buffer, - ll_safe_string((char*)binary_bucket), - IM_SESSION_INVITE, - parent_estate_id, - region_id, - position, - true); - - std::string prepend_msg; - if (gAgent.isInGroup(session_id)&& gSavedSettings.getBOOL("OptionShowGroupNameInChatIM")) - { - prepend_msg = "["; - prepend_msg += std::string((char*)binary_bucket); - prepend_msg += "] "; - } - else - { - prepend_msg = std::string("IM: "); - } - chat.mText = prepend_msg + name + separator_string + saved + message.substr(message_offset); - LLFloaterChat::addChat(chat, TRUE, from_id == gAgentID); - } - break; - - case IM_FROM_TASK: - { - if (is_do_not_disturb && !is_owned_by_me) - { - return; - } - chat.mText = name + separator_string + message.substr(message_offset); - chat.mFromName = name; - - // Build a link to open the object IM info window. - std::string location = ll_safe_string((char*)binary_bucket, binary_bucket_size-1); - - if (session_id.notNull()) - { - chat.mFromID = session_id; - } - else - { - // This message originated on a region without the updated code for task id and slurl information. - // We just need a unique ID for this object that isn't the owner ID. - // If it is the owner ID it will overwrite the style that contains the link to that owner's profile. - // This isn't ideal - it will make 1 style for all objects owned by the the same person/group. - // This works because the only thing we can really do in this case is show the owner name and link to their profile. - chat.mFromID = from_id ^ gAgent.getSessionID(); - } - - chat.mSourceType = CHAT_SOURCE_OBJECT; - - // To conclude that the source type of message is CHAT_SOURCE_SYSTEM it's not - // enough to check only from name (i.e. fromName = "Second Life"). For example - // source type of messages from objects called "Second Life" should not be CHAT_SOURCE_SYSTEM. - bool chat_from_system = (SYSTEM_FROM == name) && region_id.isNull() && position.isNull(); - if(chat_from_system) - { - // System's UUID is NULL (fixes EXT-4766) - chat.mFromID = LLUUID::null; - chat.mSourceType = CHAT_SOURCE_SYSTEM; - } - else script_msg_api(chat.mFromID.asString() + ", 6"); - - // IDEVO Some messages have embedded resident names - message = clean_name_from_task_im(message, from_group); - - LLSD query_string; - query_string["owner"] = from_id; -// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Added: RLVa-1.2.0f - if (rlv_handler_t::isEnabled()) - { - // NOTE: the chat message itself will be filtered in LLNearbyChatHandler::processChat() - if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES) || gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS)) && (!from_group) && (RlvUtil::isNearbyAgent(from_id)) ) - { - query_string["rlv_shownames"] = TRUE; - - RlvUtil::filterNames(name); - chat.mFromName = name; - } - if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) - { - std::string::size_type idxPos = location.find('/'); - if ( (std::string::npos != idxPos) && (RlvUtil::isNearbyRegion(location.substr(0, idxPos))) ) - location = RlvStrings::getString(RLV_STRING_HIDDEN_REGION); - } - } -// [/RLVa:KB] - query_string["slurl"] = location; - query_string["name"] = name; - if (from_group) - { - query_string["groupowned"] = "true"; - } - -// chat.mURL = LLSLURL("objectim", session_id, "").getSLURLString(); -// [SL:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Added: RLVa-1.2.2a - chat.mURL = LLSLURL("objectim", session_id, LLURI::mapToQueryString(query_string)).getSLURLString(); -// [/SL:KB] - chat.mText = name + separator_string + message.substr(message_offset); - - // Note: lie to LLFloaterChat::addChat(), pretending that this is NOT an IM, because - // IMs from objects don't open IM sessions. - LLFloaterChat::addChat(chat, FALSE, FALSE); - } - break; - - case IM_FROM_TASK_AS_ALERT: - if (is_do_not_disturb && !is_owned_by_me) - { - return; - } - { - // Construct a viewer alert for this message. - args["NAME"] = name; - args["MESSAGE"] = message; - LLNotificationsUtil::add("ObjectMessage", args); - } - break; - case IM_BUSY_AUTO_RESPONSE: - if (is_muted) - { - LL_DEBUGS("Messaging") << "Ignoring do-not-disturb response from " << from_id << LL_ENDL; - return; - } - else - { - gIMMgr->addMessage(session_id, from_id, name, separator_string + message.substr(message_offset), name, dialog, parent_estate_id, region_id, position, true); - } - break; - - case IM_LURE_USER: - case IM_TELEPORT_REQUEST: - { -// [RLVa:KB] - Checked: 2013-11-08 (RLVa-1.4.9) - // If we auto-accept the offer/request then this will override DnD status (but we'll still let the other party know later) - bool fRlvAutoAccept = (rlv_handler_t::isEnabled()) && - ( ((IM_LURE_USER == dialog) && (RlvActions::autoAcceptTeleportOffer(from_id))) || - ((IM_TELEPORT_REQUEST == dialog) && (RlvActions::autoAcceptTeleportRequest(from_id))) ); -// [/RLVa:KB] - - if (is_muted) - { - return; - } -// else if (is_do_not_disturb) -// [RLVa:KB] - Checked: 2013-11-08 (RLVa-1.4.9) - else if ( (is_do_not_disturb) && (!fRlvAutoAccept) ) -// [/RLVa:KB] - { - send_do_not_disturb_message(msg, from_id); - } - else - { - LLVector3 pos, look_at; - U64 region_handle(0); - U8 region_access(SIM_ACCESS_MIN); - std::string region_info = ll_safe_string((char*)binary_bucket, binary_bucket_size); - std::string region_access_str = LLStringUtil::null; - std::string region_access_icn = LLStringUtil::null; - std::string region_access_lc = LLStringUtil::null; - - bool canUserAccessDstRegion = true; - bool doesUserRequireMaturityIncrease = false; - - // Do not parse the (empty) lure bucket for TELEPORT_REQUEST - if (IM_TELEPORT_REQUEST != dialog && parse_lure_bucket(region_info, region_handle, pos, look_at, region_access)) - { - region_access_str = LLViewerRegion::accessToString(region_access); - region_access_icn = LLViewerRegion::getAccessIcon(region_access); - region_access_lc = region_access_str; - LLStringUtil::toLower(region_access_lc); - - if (!gAgent.isGodlike()) - { - switch (region_access) - { - case SIM_ACCESS_MIN : - case SIM_ACCESS_PG : - break; - case SIM_ACCESS_MATURE : - if (gAgent.isTeen()) - { - canUserAccessDstRegion = false; - } - else if (gAgent.prefersPG()) - { - doesUserRequireMaturityIncrease = true; - } - break; - case SIM_ACCESS_ADULT : - if (!gAgent.isAdult()) - { - canUserAccessDstRegion = false; - } - else if (!gAgent.prefersAdult()) - { - doesUserRequireMaturityIncrease = true; - } - break; - default : - llassert(0); - break; - } - } - } - -// [RLVa:KB] - Checked: 2013-11-08 (RLVa-1.4.9) - if (rlv_handler_t::isEnabled()) - { - if ( ((IM_LURE_USER == dialog) && (!RlvActions::canAcceptTpOffer(from_id))) || - ((IM_TELEPORT_REQUEST == dialog) && (!RlvActions::canAcceptTpRequest(from_id))) ) - { - RlvUtil::sendBusyMessage(from_id, RlvStrings::getString(RLV_STRING_BLOCKED_TPLUREREQ_REMOTE)); - if (is_do_not_disturb) - send_do_not_disturb_message(msg, from_id); - return; - } - - // Censor lure message if: 1) restricted from receiving IMs from the sender, or 2) teleport offer and @showloc=n restricted - if ( (!RlvActions::canReceiveIM(from_id)) || ((IM_LURE_USER == dialog) && (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC))) ) - { - message = RlvStrings::getString(RLV_STRING_HIDDEN); - } - } -// [/RLVa:KB] - - LLSD args; - // *TODO: Translate -> [FIRST] [LAST] (maybe) - args["NAME"] = name; - args["MESSAGE"] = message; - args["MATURITY_STR"] = region_access_str; - args["MATURITY_ICON"] = region_access_icn; - args["REGION_CONTENT_MATURITY"] = region_access_lc; - LLSD payload; - payload["from_id"] = from_id; - payload["lure_id"] = session_id; - payload["godlike"] = FALSE; - payload["region_maturity"] = region_access; - - /* Singu TODO: Figure if we should use these - if (!canUserAccessDstRegion) - { - LLNotification::Params params("TeleportOffered_MaturityBlocked"); - params.substitutions = args; - params.payload = payload; - LLPostponedNotification::add( params, from_id, false); - send_simple_im(from_id, LLTrans::getString("TeleportMaturityExceeded"), IM_NOTHING_SPECIAL, session_id); - send_simple_im(from_id, LLStringUtil::null, IM_LURE_DECLINED, session_id); - } - else if (doesUserRequireMaturityIncrease) - { - LLNotification::Params params("TeleportOffered_MaturityExceeded"); - params.substitutions = args; - params.payload = payload; - LLPostponedNotification::add( params, from_id, false); - } - else - */ - { - /* Singu Note: No default constructor for LLNotification::Params - LLNotification::Params params; - if (IM_LURE_USER == dialog) - { - params.name = "TeleportOffered"; - params.functor_name = "TeleportOffered"; - } - else if (IM_TELEPORT_REQUEST == dialog) - { - params.name = "TeleportRequest"; - params.functor_name = "TeleportRequest"; - } - */ - LLNotification::Params params(IM_LURE_USER == dialog ? "TeleportOffered" : "TeleportRequest"); - - params.substitutions = args; - params.payload = payload; - -// [RLVa:KB] - Checked: 20103-11-08 (RLVa-1.4.9) - if ( (rlv_handler_t::isEnabled()) && (fRlvAutoAccept) ) - { - if (IM_LURE_USER == dialog) - gRlvHandler.setCanCancelTp(false); - if (is_do_not_disturb) - send_do_not_disturb_message(msg, from_id); - LLNotifications::instance().forceResponse(LLNotification::Params(params.name).payload(payload), 0); - } - else - { - LLNotifications::instance().add(params); - - // - if (IM_LURE_USER == dialog) - gAgent.showLureDestination(LLAvatarActions::getSLURL(from_id), region_handle, pos.mV[VX], pos.mV[VY], pos.mV[VZ]); - script_msg_api(from_id.asString().append(IM_LURE_USER == dialog ? ", 2" : ", 3")); - // - } -// [/RLVa:KB] -// LLNotifications::instance().add(params); - } - } - } - break; - - case IM_GODLIKE_LURE_USER: - { - LLVector3 pos, look_at; - U64 region_handle(0); - U8 region_access(SIM_ACCESS_MIN); - std::string region_info = ll_safe_string((char*)binary_bucket, binary_bucket_size); - std::string region_access_str = LLStringUtil::null; - std::string region_access_icn = LLStringUtil::null; - std::string region_access_lc = LLStringUtil::null; - - bool canUserAccessDstRegion = true; - bool doesUserRequireMaturityIncrease = false; - - if (parse_lure_bucket(region_info, region_handle, pos, look_at, region_access)) - { - region_access_str = LLViewerRegion::accessToString(region_access); - region_access_icn = LLViewerRegion::getAccessIcon(region_access); - region_access_lc = region_access_str; - LLStringUtil::toLower(region_access_lc); - - if (!gAgent.isGodlike()) - { - switch (region_access) - { - case SIM_ACCESS_MIN : - case SIM_ACCESS_PG : - break; - case SIM_ACCESS_MATURE : - if (gAgent.isTeen()) - { - canUserAccessDstRegion = false; - } - else if (gAgent.prefersPG()) - { - doesUserRequireMaturityIncrease = true; - } - break; - case SIM_ACCESS_ADULT : - if (!gAgent.isAdult()) - { - canUserAccessDstRegion = false; - } - else if (!gAgent.prefersAdult()) - { - doesUserRequireMaturityIncrease = true; - } - break; - default : - llassert(0); - break; - } - } - } - - LLSD args; - // *TODO: Translate -> [FIRST] [LAST] (maybe) - args["NAME"] = name; - args["MESSAGE"] = message; - args["MATURITY_STR"] = region_access_str; - args["MATURITY_ICON"] = region_access_icn; - args["REGION_CONTENT_MATURITY"] = region_access_lc; - LLSD payload; - payload["from_id"] = from_id; - payload["lure_id"] = session_id; - payload["godlike"] = TRUE; - payload["region_maturity"] = region_access; - - // do not show a message box, because you're about to be - // teleported. - LLNotifications::instance().forceResponse(LLNotification::Params("TeleportOffered").payload(payload), 0); - } - break; - - case IM_GOTO_URL: - { - LLSD args; - // n.b. this is for URLs sent by the system, not for - // URLs sent by scripts (i.e. llLoadURL) - if (binary_bucket_size <= 0) - { - LL_WARNS("Messaging") << "bad binary_bucket_size: " - << binary_bucket_size - << " - aborting function." << LL_ENDL; - return; - } - - std::string url; - - url.assign((char*)binary_bucket, binary_bucket_size-1); - args["MESSAGE"] = message; - args["URL"] = url; - LLSD payload; - payload["url"] = url; - LLNotificationsUtil::add("GotoURL", args, payload ); - } - break; - - case IM_FRIENDSHIP_OFFERED: - { - LLSD payload; - payload["from_id"] = from_id; - payload["session_id"] = session_id;; - payload["online"] = (offline == IM_ONLINE); - payload["sender"] = msg->getSender().getIPandPort(); - - if (is_muted) - { - LLNotifications::instance().forceResponse(LLNotification::Params("OfferFriendship").payload(payload), 1); - } - else - { - if (is_do_not_disturb) - { - send_do_not_disturb_message(msg, from_id); - } - args["[NAME]"] = name; - if(message.empty()) - { - //support for frienship offers from clients before July 2008 - LLNotificationsUtil::add("OfferFriendshipNoMessage", args, payload); - } - else - { - args["[MESSAGE]"] = message; - LLNotificationsUtil::add("OfferFriendship", args, payload); - } - } - } - break; - - case IM_FRIENDSHIP_ACCEPTED: - { - // In the case of an offline IM, the formFriendship() may be extraneous - // as the database should already include the relationship. But it - // doesn't hurt for dupes. - LLAvatarTracker::formFriendship(from_id); - - std::vector strings; - strings.push_back(from_id.asString()); - send_generic_message("requestonlinenotification", strings); - - args["NAME"] = name; - LLSD payload; - payload["from_id"] = from_id; - LLAvatarNameCache::get(from_id, boost::bind(¬ification_display_name_callback, _1, _2, "FriendshipAccepted", args, payload)); - } - break; - - case IM_FRIENDSHIP_DECLINED_DEPRECATED: - default: - LL_WARNS("Messaging") << "Instant message calling for unknown dialog " - << (S32)dialog << LL_ENDL; - break; - } - - LLWindow* viewer_window = gViewerWindow->getWindow(); - if (viewer_window && viewer_window->getMinimized() && gSavedSettings.getBOOL("LiruFlashWhenMinimized")) - { - viewer_window->flashIcon(5.f); - } + LLHost sender = msg->getSender(); + + LLIMProcessing::processNewMessage(from_id, + from_group, + to_id, + offline, + dialog, + session_id, + timestamp, + agentName, + message, + parent_estate_id, + region_id, + position, + binary_bucket, + binary_bucket_size, + sender); } void send_do_not_disturb_message(LLMessageSystem* msg, const LLUUID& from_id, const LLUUID& session_id) @@ -3541,8 +1985,7 @@ void send_do_not_disturb_message(LLMessageSystem* msg, const LLUUID& from_id, co std::string my_name; LLAgentUI::buildFullname(my_name); std::string name; - msg->getStringFast(_PREHASH_MessageBlock, _PREHASH_FromAgentName, name); - name = LLCacheName::cleanFullName(name); + gCacheName->getFullName(from_id, name); std::string response = gSavedPerAccountSettings.getString("BusyModeResponse"); pack_instant_message( msg, @@ -3558,12 +2001,13 @@ void send_do_not_disturb_message(LLMessageSystem* msg, const LLUUID& from_id, co gAgent.sendReliableMessage(); LLAvatarName av_name; std::string ns_name = LLAvatarNameCache::get(from_id, &av_name) ? av_name.getNSName() : name; - if (gSavedPerAccountSettings.getBOOL("BusyModeResponseShow")) gIMMgr->addMessage(session_id, from_id, name, LLTrans::getString("IM_autoresponded_to") + ' ' + ns_name); + const auto show = gSavedPerAccountSettings.getBOOL("BusyModeResponseShow"); + if (show) gIMMgr->addMessage(session_id, from_id, name, LLTrans::getString("IM_autoresponded_to") + ' ' + ns_name); if (!gSavedPerAccountSettings.getBOOL("BusyModeResponseItem")) return; // Not sending an item, finished if (LLViewerInventoryItem* item = gInventory.getItem(static_cast(gSavedPerAccountSettings.getString("BusyModeResponseItemID")))) { LLGiveInventory::doGiveInventoryItem(from_id, item, session_id); - if (gSavedPerAccountSettings.getBOOL("BusyModeResponseShow")) + if (show) gIMMgr->addMessage(session_id, from_id, name, llformat("%s %s \"%s\"", ns_name.c_str(), LLTrans::getString("IM_autoresponse_sent_item").c_str(), item->getName().c_str())); } } @@ -3573,9 +2017,8 @@ bool callingcard_offer_callback(const LLSD& notification, const LLSD& response) { S32 option = LLNotificationsUtil::getSelectedOption(notification, response); LLUUID fid; - LLUUID from_id; LLMessageSystem* msg = gMessageSystem; - switch(option) + switch (option) { case 0: // accept @@ -3608,6 +2051,7 @@ bool callingcard_offer_callback(const LLSD& notification, const LLSD& response) return false; } + static LLNotificationFunctorRegistration callingcard_offer_cb_reg("OfferCallingCard", callingcard_offer_callback); void process_offer_callingcard(LLMessageSystem* msg, void**) @@ -3623,8 +2067,9 @@ void process_offer_callingcard(LLMessageSystem* msg, void**) msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, source_id); // NaCl - Antispam Registry - if(NACLAntiSpamRegistry::checkQueue((U32)NACLAntiSpamRegistry::QUEUE_CALLING_CARD,source_id)) - return; + if (auto antispam = NACLAntiSpamRegistry::getIfExists()) + if (antispam->checkQueue(NACLAntiSpamRegistry::QUEUE_CALLING_CARD, source_id)) + return; // NaCl End LLUUID tid; @@ -3638,7 +2083,7 @@ void process_offer_callingcard(LLMessageSystem* msg, void**) LLViewerObject* source = gObjectList.findObject(source_id); LLSD args; std::string source_name; - if(source && source->isAvatar()) + if (source && source->isAvatar()) { LLNameValue* nvfirst = source->getNVPair("FirstName"); LLNameValue* nvlast = source->getNVPair("LastName"); @@ -3649,7 +2094,7 @@ void process_offer_callingcard(LLMessageSystem* msg, void**) } } - if(!source_name.empty()) + if (!source_name.empty()) { if (gAgent.isDoNotDisturb() || LLMuteList::getInstance()->isMuted(source_id, source_name, LLMute::flagTextChat)) @@ -3680,7 +2125,7 @@ void process_decline_callingcard(LLMessageSystem* msg, void**) } #if 0 // Google translate doesn't work anymore -class ChatTranslationReceiver : public LLTranslate::TranslationReceiver +class ChatTranslationReceiver final : public LLTranslate::TranslationReceiver { public : ChatTranslationReceiver(const std::string &fromLang, const std::string &toLang, LLChat *chat, @@ -3718,7 +2163,7 @@ protected: delete m_chat; } - /*virtual*/ char const* getName(void) const { return "ChatTranslationReceiver"; } + char const* getName() const override { return "ChatTranslationReceiver"; } private: LLChat *m_chat; @@ -3726,7 +2171,7 @@ private: }; #endif -void add_floater_chat(LLChat &chat, const BOOL history) +void add_floater_chat(LLChat &chat, const bool history) { if (history) { @@ -3741,7 +2186,7 @@ void add_floater_chat(LLChat &chat, const BOOL history) } #if 0 // Google translate doesn't work anymore -void check_translate_chat(const std::string &mesg, LLChat &chat, const BOOL history) +void check_translate_chat(const std::string &mesg, LLChat &chat, const bool history) { const bool translate = LLUI::sConfigGroup->getBOOL("TranslateChat"); @@ -3763,42 +2208,7 @@ void check_translate_chat(const std::string &mesg, LLChat &chat, const BOOL hist } #endif -// defined in llchatbar.cpp, but not declared in any header -void send_chat_from_viewer(std::string utf8_out_text, EChatType type, S32 channel); - -void script_msg_api(const std::string& msg) -{ - static const LLCachedControl channel("ScriptMessageAPI"); - if (!channel) return; - static const LLCachedControl key("ScriptMessageAPIKey"); - std::string str; - for (size_t i = 0, keysize = key().size(); i != msg.size(); ++i) - str += msg[i] ^ key()[i%keysize]; - send_chat_from_viewer(LLBase64::encode(reinterpret_cast(str.c_str()), str.size()), CHAT_TYPE_WHISPER, channel); -} - -class AuthHandler : public LLHTTPClient::ResponderWithCompleted -{ -protected: - /*virtual*/ void completedRaw(LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) - { - std::string content; - decode_raw_body(channels, buffer, content); - if (mStatus == HTTP_OK) - { - send_chat_from_viewer("AUTH:" + content, CHAT_TYPE_WHISPER, 427169570); - } - else - { - LL_WARNS() << "Hippo AuthHandler: non-OK HTTP status " << mStatus << " for URL " << mURL << " (" << mReason << "). Error body: \"" << content << "\"." << LL_ENDL; - } - } - - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return authHandler_timeout; } - /*virtual*/ char const* getName(void) const { return "AuthHandler"; } -}; - -void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) +void process_chat_from_simulator(LLMessageSystem* msg, void** user_data) { LLChat chat; std::string mesg; @@ -3831,6 +2241,8 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) // Object owner for objects msg->getUUID("ChatData", "OwnerID", owner_id); + bool has_owner = owner_id.notNull(); + if (chatter && has_owner) chatter->mOwnerID = owner_id; // Singu Note: Try to get Owner whenever possible msg->getU8Fast(_PREHASH_ChatData, _PREHASH_SourceType, source_temp); chat.mSourceType = (EChatSourceType)source_temp; @@ -3839,9 +2251,10 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) chat.mChatType = (EChatType)type_temp; // NaCL - Antispam Registry - if((chat.mChatType != CHAT_TYPE_START && chat.mChatType != CHAT_TYPE_STOP) //Chat type isn't typing - &&((owner_id.isNull() && NACLAntiSpamRegistry::checkQueue((U32)NACLAntiSpamRegistry::QUEUE_CHAT,from_id)) //Spam from an object? - ||(NACLAntiSpamRegistry::checkQueue((U32)NACLAntiSpamRegistry::QUEUE_CHAT,owner_id)))) //Spam from a resident? + auto antispam = NACLAntiSpamRegistry::getIfExists(); + if (antispam && chat.mChatType != CHAT_TYPE_START && chat.mChatType != CHAT_TYPE_STOP //Chat type isn't typing + && (antispam->checkQueue(NACLAntiSpamRegistry::QUEUE_CHAT, from_id, !has_owner ? LFIDBearer::AVATAR : LFIDBearer::OBJECT) // Spam from an object or avatar? + || (has_owner && (antispam->checkQueue(NACLAntiSpamRegistry::QUEUE_CHAT, owner_id))))) // Spam from a resident? return; // NaCl End @@ -3859,7 +2272,7 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) LLAvatarName av_name; if (LLAvatarNameCache::get(from_id, &av_name)) { - chat.mFromName = av_name.getDisplayName(); + chat.mFromName = av_name.getNSName(); } else { @@ -3879,8 +2292,8 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) bool is_do_not_disturb = gAgent.isDoNotDisturb(); - BOOL is_muted = FALSE; - BOOL is_linden = FALSE; + bool is_muted = false; + bool is_linden = false; is_muted = LLMuteList::getInstance()->isMuted( from_id, from_name, @@ -3889,87 +2302,21 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) is_linden = chat.mSourceType != CHAT_SOURCE_OBJECT && LLMuteList::getInstance()->isLinden(from_name); + msg->getStringFast(_PREHASH_ChatData, _PREHASH_Message, mesg); + + bool handle_obj_auth(const LLUUID& from_id, const std::string& mesg); + if (source_temp == CHAT_SOURCE_OBJECT && type_temp == CHAT_TYPE_OWNER && handle_obj_auth(from_id, mesg)) return; + + if (is_muted && (chat.mSourceType == CHAT_SOURCE_OBJECT)) + { + return; + } + BOOL is_audible = (CHAT_AUDIBLE_FULLY == chat.mAudible); - - static std::map sChatObjectAuth; - // // because I moved it to above //chatter = gObjectList.findObject(from_id); // - - msg->getStringFast(_PREHASH_ChatData, _PREHASH_Message, mesg); - - if ((source_temp == CHAT_SOURCE_OBJECT) && (type_temp == CHAT_TYPE_OWNER) && - (mesg.substr(0, 3) == "># ")) - { - if (mesg.substr(mesg.size()-3, 3) == " #<"){ - // hello from object - if (from_id.isNull()) return; - char buf[200]; - snprintf(buf, 200, "%s v%d.%d.%d", LLVersionInfo::getChannel().c_str(), LLVersionInfo::getMajor(), LLVersionInfo::getMinor(), LLVersionInfo::getPatch()); - send_chat_from_viewer(buf, CHAT_TYPE_WHISPER, 427169570); - sChatObjectAuth[from_id] = 1; - return; - } - else if (from_id.isNull() || sChatObjectAuth.find(from_id) != sChatObjectAuth.end()) - { - LLUUID key; - if (key.set(mesg.substr(3, 36),false)) - { - // object command found - if (key.isNull() && (mesg.size() == 39)) - { - // clear all nameplates - for (int i=0; i(obj)) - { - avatar->clearNameFromChat(); - } - } - } - else - { - if (key.isNull()) - { - LL_WARNS() << "Nameplate from chat on NULL avatar (ignored)" << LL_ENDL; - return; - } - LLVOAvatar *avatar = gObjectList.findAvatar(key); - if (!avatar) - { - LL_WARNS() << "Nameplate from chat on invalid avatar (ignored)" << LL_ENDL; - return; - } - if (mesg.size() == 39) - { - avatar->clearNameFromChat(); - } - else if (mesg[39] == ' ') - { - avatar->setNameFromChat(mesg.substr(40)); - } - } - return; - } - else if (mesg.substr(2, 9) == " floater ") - { - HippoFloaterXml::execute(mesg.substr(11)); - return; - } - else if (mesg.substr(2, 6) == " auth ") - { - std::string authUrl = mesg.substr(8); - authUrl += (authUrl.find('?') != std::string::npos)? "&auth=": "?auth="; - authUrl += gAuthString; - LLHTTPClient::get(authUrl, new AuthHandler); - return; - } - } - } - if (chatter) { chat.mPosAgent = chatter->getPositionAgent(); @@ -4045,18 +2392,17 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) if (is_audible) { // NaCl - Newline flood protection - static LLCachedControl AntiSpamEnabled(gSavedSettings,"AntiSpamEnabled",false); - if (AntiSpamEnabled && can_block(from_id)) + if (antispam && can_block(from_id)) { - static LLCachedControl SpamNewlines(gSavedSettings,"_NACL_AntiSpamNewlines"); + static const LLCachedControl SpamNewlines("_NACL_AntiSpamNewlines"); boost::sregex_iterator iter(mesg.begin(), mesg.end(), NEWLINES); if((U32)std::abs(std::distance(iter, boost::sregex_iterator())) > SpamNewlines) { - NACLAntiSpamRegistry::blockOnQueue((U32)NACLAntiSpamRegistry::QUEUE_CHAT,owner_id); + antispam->blockOnQueue(NACLAntiSpamRegistry::QUEUE_CHAT, owner_id); if(gSavedSettings.getBOOL("AntiSpamNotify")) { LLSD args; - args["MESSAGE"] = "Chat: Blocked newline flood from "+owner_id.asString(); + args["MESSAGE"] = "Chat: Blocked newline flood from " + LLAvatarActions::getSLURL(owner_id); LLNotificationsUtil::add("SystemMessageTip", args); } return; @@ -4073,7 +2419,7 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) BOOL visible_in_chat_bubble = FALSE; std::string verb; - color.setVec(1.f,1.f,1.f,1.f); + color.setVec(1.f, 1.f, 1.f, 1.f); // [RLVa:KB] - Checked: 2010-04-23 (RLVa-1.2.0f) | Modified: RLVa-1.2.0f if ( (rlv_handler_t::isEnabled()) && (CHAT_TYPE_START != chat.mChatType) && (CHAT_TYPE_STOP != chat.mChatType) ) @@ -4115,7 +2461,7 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) { RlvUtil::filterNames(chat.mFromName); } - else if (chat.mFromID != gAgent.getID()) + else if (chat.mFromID != gAgentID) { chat.mFromName = RlvStrings::getAnonym(chat.mFromName); chat.mRlvNamesFiltered = TRUE; @@ -4147,7 +2493,7 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) // Look for IRC-style emotes here so chatbubbles work std::string prefix = mesg.substr(0, 4); - if (prefix == "/me " || prefix == "/me'") + if (boost::iequals(prefix, "/me ") || boost::iequals(prefix, "/me'")) // { chat.mText = chat.mFromName; mesg = mesg.substr(3); @@ -4170,7 +2516,7 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) } return; } - else if (CHAT_TYPE_STOP == chat.mChatType) + if (CHAT_TYPE_STOP == chat.mChatType) { LLLocalSpeakerMgr::getInstance()->setSpeakerTyping(from_id, FALSE); @@ -4203,7 +2549,7 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) } else { - switch(chat.mChatType) + switch (chat.mChatType) { case CHAT_TYPE_WHISPER: verb = " " + LLTrans::getString("whisper") + " "; @@ -4219,7 +2565,7 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) std::string strExecuted, strFailed, strRetained, *pstr; boost_tokenizer tokens(mesg, boost::char_separator(",", "", boost::drop_empty_tokens)); - for (boost_tokenizer::iterator itToken = tokens.begin(); itToken != tokens.end(); ++itToken) + for (auto itToken = tokens.begin(); itToken != tokens.end(); ++itToken) { std::string strCmd = *itToken; @@ -4350,11 +2696,19 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) // of TeleportRequest, then this info is redundant, but if the sim // initiated the teleport (via a script call, being killed, etc.) // then this info is news to us. -void process_teleport_start(LLMessageSystem *msg, void**) +void process_teleport_start(LLMessageSystem* msg, void**) { + // on teleport, don't tell them about destination guide anymore + //LLFirstUse::notUsingDestinationGuide(false); U32 teleport_flags = 0x0; msg->getU32("Info", "TeleportFlags", teleport_flags); + if (gAgent.getTeleportState() == LLAgent::TELEPORT_MOVING) + { + // Race condition? + LL_WARNS("Messaging") << "Got TeleportStart, but teleport already in progress. TeleportFlags=" << teleport_flags << LL_ENDL; + } + LL_DEBUGS("Messaging") << "Got TeleportStart with TeleportFlags=" << teleport_flags << ". gTeleportDisplay: " << gTeleportDisplay << ", gAgent.mTeleportState: " << gAgent.getTeleportState() << LL_ENDL; // if (teleport_flags & TELEPORT_FLAGS_DISABLE_CANCEL) @@ -4372,10 +2726,11 @@ void process_teleport_start(LLMessageSystem *msg, void**) // Freeze the UI and show progress bar // Note: could add data here to differentiate between normal teleport and death. - if( gAgent.getTeleportState() == LLAgent::TELEPORT_NONE ) + if (gAgent.getTeleportState() == LLAgent::TELEPORT_NONE) { gTeleportDisplay = TRUE; - gAgent.setTeleportState( LLAgent::TELEPORT_START ); + gAgent.setTeleportState(LLAgent::TELEPORT_START); + make_ui_sound("UISndTeleportOut"); LL_INFOS("Messaging") << "Teleport initiated by remote TeleportStart message with TeleportFlags: " << teleport_flags << LL_ENDL; @@ -4389,7 +2744,7 @@ void process_teleport_progress(LLMessageSystem* msg, void**) { LLUUID agent_id; msg->getUUID("AgentData", "AgentID", agent_id); - if((gAgent.getID() != agent_id) + if ((gAgent.getID() != agent_id) || (gAgent.getTeleportState() == LLAgent::TELEPORT_NONE)) { LL_WARNS("Messaging") << "Unexpected teleport progress message." << LL_ENDL; @@ -4410,14 +2765,14 @@ void process_teleport_progress(LLMessageSystem* msg, void**) } std::string buffer; msg->getString("Info", "Message", buffer); - LL_DEBUGS("Messaging") << "teleport progress: " << buffer << LL_ENDL; + LL_DEBUGS("Messaging") << "teleport progress: " << buffer << " flags: " << teleport_flags << LL_ENDL; //Sorta hacky...default to using simulator raw messages //if we don't find the coresponding mapping in our progress mappings std::string message = buffer; if (LLAgent::sTeleportProgressMessages.find(buffer) != - LLAgent::sTeleportProgressMessages.end() ) + LLAgent::sTeleportProgressMessages.end()) { message = LLAgent::sTeleportProgressMessages[buffer]; } @@ -4425,13 +2780,15 @@ void process_teleport_progress(LLMessageSystem* msg, void**) gAgent.setTeleportMessage(LLAgent::sTeleportProgressMessages[message]); } -class LLFetchInWelcomeArea : public LLInventoryFetchDescendentsObserver +class LLFetchInWelcomeArea final : public LLInventoryFetchDescendentsObserver { public: - LLFetchInWelcomeArea(const uuid_vec_t &ids) : + LLFetchInWelcomeArea(const uuid_vec_t& ids) : LLInventoryFetchDescendentsObserver(ids) - {} - virtual void done() + { + } + + void done() override { LLIsType is_landmark(LLAssetType::AT_LANDMARK); LLIsType is_card(LLAssetType::AT_CALLINGCARD); @@ -4443,7 +2800,7 @@ public: uuid_vec_t::iterator it = mComplete.begin(); uuid_vec_t::iterator end = mComplete.end(); - for(; it != end; ++it) + for (; it != end; ++it) { gInventory.collectDescendentsIf( (*it), @@ -4459,13 +2816,13 @@ public: is_card); } LLSD args; - if ( land_items.size() > 0 ) + if (!land_items.empty()) { // Show notification that they can now teleport to landmarks. Use a random landmark from the inventory S32 random_land = ll_rand(land_items.size() - 1); args["NAME"] = land_items[random_land]->getName(); LLNotificationsUtil::add("TeleportToLandmark",args); } - if ( card_items.size() > 0 ) + if (!card_items.empty()) { // Show notification that they can now contact people. Use a random calling card from the inventory S32 random_card = ll_rand(card_items.size() - 1); args["NAME"] = card_items[random_card]->getName(); @@ -4478,18 +2835,17 @@ public: }; - -class LLPostTeleportNotifiers : public LLEventTimer +class LLPostTeleportNotifiers final : public LLEventTimer { public: LLPostTeleportNotifiers(); virtual ~LLPostTeleportNotifiers(); //function to be called at the supplied frequency - virtual BOOL tick(); + BOOL tick() override; }; -LLPostTeleportNotifiers::LLPostTeleportNotifiers() : LLEventTimer( 2.0 ) +LLPostTeleportNotifiers::LLPostTeleportNotifiers() : LLEventTimer(2.0) { }; @@ -4500,21 +2856,21 @@ LLPostTeleportNotifiers::~LLPostTeleportNotifiers() BOOL LLPostTeleportNotifiers::tick() { BOOL all_done = FALSE; - if ( gAgent.getTeleportState() == LLAgent::TELEPORT_NONE ) + if (gAgent.getTeleportState() == LLAgent::TELEPORT_NONE) { // get callingcards and landmarks available to the user arriving. uuid_vec_t folders; const LLUUID callingcard_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD); - if(callingcard_id.notNull()) + if (callingcard_id.notNull()) folders.push_back(callingcard_id); const LLUUID folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK); - if(folder_id.notNull()) + if (folder_id.notNull()) folders.push_back(folder_id); - if(!folders.empty()) + if (!folders.empty()) { LLFetchInWelcomeArea* fetcher = new LLFetchInWelcomeArea(folders); fetcher->startFetch(); - if(fetcher->isFinished()) + if (fetcher->isFinished()) { fetcher->done(); } @@ -4530,7 +2886,6 @@ BOOL LLPostTeleportNotifiers::tick() } - // Teleport notification from the simulator // We're going to pretend to be a new agent void process_teleport_finish(LLMessageSystem* msg, void**) @@ -4551,7 +2906,7 @@ void process_teleport_finish(LLMessageSystem* msg, void**) // Do teleport effect for where you're leaving // VEFFECT: TeleportStart - LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE); + LLHUDEffectSpiral* effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE); effectp->setPositionGlobal(gAgent.getPositionGlobal()); effectp->setColor(LLColor4U(gAgent.getEffectColor())); LLHUDManager::getInstance()->sendEffects(); @@ -4570,11 +2925,12 @@ void process_teleport_finish(LLMessageSystem* msg, void**) U32 teleport_flags; msg->getU32Fast(_PREHASH_Info, _PREHASH_TeleportFlags, teleport_flags); + std::string seedCap; msg->getStringFast(_PREHASH_Info, _PREHASH_SeedCapability, seedCap); // update home location if we are teleporting out of prelude - specific to teleporting to welcome area - if((teleport_flags & TELEPORT_FLAGS_SET_HOME_TO_TARGET) + if ((teleport_flags & TELEPORT_FLAGS_SET_HOME_TO_TARGET) && (!gAgent.isGodlike())) { gAgent.setHomePosRegion(region_handle, pos); @@ -4588,7 +2944,6 @@ void process_teleport_finish(LLMessageSystem* msg, void**) // Viewer trusts the simulator. gMessageSystem->enableCircuit(sim_host, TRUE); -// Aurora Sim if (!gHippoGridManager->getConnectedGrid()->isSecondLife()) { U32 region_size_x = 256; @@ -4597,12 +2952,13 @@ void process_teleport_finish(LLMessageSystem* msg, void**) msg->getU32Fast(_PREHASH_Info, _PREHASH_RegionSizeY, region_size_y); LLWorld::getInstance()->setRegionSize(region_size_x, region_size_y); } -// Aurora Sim LLViewerRegion* regionp = LLWorld::getInstance()->addRegion(region_handle, sim_host); -/* + M7WindlightInterface::getInstance()->receiveReset(); + + /* // send camera update to new region - gAgent.updateCamera(); + gAgentCamera.updateCamera(); // likewise make sure the camera is behind the avatar gAgentCamera.resetView(TRUE); @@ -4620,8 +2976,6 @@ void process_teleport_finish(LLMessageSystem* msg, void**) gCacheName->setUpstream(sim); */ - M7WindlightInterface::getInstance()->receiveReset(); - // Make sure we're standing gAgent.standUp(); @@ -4636,9 +2990,11 @@ void process_teleport_finish(LLMessageSystem* msg, void**) msg->sendReliable(sim_host); send_complete_agent_movement(sim_host); - gAgent.setTeleportState( LLAgent::TELEPORT_MOVING ); + gAgent.setTeleportState(LLAgent::TELEPORT_MOVING); gAgent.setTeleportMessage(LLAgent::sTeleportProgressMessages["contacting"]); + LL_DEBUGS("CrossingCaps") << "Calling setSeedCapability from process_teleport_finish(). Seed cap == " + << seedCap << LL_ENDL; regionp->setSeedCapability(seedCap); // Don't send camera updates to the new region until we're @@ -4653,9 +3009,9 @@ void process_teleport_finish(LLMessageSystem* msg, void**) effectp->setColor(LLColor4U(gAgent.getEffectColor())); LLHUDManager::getInstance()->sendEffects(); -// gTeleportDisplay = TRUE; -// gTeleportDisplayTimer.reset(); -// gViewerWindow->setShowProgress(TRUE); + // gTeleportDisplay = TRUE; + // gTeleportDisplayTimer.reset(); + // gViewerWindow->setShowProgress(TRUE); } // stuff we have to do every time we get an AvatarInitComplete from a sim @@ -4677,7 +3033,7 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); LLUUID session_id; msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_SessionID, session_id); - if((gAgent.getID() != agent_id) || (gAgent.getSessionID() != session_id)) + if ((gAgent.getID() != agent_id) || (gAgent.getSessionID() != session_id)) { LL_WARNS("Messaging") << "Incorrect id in process_agent_movement_complete()" << LL_ENDL; @@ -4721,7 +3077,6 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) << LL_ENDL; LLAppViewer::instance()->forceDisconnect(LLTrans::getString("SentToInvalidRegion")); return; - } LL_INFOS("Messaging") << "Changing home region to " << x << ":" << y << LL_ENDL; @@ -4738,12 +3093,11 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) regionp->reInitPartitions(); gAgent.setRegion(regionp); // Kill objects in the regions we left behind - for (LLWorld::region_list_t::const_iterator r = LLWorld::getInstance()->getRegionList().begin(); - r != LLWorld::getInstance()->getRegionList().end(); ++r) + for (auto r : LLWorld::getInstance()->getRegionList()) { - if (*r != regionp) + if (r != regionp) { - gObjectList.killObjects(*r); + gObjectList.killObjects(r); } } } @@ -4754,7 +3108,7 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) bool is_teleport = gAgent.getTeleportState() == LLAgent::TELEPORT_MOVING; - if( is_teleport ) + if (is_teleport) { if (gAgent.getTeleportKeepsLookAt()) { @@ -4767,7 +3121,7 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) gAgentCamera.slamLookAt(look_at); gAgentCamera.updateCamera(); - gAgent.setTeleportState( LLAgent::TELEPORT_START_ARRIVAL ); + gAgent.setTeleportState(LLAgent::TELEPORT_START_ARRIVAL); // set the appearance on teleport since the new sim does not // know what you look like. @@ -4776,7 +3130,6 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) if (isAgentAvatarValid()) { // Chat the "back" SLURL. (DEV-4907) - LLSLURL slurl; gAgent.getTeleportSourceSLURL(slurl); LLChat chat(LLTrans::getString("completed_from") + " " + slurl.getSLURLString()); @@ -4795,9 +3148,9 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) else { // This is initial log-in or a region crossing - gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); + gAgent.setTeleportState(LLAgent::TELEPORT_NONE); - if(LLStartUp::getStartupState() < STATE_STARTED) + if (LLStartUp::getStartupState() < STATE_STARTED) { // This is initial log-in, not a region crossing: // Set the camera looking ahead of the AV so send_agent_update() below // will report the correct location to the server. @@ -4820,7 +3173,7 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) } else if (is_teleport) { - if (!gAgent.getTeleportKeepsLookAt()) + if (!gAgent.getTeleportKeepsLookAt() && look_at.isExactlyZero()) { //look at the beacon LLVector3 global_agent_pos = agent_pos; @@ -4857,7 +3210,8 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) gAgent.setFlying(false/*gAgent.canFly()*/); } - // force simulator to recognize busy state + // force simulator to recognize do not disturb state + gAgent.setDoNotDisturb(gAgent.isDoNotDisturb()); if (isAgentAvatarValid()) @@ -4880,9 +3234,10 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) if (!gLastVersionChannel.empty() && gSavedSettings.getBOOL("SGServerVersionChangedNotification")) { - LLSD payload; - payload["message"] = version_channel; - LLNotificationsUtil::add("ServerVersionChanged", LLSD(), payload); + LLSD args; + args["OLD_VERSION"] = gLastVersionChannel; + args["NEW_VERSION"] = version_channel; + LLNotificationsUtil::add("ServerVersionChanged", args); } gLastVersionChannel = version_channel; @@ -4894,7 +3249,7 @@ void process_crossed_region(LLMessageSystem* msg, void**) msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); LLUUID session_id; msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_SessionID, session_id); - if((gAgent.getID() != agent_id) || (gAgent.getSessionID() != session_id)) + if ((gAgent.getID() != agent_id) || (gAgent.getSessionID() != session_id)) { LL_WARNS("Messaging") << "Incorrect id in process_crossed_region()" << LL_ENDL; @@ -4902,6 +3257,8 @@ void process_crossed_region(LLMessageSystem* msg, void**) } LL_INFOS("Messaging") << "process_crossed_region()" << LL_ENDL; gAgentAvatarp->resetRegionCrossingTimer(); + gAgent.setIsCrossingRegion(false); // Attachments getting lost on TP, region crossing hook + U32 sim_ip; msg->getIPAddrFast(_PREHASH_RegionData, _PREHASH_SimIP, sim_ip); @@ -4916,7 +3273,6 @@ void process_crossed_region(LLMessageSystem* msg, void**) send_complete_agent_movement(sim_host); -// Aurora Sim if (!gHippoGridManager->getConnectedGrid()->isSecondLife()) { U32 region_size_x = 256; @@ -4925,13 +3281,14 @@ void process_crossed_region(LLMessageSystem* msg, void**) msg->getU32(_PREHASH_RegionData, _PREHASH_RegionSizeY, region_size_y); LLWorld::getInstance()->setRegionSize(region_size_x, region_size_y); } -// Aurora Sim LLViewerRegion* regionp = LLWorld::getInstance()->addRegion(region_handle, sim_host); + + LL_DEBUGS("CrossingCaps") << "Calling setSeedCapability from process_crossed_region(). Seed cap == " + << seedCap << LL_ENDL; regionp->setSeedCapability(seedCap); } - // Sends avatar and camera information to simulator. // Sent roughly once per frame, or 20 times per second, whichever is less often @@ -4951,13 +3308,13 @@ void send_agent_update(BOOL force_send, BOOL send_reliable) } // We have already requested to log out. Don't send agent updates. - if(LLAppViewer::instance()->logoutRequestSent()) + if (LLAppViewer::instance()->logoutRequestSent()) { return; } // no region to send update to - if(gAgent.getRegion() == NULL) + if (gAgent.getRegion() == nullptr) { return; } @@ -4967,7 +3324,7 @@ void send_agent_update(BOOL force_send, BOOL send_reliable) // NOTA BENE: This is (intentionally?) using the small angle sine approximation to test for rotation // Plus, there is an extra 0.5 in the mix since the perpendicular between last_camera_at and getAtAxis() bisects cam_rot_change // Thus, we're actually testing against 0.2 degrees - const F32 ROTATION_THRESHOLD = 0.1f * 2.f*F_PI/360.f; // Rotation thresh 0.2 deg, see note above + const F32 ROTATION_THRESHOLD = 0.1f * 2.f * F_PI / 360.f; // Rotation thresh 0.2 deg, see note above const U8 DUP_MSGS = 1; // HACK! number of times to repeat data on motionless agent @@ -4987,7 +3344,7 @@ void send_agent_update(BOOL force_send, BOOL send_reliable) static F32 head_rot_chg = 1.0; static U8 last_flags; - LLMessageSystem *msg = gMessageSystem; + LLMessageSystem* msg = gMessageSystem; LLVector3 camera_pos_agent; // local to avatar's region U8 render_state; @@ -5009,21 +3366,22 @@ void send_agent_update(BOOL force_send, BOOL send_reliable) // trigger a control event. U32 control_flags = gAgent.getControlFlags(); - // - if(gSavedSettings.getBOOL("Nimble")) + // + static LLCachedControl alchemyPrejump(gSavedSettings, "Nimble", false); + if (alchemyPrejump) { control_flags |= AGENT_CONTROL_FINISH_ANIM; } - // + // MASK key_mask = gKeyboard->currentMask(TRUE); if (key_mask & MASK_ALT || key_mask & MASK_CONTROL) { - control_flags &= ~( AGENT_CONTROL_LBUTTON_DOWN | - AGENT_CONTROL_ML_LBUTTON_DOWN ); + control_flags &= ~(AGENT_CONTROL_LBUTTON_DOWN | + AGENT_CONTROL_ML_LBUTTON_DOWN); control_flags |= AGENT_CONTROL_LBUTTON_UP | - AGENT_CONTROL_ML_LBUTTON_UP ; + AGENT_CONTROL_ML_LBUTTON_UP; } control_flag_change = last_control_flags ^ control_flags; @@ -5137,10 +3495,10 @@ void send_agent_update(BOOL force_send, BOOL send_reliable) msg->addU8Fast(_PREHASH_State, render_state); msg->addU8Fast(_PREHASH_Flags, flags); -// if (camera_pos_agent.mV[VY] > 255.f) -// { -// LL_INFOS("Messaging") << "Sending camera center " << camera_pos_agent << LL_ENDL; -// } + // if (camera_pos_agent.mV[VY] > 255.f) + // { + // LL_INFOS("Messaging") << "Sending camera center " << camera_pos_agent << LL_ENDL; + // } msg->addVector3Fast(_PREHASH_CameraCenter, camera_pos_agent); msg->addVector3Fast(_PREHASH_CameraAtAxis, LLViewerCamera::getInstance()->getAtAxis()); @@ -5174,7 +3532,7 @@ void send_agent_update(BOOL force_send, BOOL send_reliable) gAgent.sendReliableMessage(); } -// LL_DEBUGS("Messaging") << "agent " << avatar_pos_agent << " cam " << camera_pos_agent << LL_ENDL; + // LL_DEBUGS("Messaging") << "agent " << avatar_pos_agent << " cam " << camera_pos_agent << LL_ENDL; // Copy the old data last_head_rot = head_rotation; @@ -5189,53 +3547,167 @@ void send_agent_update(BOOL force_send, BOOL send_reliable) } +// sounds can arrive before objects, store them for a short time +// Note: this is a workaround for MAINT-4743, real fix would be to make +// server send sound along with object update that creates (rezes) the object +class PostponedSoundData +{ +public: + PostponedSoundData() : + mExpirationTime(0) + {} + PostponedSoundData(const LLUUID &object_id, const LLUUID &sound_id, const LLUUID& owner_id, const F32 gain, const U8 flags); + bool hasExpired() { return LLFrameTimer::getTotalSeconds() > mExpirationTime; } + + LLUUID mObjectId; + LLUUID mSoundId; + LLUUID mOwnerId; + F32 mGain; + U8 mFlags; + static const F64 MAXIMUM_PLAY_DELAY; + +private: + F64 mExpirationTime; //seconds since epoch +}; +const F64 PostponedSoundData::MAXIMUM_PLAY_DELAY = 15.0; +static F64 postponed_sounds_update_expiration = 0.0; +static std::map postponed_sounds; + +void set_attached_sound(LLViewerObject *objectp, const LLUUID &object_id, const LLUUID &sound_id, const LLUUID& owner_id, const F32 gain, const U8 flags) +{ + if (LLMuteList::getInstance()->isMuted(object_id)) return; + + if (LLMuteList::getInstance()->isMuted(owner_id, LLMute::flagObjectSounds)) return; + + // Don't play sounds from a region with maturity above current agent maturity + LLVector3d pos = objectp->getPositionGlobal(); + if (!gAgent.canAccessMaturityAtGlobal(pos)) + { + return; + } + + objectp->setAttachedSound(sound_id, owner_id, gain, flags); +} + +PostponedSoundData::PostponedSoundData(const LLUUID &object_id, const LLUUID &sound_id, const LLUUID& owner_id, const F32 gain, const U8 flags) + : + mObjectId(object_id), + mSoundId(sound_id), + mOwnerId(owner_id), + mGain(gain), + mFlags(flags), + mExpirationTime(LLFrameTimer::getTotalSeconds() + MAXIMUM_PLAY_DELAY) +{ +} + +// static +void update_attached_sounds() +{ + if (postponed_sounds.empty()) + { + return; + } + + std::map::iterator iter = postponed_sounds.begin(); + std::map::iterator end = postponed_sounds.end(); + while (iter != end) + { + std::map::iterator cur_iter = iter++; + PostponedSoundData* data = &cur_iter->second; + if (data->hasExpired()) + { + postponed_sounds.erase(cur_iter); + } + else + { + LLViewerObject *objectp = gObjectList.findObject(data->mObjectId); + if (objectp) + { + set_attached_sound(objectp, data->mObjectId, data->mSoundId, data->mOwnerId, data->mGain, data->mFlags); + postponed_sounds.erase(cur_iter); + } + } + } + postponed_sounds_update_expiration = LLFrameTimer::getTotalSeconds() + 2 * PostponedSoundData::MAXIMUM_PLAY_DELAY; +} + +//static +void clear_expired_postponed_sounds() +{ + if (postponed_sounds_update_expiration > LLFrameTimer::getTotalSeconds()) + { + return; + } + std::map::iterator iter = postponed_sounds.begin(); + std::map::iterator end = postponed_sounds.end(); + while (iter != end) + { + std::map::iterator cur_iter = iter++; + PostponedSoundData* data = &cur_iter->second; + if (data->hasExpired()) + { + postponed_sounds.erase(cur_iter); + } + } + postponed_sounds_update_expiration = LLFrameTimer::getTotalSeconds() + 2 * PostponedSoundData::MAXIMUM_PLAY_DELAY; +} // *TODO: Remove this dependency, or figure out a better way to handle // this hack. extern U32Bits gObjectData; -void process_object_update(LLMessageSystem *mesgsys, void **user_data) +void process_object_update(LLMessageSystem* mesgsys, void** user_data) { // Update the data counters if (mesgsys->getReceiveCompressedSize()) { - gObjectData += (U32Bytes)mesgsys->getReceiveCompressedSize(); + gObjectData += U32Bytes(mesgsys->getReceiveCompressedSize()); } else { - gObjectData += (U32Bytes)mesgsys->getReceiveSize(); + gObjectData += U32Bytes(mesgsys->getReceiveSize()); } // Update the object... + S32 old_num_objects = gObjectList.mNumNewObjects; gObjectList.processObjectUpdate(mesgsys, user_data, OUT_FULL); + if (old_num_objects != gObjectList.mNumNewObjects) + { + update_attached_sounds(); + } } -void process_compressed_object_update(LLMessageSystem *mesgsys, void **user_data) +void process_compressed_object_update(LLMessageSystem* mesgsys, void** user_data) { // Update the data counters if (mesgsys->getReceiveCompressedSize()) { - gObjectData += (U32Bytes)mesgsys->getReceiveCompressedSize(); + gObjectData += U32Bytes(mesgsys->getReceiveCompressedSize()); } else { - gObjectData += (U32Bytes)mesgsys->getReceiveSize(); + gObjectData += U32Bytes(mesgsys->getReceiveSize()); } // Update the object... + S32 old_num_objects = gObjectList.mNumNewObjects; gObjectList.processCompressedObjectUpdate(mesgsys, user_data, OUT_FULL_COMPRESSED); + if (old_num_objects != gObjectList.mNumNewObjects) + { + update_attached_sounds(); + } } -void process_cached_object_update(LLMessageSystem *mesgsys, void **user_data) +void process_cached_object_update(LLMessageSystem* mesgsys, void** user_data) { // Update the data counters if (mesgsys->getReceiveCompressedSize()) { - gObjectData += (U32Bytes)mesgsys->getReceiveCompressedSize(); + gObjectData += U32Bytes(mesgsys->getReceiveCompressedSize()); } else { - gObjectData += (U32Bytes)mesgsys->getReceiveSize(); + gObjectData += U32Bytes(mesgsys->getReceiveSize()); } // Update the object... @@ -5243,48 +3715,52 @@ void process_cached_object_update(LLMessageSystem *mesgsys, void **user_data) } -void process_terse_object_update_improved(LLMessageSystem *mesgsys, void **user_data) +void process_terse_object_update_improved(LLMessageSystem* mesgsys, void** user_data) { if (mesgsys->getReceiveCompressedSize()) { - gObjectData += (U32Bytes)mesgsys->getReceiveCompressedSize(); + gObjectData += U32Bytes(mesgsys->getReceiveCompressedSize()); } else { - gObjectData += (U32Bytes)mesgsys->getReceiveSize(); + gObjectData += U32Bytes(mesgsys->getReceiveSize()); } + S32 old_num_objects = gObjectList.mNumNewObjects; gObjectList.processCompressedObjectUpdate(mesgsys, user_data, OUT_TERSE_IMPROVED); + if (old_num_objects != gObjectList.mNumNewObjects) + { + update_attached_sounds(); + } } -static LLTrace::BlockTimerStatHandle FTM_PROCESS_OBJECTS("Process Objects"); +static LLTrace::BlockTimerStatHandle FTM_PROCESS_OBJECTS("Process Kill Objects"); - -void process_kill_object(LLMessageSystem *mesgsys, void **user_data) +void process_kill_object(LLMessageSystem* mesgsys, void** user_data) { LL_RECORD_BLOCK_TIME(FTM_PROCESS_OBJECTS); + auto agent_region = gAgent.getRegion(); + if (!agent_region) return; + LLUUID id; - U32 local_id; - S32 i; - S32 num_objects; - num_objects = mesgsys->getNumberOfBlocksFast(_PREHASH_ObjectData); + U32 ip = mesgsys->getSenderIP(); + U32 port = mesgsys->getSenderPort(); - bool different_region = mesgsys->getSender().getIPandPort() != gAgent.getRegion()->getHost().getIPandPort(); + bool different_region = mesgsys->getSender().getIPandPort() != agent_region->getHost().getIPandPort(); - for (i = 0; i < num_objects; i++) + S32 num_objects = mesgsys->getNumberOfBlocksFast(_PREHASH_ObjectData); + for (S32 i = 0; i < num_objects; ++i) { + U32 local_id; mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_ID, local_id, i); - LLViewerObjectList::getUUIDFromLocal(id, - local_id, - gMessageSystem->getSenderIP(), - gMessageSystem->getSenderPort()); + LLViewerObjectList::getUUIDFromLocal(id, local_id, ip, port); if (id == LLUUID::null) { LL_DEBUGS("Messaging") << "Unknown kill for local " << local_id << LL_ENDL; - gObjectList.mNumUnknownKills++; + ++gObjectList.mNumUnknownKills; continue; } else @@ -5292,43 +3768,58 @@ void process_kill_object(LLMessageSystem *mesgsys, void **user_data) LL_DEBUGS("Messaging") << "Kill message for local " << local_id << LL_ENDL; } - // ...don't kill the avatar - if (!(id == gAgentID)) + if (id == gAgentID) { - LLViewerObject *objectp = gObjectList.findObject(id); - if (objectp) + // never kill our avatar + continue; + } + + LLViewerObject* objectp = gObjectList.findObject(id); + if (objectp) + { + if (gAgentAvatarp == objectp->getAvatar()) { - if (different_region && gAgentAvatarp == objectp->getAvatar()) + if (different_region) { LL_WARNS() << "Region other than our own killing our attachments!!" << LL_ENDL; continue; } - // Display green bubble on kill - if ( gShowObjectUpdates ) + else if (gAgent.getTeleportState() != LLAgent::TELEPORT_NONE) { - LLColor4 color(0.f,1.f,0.f,1.f); - gPipeline.addDebugBlip(objectp->getPositionAgent(), color); + LL_WARNS() << "Region killing our attachments during teleport!!" << LL_ENDL; + continue; } + else if (gAgent.isCrossingRegion()) + { + LL_WARNS() << "Region killing our attachments during region cross!!" << LL_ENDL; + continue; + } + } - // Do the kill - gObjectList.killObject(objectp); - } - else + // Display green bubble on kill + if (gShowObjectUpdates) { - LL_WARNS("Messaging") << "Object in UUID lookup, but not on object list in kill!" << LL_ENDL; - gObjectList.mNumUnknownKills++; + LLColor4 color(0.f, 1.f, 0.f, 1.f); + gPipeline.addDebugBlip(objectp->getPositionAgent(), color); } + + // Do the kill + gObjectList.killObject(objectp); + } + else + { + LL_WARNS("Messaging") << "Object in UUID lookup, but not on object list in kill!" << LL_ENDL; + gObjectList.mNumUnknownKills++; } // We should remove the object from selection after it is marked dead by gObjectList to make LLToolGrab, // which is using the object, release the mouse capture correctly when the object dies. // See LLToolGrab::handleHoverActive() and LLToolGrab::handleHoverNonPhysical(). LLSelectMgr::getInstance()->removeObjectFromSelections(id); - } } -void process_time_synch(LLMessageSystem *mesgsys, void **user_data) +void process_time_synch(LLMessageSystem* mesgsys, void** user_data) { LLVector3 sun_direction; LLVector3 sun_ang_velocity; @@ -5350,7 +3841,7 @@ void process_time_synch(LLMessageSystem *mesgsys, void **user_data) LLWorld::getInstance()->setSpaceTimeUSec(space_time_usec); - LL_DEBUGS("Windlight Sync") << "Sun phase: " << phase << " rad = " << fmodf(phase / F_TWO_PI + 0.25, 1.f) * 24.f << " h" << LL_ENDL; + LL_DEBUGS("WindlightSync") << "Sun phase: " << phase << " rad = " << fmodf(phase / F_TWO_PI + 0.25, 1.f) * 24.f << " h" << LL_ENDL; gSky.setSunPhase(phase); gSky.setSunTargetDirection(sun_direction, sun_ang_velocity); @@ -5360,9 +3851,15 @@ void process_time_synch(LLMessageSystem *mesgsys, void **user_data) } } -void process_sound_trigger(LLMessageSystem *msg, void **) +void process_sound_trigger(LLMessageSystem* msg, void**) { - if (!gAudiop) return; + if (!gAudiop) + { +#if !LL_LINUX + LL_WARNS("AudioEngine") << "LLAudioEngine instance doesn't exist!" << LL_ENDL; +#endif + return; + } U64 region_handle = 0; F32 gain = 0; @@ -5377,18 +3874,18 @@ void process_sound_trigger(LLMessageSystem *msg, void **) msg->getUUIDFast(_PREHASH_SoundData, _PREHASH_ObjectID, object_id); // NaCl - Antispam Registry - static LLCachedControl _NACL_AntiSpamSoundMulti(gSavedSettings,"_NACL_AntiSpamSoundMulti"); - if(owner_id.isNull()) + if (auto antispam = NACLAntiSpamRegistry::getIfExists()) { - bool bDoSpamCheck=1; - std::string sSound=sound_id.asString(); - for(int i=0;i< COLLISION_SOUNDS_SIZE;i++) - if(COLLISION_SOUNDS[i] == sSound) - bDoSpamCheck=0; - if(bDoSpamCheck) - if(NACLAntiSpamRegistry::checkQueue((U32)NACLAntiSpamRegistry::QUEUE_SOUND,object_id, _NACL_AntiSpamSoundMulti)) return; + static const LLCachedControl _NACL_AntiSpamSoundMulti("_NACL_AntiSpamSoundMulti"); + if (owner_id.isNull()) + { + bool is_collision_sound(const std::string & sound); + if (!is_collision_sound(sound_id.asString()) + && antispam->checkQueue(NACLAntiSpamRegistry::QUEUE_SOUND, object_id, LFIDBearer::OBJECT, _NACL_AntiSpamSoundMulti)) + return; + } + else if (antispam->checkQueue(NACLAntiSpamRegistry::QUEUE_SOUND, owner_id, LFIDBearer::AVATAR, _NACL_AntiSpamSoundMulti)) return; } - else if(NACLAntiSpamRegistry::checkQueue((U32)NACLAntiSpamRegistry::QUEUE_SOUND,owner_id, _NACL_AntiSpamSoundMulti)) return; // NaCl End msg->getUUIDFast(_PREHASH_SoundData, _PREHASH_ParentID, parent_id); @@ -5420,7 +3917,7 @@ void process_sound_trigger(LLMessageSystem *msg, void **) } // Don't play sounds from a region with maturity above current agent maturity - if( !gAgent.canAccessMaturityInRegion( region_handle ) ) + if (!gAgent.canAccessMaturityInRegion(region_handle)) { return; } @@ -5448,10 +3945,13 @@ void process_sound_trigger(LLMessageSystem *msg, void **) // } -void process_preload_sound(LLMessageSystem *msg, void **user_data) +void process_preload_sound(LLMessageSystem* msg, void** user_data) { if (!gAudiop) { +#if !LL_LINUX + LL_WARNS("AudioEngine") << "LLAudioEngine instance doesn't exist!" << LL_ENDL; +#endif return; } @@ -5464,20 +3964,23 @@ void process_preload_sound(LLMessageSystem *msg, void **user_data) msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_OwnerID, owner_id); // NaCl - Antispam Registry - static LLCachedControl _NACL_AntiSpamSoundPreloadMulti(gSavedSettings,"_NACL_AntiSpamSoundPreloadMulti"); - if((owner_id.isNull() - && NACLAntiSpamRegistry::checkQueue((U32)NACLAntiSpamRegistry::QUEUE_SOUND_PRELOAD,object_id,_NACL_AntiSpamSoundPreloadMulti)) - || NACLAntiSpamRegistry::checkQueue((U32)NACLAntiSpamRegistry::QUEUE_SOUND_PRELOAD,owner_id,_NACL_AntiSpamSoundPreloadMulti)) - return; + if (auto antispam = NACLAntiSpamRegistry::getIfExists()) + { + static const LLCachedControl _NACL_AntiSpamSoundPreloadMulti("_NACL_AntiSpamSoundPreloadMulti"); + if ((owner_id.isNull() + && antispam->checkQueue(NACLAntiSpamRegistry::QUEUE_SOUND_PRELOAD, object_id, LFIDBearer::OBJECT, _NACL_AntiSpamSoundPreloadMulti)) + || antispam->checkQueue(NACLAntiSpamRegistry::QUEUE_SOUND_PRELOAD, owner_id, LFIDBearer::AVATAR, _NACL_AntiSpamSoundPreloadMulti)) + return; + } // NaCl End - LLViewerObject *objectp = gObjectList.findObject(object_id); + LLViewerObject* objectp = gObjectList.findObject(object_id); if (!objectp) return; if (LLMuteList::getInstance()->isMuted(object_id)) return; if (LLMuteList::getInstance()->isMuted(owner_id, LLMute::flagObjectSounds)) return; - LLAudioSource *sourcep = objectp->getAudioSource(owner_id); + LLAudioSource* sourcep = objectp->getAudioSource(owner_id); if (!sourcep) return; // Note that I don't actually do any loading of the @@ -5493,7 +3996,7 @@ void process_preload_sound(LLMessageSystem *msg, void **user_data) } } -void process_attached_sound(LLMessageSystem *msg, void **user_data) +void process_attached_sound(LLMessageSystem* msg, void** user_data) { F32 gain = 0; LLUUID sound_id; @@ -5506,43 +4009,46 @@ void process_attached_sound(LLMessageSystem *msg, void **user_data) msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_OwnerID, owner_id); // NaCl - Antispam Registry - if((owner_id.isNull() - && NACLAntiSpamRegistry::checkQueue((U32)NACLAntiSpamRegistry::QUEUE_SOUND,object_id)) - || NACLAntiSpamRegistry::checkQueue((U32)NACLAntiSpamRegistry::QUEUE_SOUND,owner_id)) - return; + if (auto antispam = NACLAntiSpamRegistry::getIfExists()) + { + if ((owner_id.isNull() + && antispam->checkQueue(NACLAntiSpamRegistry::QUEUE_SOUND, object_id, LFIDBearer::OBJECT)) + || antispam->checkQueue(NACLAntiSpamRegistry::QUEUE_SOUND, owner_id)) + return; + } // NaCl End msg->getF32Fast(_PREHASH_DataBlock, _PREHASH_Gain, gain); msg->getU8Fast(_PREHASH_DataBlock, _PREHASH_Flags, flags); LLViewerObject *objectp = gObjectList.findObject(object_id); - if (!objectp) + if (objectp) { - // we don't know about this object, just bail - return; + set_attached_sound(objectp, object_id, sound_id, owner_id, gain, flags); } - - if (LLMuteList::getInstance()->isMuted(object_id)) return; - - if (LLMuteList::getInstance()->isMuted(owner_id, LLMute::flagObjectSounds)) return; - - - // Don't play sounds from a region with maturity above current agent maturity - LLVector3d pos = objectp->getPositionGlobal(); - if( !gAgent.canAccessMaturityAtGlobal(pos) ) + else if (sound_id.notNull()) { - return; + // we don't know about this object yet, probably it has yet to arrive + // std::map for dupplicate prevention. + if (!LLMuteList::getInstance()->isMuted(object_id) && !LLMuteList::getInstance()->isMuted(owner_id, LLMute::flagObjectSounds)) + postponed_sounds[object_id] = (PostponedSoundData(object_id, sound_id, owner_id, gain, flags)); + clear_expired_postponed_sounds(); + } + else + { + std::map::iterator iter = postponed_sounds.find(object_id); + if (iter != postponed_sounds.end()) + { + postponed_sounds.erase(iter); + } } - - objectp->setAttachedSound(sound_id, owner_id, gain, flags); } - void process_attached_sound_gain_change(LLMessageSystem *mesgsys, void **user_data) { F32 gain = 0; LLUUID object_guid; - LLViewerObject *objectp = NULL; + LLViewerObject* objectp = nullptr; mesgsys->getUUIDFast(_PREHASH_DataBlock, _PREHASH_ObjectID, object_guid); @@ -5558,7 +4064,7 @@ void process_attached_sound_gain_change(LLMessageSystem *mesgsys, void **user_da } -void process_health_message(LLMessageSystem *mesgsys, void **user_data) +void process_health_message(LLMessageSystem* mesgsys, void** user_data) { F32 health; @@ -5571,48 +4077,49 @@ void process_health_message(LLMessageSystem *mesgsys, void **user_data) } -void process_sim_stats(LLMessageSystem *msg, void **user_data) +void process_sim_stats(LLMessageSystem* msg, void** user_data) { static LLHost sLastHost; + auto& stats = LLViewerStats::instance(); if (msg->getSender() != sLastHost) { sLastHost = msg->getSender(); - LLViewerStats::getInstance()->mSimTimeDilation.reset(); - LLViewerStats::getInstance()->mSimFPS.reset(); - LLViewerStats::getInstance()->mSimPhysicsFPS.reset(); - LLViewerStats::getInstance()->mSimAgentUPS.reset(); - LLViewerStats::getInstance()->mSimFrameMsec.reset(); - LLViewerStats::getInstance()->mSimNetMsec.reset(); - LLViewerStats::getInstance()->mSimSimOtherMsec.reset(); - LLViewerStats::getInstance()->mSimSimPhysicsMsec.reset(); - LLViewerStats::getInstance()->mSimAgentMsec.reset(); - LLViewerStats::getInstance()->mSimImagesMsec.reset(); - LLViewerStats::getInstance()->mSimScriptMsec.reset(); - LLViewerStats::getInstance()->mSimObjects.reset(); - LLViewerStats::getInstance()->mSimActiveObjects.reset(); - LLViewerStats::getInstance()->mSimMainAgents.reset(); - LLViewerStats::getInstance()->mSimChildAgents.reset(); - LLViewerStats::getInstance()->mSimActiveScripts.reset(); - LLViewerStats::getInstance()->mSimScriptEPS.reset(); - LLViewerStats::getInstance()->mSimInPPS.reset(); - LLViewerStats::getInstance()->mSimOutPPS.reset(); - LLViewerStats::getInstance()->mSimPendingDownloads.reset(); - LLViewerStats::getInstance()->mSimPendingUploads.reset(); - LLViewerStats::getInstance()->mSimPendingLocalUploads.reset(); - LLViewerStats::getInstance()->mSimTotalUnackedBytes.reset(); - LLViewerStats::getInstance()->mPhysicsPinnedTasks.reset(); - LLViewerStats::getInstance()->mPhysicsLODTasks.reset(); - LLViewerStats::getInstance()->mSimSimPhysicsStepMsec.reset(); - LLViewerStats::getInstance()->mSimSimPhysicsShapeUpdateMsec.reset(); - LLViewerStats::getInstance()->mSimSimPhysicsOtherMsec.reset(); - LLViewerStats::getInstance()->mPhysicsMemoryAllocated.reset(); - LLViewerStats::getInstance()->mSimSpareMsec.reset(); - LLViewerStats::getInstance()->mSimSleepMsec.reset(); - LLViewerStats::getInstance()->mSimPumpIOMsec.reset(); - LLViewerStats::getInstance()->mSimPctScriptsRun.reset(); - LLViewerStats::getInstance()->mSimSimAIStepMsec.reset(); - LLViewerStats::getInstance()->mSimSimSkippedSilhouetteSteps.reset(); - LLViewerStats::getInstance()->mSimSimPctSteppedCharacters.reset(); + stats.mSimTimeDilation.reset(); + stats.mSimFPS.reset(); + stats.mSimPhysicsFPS.reset(); + stats.mSimAgentUPS.reset(); + stats.mSimFrameMsec.reset(); + stats.mSimNetMsec.reset(); + stats.mSimSimOtherMsec.reset(); + stats.mSimSimPhysicsMsec.reset(); + stats.mSimAgentMsec.reset(); + stats.mSimImagesMsec.reset(); + stats.mSimScriptMsec.reset(); + stats.mSimObjects.reset(); + stats.mSimActiveObjects.reset(); + stats.mSimMainAgents.reset(); + stats.mSimChildAgents.reset(); + stats.mSimActiveScripts.reset(); + stats.mSimScriptEPS.reset(); + stats.mSimInPPS.reset(); + stats.mSimOutPPS.reset(); + stats.mSimPendingDownloads.reset(); + stats.mSimPendingUploads.reset(); + stats.mSimPendingLocalUploads.reset(); + stats.mSimTotalUnackedBytes.reset(); + stats.mPhysicsPinnedTasks.reset(); + stats.mPhysicsLODTasks.reset(); + stats.mSimSimPhysicsStepMsec.reset(); + stats.mSimSimPhysicsShapeUpdateMsec.reset(); + stats.mSimSimPhysicsOtherMsec.reset(); + stats.mPhysicsMemoryAllocated.reset(); + stats.mSimSpareMsec.reset(); + stats.mSimSleepMsec.reset(); + stats.mSimPumpIOMsec.reset(); + stats.mSimPctScriptsRun.reset(); + stats.mSimSimAIStepMsec.reset(); + stats.mSimSimSkippedSilhouetteSteps.reset(); + stats.mSimSimPctSteppedCharacters.reset(); } S32 count = msg->getNumberOfBlocks("Stat"); for (S32 i = 0; i < count; ++i) @@ -5624,131 +4131,128 @@ void process_sim_stats(LLMessageSystem *msg, void **user_data) switch (stat_id) { case LL_SIM_STAT_TIME_DILATION: - LLViewerStats::getInstance()->mSimTimeDilation.addValue(stat_value); + stats.mSimTimeDilation.addValue(stat_value); break; case LL_SIM_STAT_FPS: - LLViewerStats::getInstance()->mSimFPS.addValue(stat_value); + stats.mSimFPS.addValue(stat_value); break; case LL_SIM_STAT_PHYSFPS: - LLViewerStats::getInstance()->mSimPhysicsFPS.addValue(stat_value); + stats.mSimPhysicsFPS.addValue(stat_value); break; case LL_SIM_STAT_AGENTUPS: - LLViewerStats::getInstance()->mSimAgentUPS.addValue(stat_value); + stats.mSimAgentUPS.addValue(stat_value); break; case LL_SIM_STAT_FRAMEMS: - LLViewerStats::getInstance()->mSimFrameMsec.addValue(stat_value); + stats.mSimFrameMsec.addValue(stat_value); break; case LL_SIM_STAT_NETMS: - LLViewerStats::getInstance()->mSimNetMsec.addValue(stat_value); + stats.mSimNetMsec.addValue(stat_value); break; case LL_SIM_STAT_SIMOTHERMS: - LLViewerStats::getInstance()->mSimSimOtherMsec.addValue(stat_value); + stats.mSimSimOtherMsec.addValue(stat_value); break; case LL_SIM_STAT_SIMPHYSICSMS: - LLViewerStats::getInstance()->mSimSimPhysicsMsec.addValue(stat_value); + stats.mSimSimPhysicsMsec.addValue(stat_value); break; case LL_SIM_STAT_AGENTMS: - LLViewerStats::getInstance()->mSimAgentMsec.addValue(stat_value); + stats.mSimAgentMsec.addValue(stat_value); break; case LL_SIM_STAT_IMAGESMS: - LLViewerStats::getInstance()->mSimImagesMsec.addValue(stat_value); + stats.mSimImagesMsec.addValue(stat_value); break; case LL_SIM_STAT_SCRIPTMS: - LLViewerStats::getInstance()->mSimScriptMsec.addValue(stat_value); + stats.mSimScriptMsec.addValue(stat_value); break; case LL_SIM_STAT_NUMTASKS: - LLViewerStats::getInstance()->mSimObjects.addValue(stat_value); + stats.mSimObjects.addValue(stat_value); break; case LL_SIM_STAT_NUMTASKSACTIVE: - LLViewerStats::getInstance()->mSimActiveObjects.addValue(stat_value); + stats.mSimActiveObjects.addValue(stat_value); break; case LL_SIM_STAT_NUMAGENTMAIN: - LLViewerStats::getInstance()->mSimMainAgents.addValue(stat_value); + stats.mSimMainAgents.addValue(stat_value); break; case LL_SIM_STAT_NUMAGENTCHILD: - LLViewerStats::getInstance()->mSimChildAgents.addValue(stat_value); + stats.mSimChildAgents.addValue(stat_value); break; case LL_SIM_STAT_NUMSCRIPTSACTIVE: if (gSavedSettings.getBOOL("AscentDisplayTotalScriptJumps")) { - if(abs(stat_value-gSavedSettings.getF32("Ascentnumscripts"))>gSavedSettings.getF32("Ascentnumscriptdiff")) + auto control = gSavedSettings.getControl("Ascentnumscripts"); + const auto& numscripts = control->get().asFloat(); + if(abs(stat_value-numscripts)>gSavedSettings.getF32("Ascentnumscriptdiff")) { - LLChat chat; std::stringstream os; - os << (U32)gSavedSettings.getF32("Ascentnumscripts"); - std::stringstream ns; - ns << (U32)stat_value; - std::stringstream diff; - S32 tdiff = (stat_value-gSavedSettings.getF32("Ascentnumscripts")); - diff << tdiff; - std::string change_type = ""; - if (tdiff > 0) change_type = "+"; - chat.mText = "Total scripts jumped from " + os.str() + " to " + ns.str() + " ("+change_type+diff.str()+")"; - LLFloaterChat::addChat(chat, FALSE,FALSE); + os << (U32)numscripts << " to " << (U32)stat_value << " ("; + const S32 tdiff = stat_value - numscripts; + if (tdiff > 0) os << "+"; + os << tdiff << ')'; + LLChat chat("Total scripts jumped from " + os.str()); + LLFloaterChat::addChat(chat, FALSE, FALSE); } - gSavedSettings.setF32("Ascentnumscripts",stat_value); + control->set(stat_value); } - LLViewerStats::getInstance()->mSimActiveScripts.addValue(stat_value); + stats.mSimActiveScripts.addValue(stat_value); break; case LL_SIM_STAT_SCRIPT_EPS: - LLViewerStats::getInstance()->mSimScriptEPS.addValue(stat_value); + stats.mSimScriptEPS.addValue(stat_value); break; case LL_SIM_STAT_INPPS: - LLViewerStats::getInstance()->mSimInPPS.addValue(stat_value); + stats.mSimInPPS.addValue(stat_value); break; case LL_SIM_STAT_OUTPPS: - LLViewerStats::getInstance()->mSimOutPPS.addValue(stat_value); + stats.mSimOutPPS.addValue(stat_value); break; case LL_SIM_STAT_PENDING_DOWNLOADS: - LLViewerStats::getInstance()->mSimPendingDownloads.addValue(stat_value); + stats.mSimPendingDownloads.addValue(stat_value); break; case LL_SIM_STAT_PENDING_UPLOADS: - LLViewerStats::getInstance()->mSimPendingUploads.addValue(stat_value); + stats.mSimPendingUploads.addValue(stat_value); break; case LL_SIM_STAT_PENDING_LOCAL_UPLOADS: - LLViewerStats::getInstance()->mSimPendingLocalUploads.addValue(stat_value); + stats.mSimPendingLocalUploads.addValue(stat_value); break; case LL_SIM_STAT_TOTAL_UNACKED_BYTES: - LLViewerStats::getInstance()->mSimTotalUnackedBytes.addValue(stat_value / 1024.f); + stats.mSimTotalUnackedBytes.addValue(stat_value / 1024.f); break; case LL_SIM_STAT_PHYSICS_PINNED_TASKS: - LLViewerStats::getInstance()->mPhysicsPinnedTasks.addValue(stat_value); + stats.mPhysicsPinnedTasks.addValue(stat_value); break; case LL_SIM_STAT_PHYSICS_LOD_TASKS: - LLViewerStats::getInstance()->mPhysicsLODTasks.addValue(stat_value); + stats.mPhysicsLODTasks.addValue(stat_value); break; case LL_SIM_STAT_SIMPHYSICSSTEPMS: - LLViewerStats::getInstance()->mSimSimPhysicsStepMsec.addValue(stat_value); + stats.mSimSimPhysicsStepMsec.addValue(stat_value); break; case LL_SIM_STAT_SIMPHYSICSSHAPEMS: - LLViewerStats::getInstance()->mSimSimPhysicsShapeUpdateMsec.addValue(stat_value); + stats.mSimSimPhysicsShapeUpdateMsec.addValue(stat_value); break; case LL_SIM_STAT_SIMPHYSICSOTHERMS: - LLViewerStats::getInstance()->mSimSimPhysicsOtherMsec.addValue(stat_value); + stats.mSimSimPhysicsOtherMsec.addValue(stat_value); break; case LL_SIM_STAT_SIMPHYSICSMEMORY: - LLViewerStats::getInstance()->mPhysicsMemoryAllocated.addValue(stat_value); + stats.mPhysicsMemoryAllocated.addValue(stat_value); break; case LL_SIM_STAT_SIMSPARETIME: - LLViewerStats::getInstance()->mSimSpareMsec.addValue(stat_value); + stats.mSimSpareMsec.addValue(stat_value); break; case LL_SIM_STAT_SIMSLEEPTIME: - LLViewerStats::getInstance()->mSimSleepMsec.addValue(stat_value); + stats.mSimSleepMsec.addValue(stat_value); break; case LL_SIM_STAT_IOPUMPTIME: - LLViewerStats::getInstance()->mSimPumpIOMsec.addValue(stat_value); + stats.mSimPumpIOMsec.addValue(stat_value); break; case LL_SIM_STAT_PCTSCRIPTSRUN: - LLViewerStats::getInstance()->mSimPctScriptsRun.addValue(stat_value); + stats.mSimPctScriptsRun.addValue(stat_value); break; case LL_SIM_STAT_SIMAISTEPTIMEMS: - LLViewerStats::getInstance()->mSimSimAIStepMsec.addValue(stat_value); + stats.mSimSimAIStepMsec.addValue(stat_value); break; case LL_SIM_STAT_SKIPPEDAISILSTEPS_PS: - LLViewerStats::getInstance()->mSimSimSkippedSilhouetteSteps.addValue(stat_value); + stats.mSimSimSkippedSilhouetteSteps.addValue(stat_value); break; case LL_SIM_STAT_PCTSTEPPEDCHARACTERS: - LLViewerStats::getInstance()->mSimSimPctSteppedCharacters.addValue(stat_value); + stats.mSimSimPctSteppedCharacters.addValue(stat_value); break; default: // Used to be a commented out warning. @@ -5757,28 +4261,6 @@ void process_sim_stats(LLMessageSystem *msg, void **user_data) } } - /* - msg->getF32Fast(_PREHASH_Statistics, _PREHASH_PhysicsTimeDilation, time_dilation); - LLViewerStats::getInstance()->mSimTDStat.addValue(time_dilation); - - // Process information - // { CpuUsage F32 } - // { SimMemTotal F32 } - // { SimMemRSS F32 } - // { ProcessUptime F32 } - F32 cpu_usage; - F32 sim_mem_total; - F32 sim_mem_rss; - F32 process_uptime; - msg->getF32Fast(_PREHASH_Statistics, _PREHASH_CpuUsage, cpu_usage); - msg->getF32Fast(_PREHASH_Statistics, _PREHASH_SimMemTotal, sim_mem_total); - msg->getF32Fast(_PREHASH_Statistics, _PREHASH_SimMemRSS, sim_mem_rss); - msg->getF32Fast(_PREHASH_Statistics, _PREHASH_ProcessUptime, process_uptime); - LLViewerStats::getInstance()->mSimCPUUsageStat.addValue(cpu_usage); - LLViewerStats::getInstance()->mSimMemTotalStat.addValue(sim_mem_total); - LLViewerStats::getInstance()->mSimMemRSSStat.addValue(sim_mem_rss); - */ - // // Various hacks that aren't statistics, but are being handled here. // @@ -5813,8 +4295,7 @@ void process_sim_stats(LLMessageSystem *msg, void **user_data) } - -void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data) +void process_avatar_animation(LLMessageSystem* mesgsys, void** user_data) { LLUUID animation_id; LLUUID uuid; @@ -5822,7 +4303,6 @@ void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data) mesgsys->getUUIDFast(_PREHASH_Sender, _PREHASH_ID, uuid); - //clear animation flags LLVOAvatar* avatarp = gObjectList.findAvatar(uuid); if (!avatarp) @@ -5835,19 +4315,20 @@ void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data) S32 num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_AnimationList); S32 num_source_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_AnimationSourceList); + LL_DEBUGS("Messaging", "Motion") << "Processing " << num_blocks << " Animations" << LL_ENDL; + + //clear animation flags avatarp->mSignaledAnimations.clear(); if (avatarp->isSelf()) { LLUUID object_id; - for( S32 i = 0; i < num_blocks; i++ ) + for (S32 i = 0; i < num_blocks; i++) { mesgsys->getUUIDFast(_PREHASH_AnimationList, _PREHASH_AnimID, animation_id, i); mesgsys->getS32Fast(_PREHASH_AnimationList, _PREHASH_AnimSequenceID, anim_sequence_id, i); - LL_DEBUGS("Messaging") << "Anim sequence ID: " << anim_sequence_id << LL_ENDL; - avatarp->mSignaledAnimations[animation_id] = anim_sequence_id; // *HACK: Disabling flying mode if it has been enabled shortly before the agent @@ -5872,7 +4353,7 @@ void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data) BOOL anim_found = FALSE; LLVOAvatar::AnimSourceIterator anim_it = avatarp->mAnimationSources.find(object_id); - for (;anim_it != avatarp->mAnimationSources.end(); ++anim_it) + for (; anim_it != avatarp->mAnimationSources.end(); ++anim_it) { if (anim_it->second == animation_id) { @@ -5886,12 +4367,20 @@ void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data) avatarp->mAnimationSources.insert(LLVOAvatar::AnimationSourceMap::value_type(object_id, animation_id)); } } + LL_DEBUGS("Messaging", "Motion") << "Anim sequence ID: " << anim_sequence_id + << " Animation id: " << animation_id + << " From block: " << object_id << LL_ENDL; + } + else + { + LL_DEBUGS("Messaging", "Motion") << "Anim sequence ID: " << anim_sequence_id + << " Animation id: " << animation_id << LL_ENDL; } } } else { - for( S32 i = 0; i < num_blocks; i++ ) + for (S32 i = 0; i < num_blocks; i++) { mesgsys->getUUIDFast(_PREHASH_AnimationList, _PREHASH_AnimID, animation_id, i); mesgsys->getS32Fast(_PREHASH_AnimationList, _PREHASH_AnimSequenceID, anim_sequence_id, i); @@ -5936,7 +4425,7 @@ void process_object_animation(LLMessageSystem *mesgsys, void **user_data) return; } - LLVOVolume *volp = dynamic_cast(objp); + LLVOVolume *volp = objp->asVolume(); if (!volp) { LL_DEBUGS("AnimatedObjectsNotify") << "Received animation state for non-volume object " << uuid << LL_ENDL; @@ -5971,7 +4460,7 @@ void process_object_animation(LLMessageSystem *mesgsys, void **user_data) } -void process_avatar_appearance(LLMessageSystem *mesgsys, void **user_data) +void process_avatar_appearance(LLMessageSystem* mesgsys, void** user_data) { LLUUID uuid; mesgsys->getUUIDFast(_PREHASH_Sender, _PREHASH_ID, uuid); @@ -5979,7 +4468,7 @@ void process_avatar_appearance(LLMessageSystem *mesgsys, void **user_data) LLVOAvatar* avatarp = gObjectList.findAvatar(uuid); if (avatarp) { - avatarp->processAvatarAppearance( mesgsys ); + avatarp->processAvatarAppearance(mesgsys); } else { @@ -5987,15 +4476,19 @@ void process_avatar_appearance(LLMessageSystem *mesgsys, void **user_data) } } -void process_camera_constraint(LLMessageSystem *mesgsys, void **user_data) +void process_camera_constraint(LLMessageSystem* mesgsys, void** user_data) { + static LLCachedControl disableSimConst(gSavedSettings, "AlchemyDisableSimCamConstraint"); + if (disableSimConst) + return; + LLVector4 cameraCollidePlane; mesgsys->getVector4Fast(_PREHASH_CameraCollidePlane, _PREHASH_Plane, cameraCollidePlane); gAgentCamera.setCameraCollidePlane(cameraCollidePlane); } -void near_sit_object(BOOL success, void *data) +void near_sit_object(BOOL success, void* data) { if (success) { @@ -6008,7 +4501,7 @@ void near_sit_object(BOOL success, void *data) } } -void process_avatar_sit_response(LLMessageSystem *mesgsys, void **user_data) +void process_avatar_sit_response(LLMessageSystem* mesgsys, void** user_data) { LLVector3 sitPosition; LLQuaternion sitRotation; @@ -6047,7 +4540,7 @@ void process_avatar_sit_response(LLMessageSystem *mesgsys, void **user_data) } else { - gAgent.startAutoPilotGlobal(gAgent.getPosGlobalFromAgent(sit_spot), "Sit", &sitRotation, near_sit_object, NULL, 0.5f); + gAgent.startAutoPilotGlobal(gAgent.getPosGlobalFromAgent(sit_spot), "Sit", &sitRotation, near_sit_object, nullptr, 0.5f); } } else @@ -6056,7 +4549,7 @@ void process_avatar_sit_response(LLMessageSystem *mesgsys, void **user_data) } } -void process_clear_follow_cam_properties(LLMessageSystem *mesgsys, void **user_data) +void process_clear_follow_cam_properties(LLMessageSystem* mesgsys, void** user_data) { LLUUID source_id; @@ -6065,7 +4558,7 @@ void process_clear_follow_cam_properties(LLMessageSystem *mesgsys, void **user_d LLFollowCamMgr::removeFollowCamParams(source_id); } -void process_set_follow_cam_properties(LLMessageSystem *mesgsys, void **user_data) +void process_set_follow_cam_properties(LLMessageSystem* mesgsys, void** user_data) { S32 type; F32 value; @@ -6091,7 +4584,7 @@ void process_set_follow_cam_properties(LLMessageSystem *mesgsys, void **user_dat { mesgsys->getS32("CameraProperty", "Type", type, block_index); mesgsys->getF32("CameraProperty", "Value", value, block_index); - switch(type) + switch (type) { case FOLLOWCAM_PITCH: LLFollowCamMgr::setPitch(source_id, value); @@ -6135,27 +4628,27 @@ void process_set_follow_cam_properties(LLMessageSystem *mesgsys, void **user_dat break; case FOLLOWCAM_POSITION_X: settingPosition = true; - position.mV[ 0 ] = value; + position.mV[0] = value; break; case FOLLOWCAM_POSITION_Y: settingPosition = true; - position.mV[ 1 ] = value; + position.mV[1] = value; break; case FOLLOWCAM_POSITION_Z: settingPosition = true; - position.mV[ 2 ] = value; + position.mV[2] = value; break; case FOLLOWCAM_FOCUS_X: settingFocus = true; - focus.mV[ 0 ] = value; + focus.mV[0] = value; break; case FOLLOWCAM_FOCUS_Y: settingFocus = true; - focus.mV[ 1 ] = value; + focus.mV[1] = value; break; case FOLLOWCAM_FOCUS_Z: settingFocus = true; - focus.mV[ 2 ] = value; + focus.mV[2] = value; break; case FOLLOWCAM_POSITION_LOCKED: LLFollowCamMgr::setPositionLocked(source_id, value != 0.f); @@ -6169,24 +4662,25 @@ void process_set_follow_cam_properties(LLMessageSystem *mesgsys, void **user_dat } } - if ( settingPosition ) + if (settingPosition) { LLFollowCamMgr::setPosition(source_id, position); } - if ( settingFocus ) + if (settingFocus) { LLFollowCamMgr::setFocus(source_id, focus); } - if ( settingFocusOffset ) + if (settingFocusOffset) { LLFollowCamMgr::setFocusOffset(source_id, focus_offset); } } + //end Ventrella // Culled from newsim lltask.cpp -void process_name_value(LLMessageSystem *mesgsys, void **user_data) +void process_name_value(LLMessageSystem* mesgsys, void** user_data) { std::string temp_str; LLUUID id; @@ -6212,7 +4706,7 @@ void process_name_value(LLMessageSystem *mesgsys, void **user_data) } } -void process_remove_name_value(LLMessageSystem *mesgsys, void **user_data) +void process_remove_name_value(LLMessageSystem* mesgsys, void** user_data) { std::string temp_str; LLUUID id; @@ -6238,7 +4732,7 @@ void process_remove_name_value(LLMessageSystem *mesgsys, void **user_data) } } -void process_kick_user(LLMessageSystem *msg, void** /*user_data*/) +void process_kick_user(LLMessageSystem* msg, void** /*user_data*/) { std::string message; @@ -6301,7 +4795,7 @@ void process_time_dilation(LLMessageSystem *msg, void **user_data) */ -void process_money_balance_reply( LLMessageSystem* msg, void** ) +void process_money_balance_reply(LLMessageSystem* msg, void**) { S32 balance = 0; S32 credit = 0; @@ -6358,7 +4852,7 @@ void process_money_balance_reply( LLMessageSystem* msg, void** ) // off the beginning. const U32 MAX_LOOKBACK = 30; const S32 POP_FRONT_SIZE = 12; - if(recent.size() > MAX_LOOKBACK) + if (recent.size() > MAX_LOOKBACK) { LL_DEBUGS("Messaging") << "Removing oldest transaction records" << LL_ENDL; recent.erase(recent.begin(), recent.begin() + POP_FRONT_SIZE); @@ -6420,9 +4914,12 @@ static std::string reason_from_transaction_type(S32 transaction_type, case TRANS_CLASSIFIED_CHARGE: return LLTrans::getString("to publish a classified ad"); + case TRANS_GIFT: + // Simulator returns "Payment" if no custom description has been entered + return (item_desc == "Payment" ? std::string() : item_desc); + // These have no reason to display, but are expected and should not // generate warnings - case TRANS_GIFT: case TRANS_PAY_OBJECT: case TRANS_OBJECT_PAYS: return std::string(); @@ -6434,39 +4931,6 @@ static std::string reason_from_transaction_type(S32 transaction_type, } } -static void money_balance_group_notify(const LLUUID& group_id, - const std::string& name, - bool is_group, - std::string message, - LLStringUtil::format_map_t args, - LLSD payload) -{ - bool no_transaction_clutter = gSavedSettings.getBOOL("LiruNoTransactionClutter"); - std::string notification = no_transaction_clutter ? "Payment" : "SystemMessage"; - args["NAME"] = name; - LLSD msg_args; - msg_args["MESSAGE"] = LLTrans::getString(message,args); - LLNotificationsUtil::add(notification,msg_args,payload); - - if (!no_transaction_clutter) LLFloaterChat::addChat(msg_args["MESSAGE"].asString()); // Alerts won't automatically log to chat. -} - -static void money_balance_avatar_notify(const LLUUID& agent_id, - const LLAvatarName& av_name, - std::string message, - LLStringUtil::format_map_t args, - LLSD payload) -{ - bool no_transaction_clutter = gSavedSettings.getBOOL("LiruNoTransactionClutter"); - std::string notification = no_transaction_clutter ? "Payment" : "SystemMessage"; - args["NAME"] = av_name.getNSName(); - LLSD msg_args; - msg_args["MESSAGE"] = LLTrans::getString(message,args); - LLNotificationsUtil::add(notification,msg_args,payload); - - if (!no_transaction_clutter) LLFloaterChat::addChat(msg_args["MESSAGE"].asString()); // Alerts won't automatically log to chat. -} - static void process_money_balance_reply_extended(LLMessageSystem* msg) { // Added in server 1.40 and viewer 2.1, support for localization @@ -6516,6 +4980,7 @@ static void process_money_balance_reply_extended(LLMessageSystem* msg) LLSD payload; bool you_paid_someone = (source_id == gAgentID); + std::string gift_suffix = (transaction_type == TRANS_GIFT ? "_gift" : ""); if (you_paid_someone) { is_name_group = is_dest_group; @@ -6524,8 +4989,8 @@ static void process_money_balance_reply_extended(LLMessageSystem* msg) { if (dest_id.notNull()) { - message = success ? "you_paid_ldollars" : - "you_paid_failure_ldollars"; + message = success ? "you_paid_ldollars" + gift_suffix : + "you_paid_failure_ldollars" + gift_suffix; } else { @@ -6556,7 +5021,7 @@ static void process_money_balance_reply_extended(LLMessageSystem* msg) name_id = source_id; if (!reason.empty()) { - message = "paid_you_ldollars"; + message = "paid_you_ldollars" + gift_suffix; } else { @@ -6565,25 +5030,23 @@ static void process_money_balance_reply_extended(LLMessageSystem* msg) // make notification loggable payload["from_id"] = source_id; + + void script_msg_api(const std::string& msg); if (!is_source_group) script_msg_api(source_id.asString() + ", 7"); } // Despite using SLURLs, wait until the name is available before // showing the notification, otherwise the UI layout is strange and // the user sees a "Loading..." message - if (is_name_group) - { - gCacheName->getGroup(name_id, - boost::bind(&money_balance_group_notify, - _1, _2, _3, message, - args, payload)); - } - else { - LLAvatarNameCache::get(name_id, - boost::bind(&money_balance_avatar_notify, - _1, _2, message, - args, payload)); - } + // Singu Note: Wat? SLURLs resolve over time, not the end of the world. + bool no_transaction_clutter = gSavedSettings.getBOOL("LiruNoTransactionClutter"); + std::string notification = no_transaction_clutter ? "Payment" : "SystemMessage"; + args["NAME"] = is_name_group ? LLGroupActions::getSLURL(name_id) : LLAvatarActions::getSLURL(name_id); + LLSD msg_args; + msg_args["MESSAGE"] = LLTrans::getString(message,args); + LLNotificationsUtil::add(notification,msg_args,payload); + + if (!no_transaction_clutter) LLFloaterChat::addChat(msg_args["MESSAGE"].asString()); // Alerts won't automatically log to chat. } bool handle_prompt_for_maturity_level_change_callback(const LLSD& notification, const LLSD& response) @@ -6623,108 +5086,33 @@ bool handle_prompt_for_maturity_level_change_and_reteleport_callback(const LLSD& // some of the server notifications need special handling. This is where we do that. bool handle_special_notification(std::string notificationID, LLSD& llsdBlock) { - U8 regionAccess = static_cast(llsdBlock["_region_access"].asInteger()); - std::string regionMaturity = LLViewerRegion::accessToString(regionAccess); - LLStringUtil::toLower(regionMaturity); - llsdBlock["REGIONMATURITY"] = regionMaturity; bool returnValue = false; - LLNotificationPtr maturityLevelNotification; - std::string notifySuffix = "_Notify"; - if (regionAccess == SIM_ACCESS_MATURE) + if (llsdBlock.has("_region_access")) { - if (gAgent.isTeen()) - { - gAgent.clearTeleportRequest(); - maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_AdultsOnlyContent", llsdBlock); - returnValue = true; - - notifySuffix = "_NotifyAdultsOnly"; - } - else if (gAgent.prefersPG()) - { - maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_Change", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); - returnValue = true; - } - else if (LLStringUtil::compareStrings(notificationID, "RegionEntryAccessBlocked") == 0) - { - maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_PreferencesOutOfSync", llsdBlock, llsdBlock); - returnValue = true; - } - } - else if (regionAccess == SIM_ACCESS_ADULT) - { - if (!gAgent.isAdult()) - { - gAgent.clearTeleportRequest(); - maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_AdultsOnlyContent", llsdBlock); - returnValue = true; - - notifySuffix = "_NotifyAdultsOnly"; - } - else if (gAgent.prefersPG() || gAgent.prefersMature()) - { - maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_Change", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); - returnValue = true; - } - else if (LLStringUtil::compareStrings(notificationID, "RegionEntryAccessBlocked") == 0) - { - maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_PreferencesOutOfSync", llsdBlock, llsdBlock); - returnValue = true; - } - } - - if ((maturityLevelNotification == NULL) || maturityLevelNotification->isIgnored()) - { - // Given a simple notification if no maturityLevelNotification is set or it is ignore - LLNotificationsUtil::add(notificationID + notifySuffix, llsdBlock); - } - - return returnValue; -} - -// some of the server notifications need special handling. This is where we do that. -bool handle_teleport_access_blocked(LLSD& llsdBlock, const std::string & notificationID, const std::string & defaultMessage) -{ - U8 regionAccess = static_cast(llsdBlock["_region_access"].asInteger()); - std::string regionMaturity = LLViewerRegion::accessToString(regionAccess); - LLStringUtil::toLower(regionMaturity); - llsdBlock["REGIONMATURITY"] = regionMaturity; - - bool returnValue = false; - LLNotificationPtr tp_failure_notification; - std::string notifySuffix; - - if (notificationID == std::string("TeleportEntryAccessBlocked")) - { - notifySuffix = "_Notify"; + U8 regionAccess = static_cast(llsdBlock["_region_access"].asInteger()); + std::string regionMaturity = LLViewerRegion::accessToString(regionAccess); + LLStringUtil::toLower(regionMaturity); + llsdBlock["REGIONMATURITY"] = regionMaturity; + LLNotificationPtr maturityLevelNotification; + std::string notifySuffix = "_Notify"; if (regionAccess == SIM_ACCESS_MATURE) { if (gAgent.isTeen()) { gAgent.clearTeleportRequest(); - tp_failure_notification = LLNotificationsUtil::add(notificationID+"_AdultsOnlyContent", llsdBlock); + maturityLevelNotification = LLNotificationsUtil::add(notificationID + "_AdultsOnlyContent", llsdBlock); returnValue = true; notifySuffix = "_NotifyAdultsOnly"; } else if (gAgent.prefersPG()) { - if (gAgent.hasRestartableFailedTeleportRequest()) - { - tp_failure_notification = LLNotificationsUtil::add(notificationID+"_ChangeAndReTeleport", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_and_reteleport_callback); - returnValue = true; - } - else - { - gAgent.clearTeleportRequest(); - tp_failure_notification = LLNotificationsUtil::add(notificationID+"_Change", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); - returnValue = true; - } + maturityLevelNotification = LLNotificationsUtil::add(notificationID + "_Change", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); + returnValue = true; } - else + else if (LLStringUtil::compareStrings(notificationID, "RegionEntryAccessBlocked") == 0) { - gAgent.clearTeleportRequest(); - tp_failure_notification = LLNotificationsUtil::add(notificationID+"_PreferencesOutOfSync", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); + maturityLevelNotification = LLNotificationsUtil::add(notificationID + "_PreferencesOutOfSync", llsdBlock, llsdBlock); returnValue = true; } } @@ -6733,54 +5121,157 @@ bool handle_teleport_access_blocked(LLSD& llsdBlock, const std::string & notific if (!gAgent.isAdult()) { gAgent.clearTeleportRequest(); - tp_failure_notification = LLNotificationsUtil::add(notificationID+"_AdultsOnlyContent", llsdBlock); + maturityLevelNotification = LLNotificationsUtil::add(notificationID + "_AdultsOnlyContent", llsdBlock); returnValue = true; notifySuffix = "_NotifyAdultsOnly"; } else if (gAgent.prefersPG() || gAgent.prefersMature()) { - if (gAgent.hasRestartableFailedTeleportRequest()) + maturityLevelNotification = LLNotificationsUtil::add(notificationID + "_Change", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); + returnValue = true; + } + else if (LLStringUtil::compareStrings(notificationID, "RegionEntryAccessBlocked") == 0) + { + maturityLevelNotification = LLNotificationsUtil::add(notificationID + "_PreferencesOutOfSync", llsdBlock, llsdBlock); + returnValue = true; + } + } + + if ((maturityLevelNotification == nullptr) || maturityLevelNotification->isIgnored()) + { + // Given a simple notification if no maturityLevelNotification is set or it is ignore + LLNotificationsUtil::add(notificationID + notifySuffix, llsdBlock); + } + } + + return returnValue; +} + +bool handle_trusted_experiences_notification(const LLSD& llsdBlock) +{ + if (llsdBlock.has("trusted_experiences")) + { + std::ostringstream str; + const LLSD& experiences = llsdBlock["trusted_experiences"]; + LLSD::array_const_iterator it = experiences.beginArray(); + for (/**/; it != experiences.endArray(); ++it) + { + str << LLSLURL("experience", it->asUUID(), "profile").getSLURLString() << "\n"; + } + std::string str_list = str.str(); + if (!str_list.empty()) + { + LLNotificationsUtil::add("TrustedExperiencesAvailable", LLSD::emptyMap().with("EXPERIENCE_LIST", (LLSD)str_list)); + return true; + } + } + return false; +} + +// some of the server notifications need special handling. This is where we do that. +bool handle_teleport_access_blocked(LLSD& llsdBlock, const std::string& notificationID, const std::string& defaultMessage) +{ + bool returnValue = false; + if (llsdBlock.has("_region_access")) + { + U8 regionAccess = static_cast(llsdBlock["_region_access"].asInteger()); + std::string regionMaturity = LLViewerRegion::accessToString(regionAccess); + LLStringUtil::toLower(regionMaturity); + llsdBlock["REGIONMATURITY"] = regionMaturity; + + LLNotificationPtr tp_failure_notification; + std::string notifySuffix; + + if (notificationID == std::string("TeleportEntryAccessBlocked")) + { + notifySuffix = "_Notify"; + if (regionAccess == SIM_ACCESS_MATURE) + { + if (gAgent.isTeen()) { - tp_failure_notification = LLNotificationsUtil::add(notificationID+"_ChangeAndReTeleport", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_and_reteleport_callback); + gAgent.clearTeleportRequest(); + tp_failure_notification = LLNotificationsUtil::add(notificationID + "_AdultsOnlyContent", llsdBlock); returnValue = true; + + notifySuffix = "_NotifyAdultsOnly"; + } + else if (gAgent.prefersPG()) + { + if (gAgent.hasRestartableFailedTeleportRequest()) + { + tp_failure_notification = LLNotificationsUtil::add(notificationID + "_ChangeAndReTeleport", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_and_reteleport_callback); + returnValue = true; + } + else + { + gAgent.clearTeleportRequest(); + tp_failure_notification = LLNotificationsUtil::add(notificationID + "_Change", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); + returnValue = true; + } } else { gAgent.clearTeleportRequest(); - tp_failure_notification = LLNotificationsUtil::add(notificationID+"_Change", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); + tp_failure_notification = LLNotificationsUtil::add(notificationID + "_PreferencesOutOfSync", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); returnValue = true; } } + else if (regionAccess == SIM_ACCESS_ADULT) + { + if (!gAgent.isAdult()) + { + gAgent.clearTeleportRequest(); + tp_failure_notification = LLNotificationsUtil::add(notificationID + "_AdultsOnlyContent", llsdBlock); + returnValue = true; + + notifySuffix = "_NotifyAdultsOnly"; + } + else if (gAgent.prefersPG() || gAgent.prefersMature()) + { + if (gAgent.hasRestartableFailedTeleportRequest()) + { + tp_failure_notification = LLNotificationsUtil::add(notificationID + "_ChangeAndReTeleport", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_and_reteleport_callback); + returnValue = true; + } + else + { + gAgent.clearTeleportRequest(); + tp_failure_notification = LLNotificationsUtil::add(notificationID + "_Change", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); + returnValue = true; + } + } + else + { + gAgent.clearTeleportRequest(); + tp_failure_notification = LLNotificationsUtil::add(notificationID + "_PreferencesOutOfSync", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); + returnValue = true; + } + } + } // End of special handling for "TeleportEntryAccessBlocked" + else + { // Normal case, no message munging + gAgent.clearTeleportRequest(); + if (LLNotificationTemplates::getInstance()->templateExists(notificationID)) + { + tp_failure_notification = LLNotificationsUtil::add(notificationID, llsdBlock, llsdBlock); + } else { - gAgent.clearTeleportRequest(); - tp_failure_notification = LLNotificationsUtil::add(notificationID+"_PreferencesOutOfSync", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); - returnValue = true; + llsdBlock["MESSAGE"] = defaultMessage; + tp_failure_notification = LLNotificationsUtil::add("GenericAlertOK", llsdBlock); } + returnValue = true; } - } // End of special handling for "TeleportEntryAccessBlocked" - else - { // Normal case, no message munging - gAgent.clearTeleportRequest(); - if (LLNotificationTemplates::getInstance()->templateExists(notificationID)) + + if ((tp_failure_notification == nullptr) || tp_failure_notification->isIgnored()) { - tp_failure_notification = LLNotificationsUtil::add(notificationID, llsdBlock, llsdBlock); + // Given a simple notification if no tp_failure_notification is set or it is ignore + LLNotificationsUtil::add(notificationID + notifySuffix, llsdBlock); } - else - { - llsdBlock["MESSAGE"] = defaultMessage; - tp_failure_notification = LLNotificationsUtil::add("GenericAlertOK", llsdBlock); - } - returnValue = true; - } - - if ((tp_failure_notification == NULL) || tp_failure_notification->isIgnored()) - { - // Given a simple notification if no tp_failure_notification is set or it is ignore - LLNotificationsUtil::add(notificationID + notifySuffix, llsdBlock); } + handle_trusted_experiences_notification(llsdBlock); return returnValue; } @@ -6795,19 +5286,10 @@ void home_position_set() void update_region_restart(const LLSD& llsdBlock) { - U32 seconds; - if (llsdBlock.has("MINUTES")) - { - seconds = 60U * static_cast(llsdBlock["MINUTES"].asInteger()); - } - else - { - seconds = static_cast(llsdBlock["SECONDS"].asInteger()); - } - - LLFloaterRegionRestarting* restarting_floater = LLFloaterRegionRestarting::findInstance(); - - if (restarting_floater) + const U32 seconds = llsdBlock.has("MINUTES") + ? (60U * static_cast(llsdBlock["MINUTES"].asInteger())) + : static_cast(llsdBlock["SECONDS"].asInteger()); + if (LLFloaterRegionRestarting* restarting_floater = LLFloaterRegionRestarting::findInstance()) { restarting_floater->updateTime(seconds); /*if (!restarting_floater->isMinimized()) @@ -6839,7 +5321,6 @@ bool attempt_standard_notification(LLMessageSystem* msgsystem) std::string llsdRaw; LLSD llsdBlock; - msgsystem->getStringFast(_PREHASH_AlertInfo, _PREHASH_Message, notificationID); msgsystem->getStringFast(_PREHASH_AlertInfo, _PREHASH_ExtraParams, llsdRaw); if (llsdRaw.length()) { @@ -6850,6 +5331,9 @@ bool attempt_standard_notification(LLMessageSystem* msgsystem) } } + + handle_trusted_experiences_notification(llsdBlock); + if ( (notificationID == "RegionEntryAccessBlocked") || (notificationID == "LandClaimAccessBlocked") || @@ -6886,6 +5370,11 @@ bool attempt_standard_notification(LLMessageSystem* msgsystem) return true; } } + else if (notificationID == "expired_region_handoff" || notificationID == "invalid_region_handoff") // borked region handoff + { + gAgent.setIsCrossingRegion(false); // Attachments getting lost on TP + } + else // HACK -- handle callbacks for specific alerts. if (notificationID == "HomePositionSet") { @@ -6895,14 +5384,14 @@ bool attempt_standard_notification(LLMessageSystem* msgsystem) { LLViewerStats::getInstance()->incStat(LLViewerStats::ST_KILLED_COUNT); } - else if (notificationID == "RegionRestartMinutes" || notificationID == "RegionRestartSeconds") + else if (notificationID == "RegionRestartMinutes" || + notificationID == "RegionRestartSeconds") { update_region_restart(llsdBlock); LLUI::sAudioCallback(LLUUID(gSavedSettings.getString("UISndRestart"))); return true; // Floater is enough. } else - // Special Marketplace update notification if (notificationID == "SLM_UPDATE_FOLDER") { @@ -6913,12 +5402,31 @@ bool attempt_standard_notification(LLMessageSystem* msgsystem) LLMarketplaceData::instance().deleteListing(llsdBlock["listing_id"].asInteger()); return true; } - else - { - // In general, no message will be displayed, all we want is to get the listing updated in the marketplace floater - // If getListing() fails though, the message of the alert will be shown by the caller of attempt_standard_notification() - return LLMarketplaceData::instance().getListing(llsdBlock["listing_id"].asInteger()); - } + // In general, no message will be displayed, all we want is to get the listing updated in the marketplace floater + // If getListing() fails though, the message of the alert will be shown by the caller of attempt_standard_notification() + return LLMarketplaceData::instance().getListing(llsdBlock["listing_id"].asInteger()); + } + + // Error Notification can come with and without reason + if (notificationID == "JoinGroupError") + { + if (llsdBlock.has("reason")) + { + LLNotificationsUtil::add("JoinGroupErrorReason", llsdBlock); + return true; + } + if (llsdBlock.has("group_id")) + { + LLGroupData agent_gdatap; + bool is_member = gAgent.getGroupData(llsdBlock["group_id"].asUUID(), agent_gdatap); + if (is_member) + { + LLSD args; + args["reason"] = LLTrans::getString("AlreadyInGroup"); + LLNotificationsUtil::add("JoinGroupErrorReason", args); + return true; + } + } } LLNotificationsUtil::add(notificationID, llsdBlock); @@ -6928,19 +5436,37 @@ bool attempt_standard_notification(LLMessageSystem* msgsystem) } +static void process_special_alert_messages(const std::string& message) +{ + // Do special handling for alert messages. This is a legacy hack, and any actual displayed + // text should be altered in the notifications.xml files. + if (message == "You died and have been teleported to your home location") + { + LLViewerStats::getInstance()->incStat(LLViewerStats::ST_KILLED_COUNT); + } + else if (message == "Home position set.") + { + home_position_set(); + } +} + + void process_agent_alert_message(LLMessageSystem* msgsystem, void** user_data) { // make sure the cursor is back to the usual default since the // alert is probably due to some kind of error. gViewerWindow->getWindow()->resetBusyCount(); + std::string message; + msgsystem->getStringFast(_PREHASH_AlertData, _PREHASH_Message, message); + + process_special_alert_messages(message); + if (!attempt_standard_notification(msgsystem)) { BOOL modal = FALSE; msgsystem->getBOOL("AlertData", "Modal", modal); - std::string buffer; - msgsystem->getStringFast(_PREHASH_AlertData, _PREHASH_Message, buffer); - process_alert_core(buffer, modal); + process_alert_core(message, modal); } } @@ -6949,25 +5475,27 @@ void process_agent_alert_message(LLMessageSystem* msgsystem, void** user_data) // handled by this routine, there is no "Modal" parameter on the message, and // there's no API to tell if a message has the given parameter or not. // So we can't handle the messages with the same handler. -void process_alert_message(LLMessageSystem *msgsystem, void **user_data) +void process_alert_message(LLMessageSystem* msgsystem, void** user_data) { // make sure the cursor is back to the usual default since the // alert is probably due to some kind of error. gViewerWindow->getWindow()->resetBusyCount(); + std::string message; + msgsystem->getStringFast(_PREHASH_AlertData, _PREHASH_Message, message); + process_special_alert_messages(message); + if (!attempt_standard_notification(msgsystem)) { BOOL modal = FALSE; - std::string buffer; - msgsystem->getStringFast(_PREHASH_AlertData, _PREHASH_Message, buffer); - process_alert_core(buffer, modal); + process_alert_core(message, modal); } } -bool handle_not_age_verified_alert(const std::string &pAlertName) +bool handle_not_age_verified_alert(const std::string& pAlertName) { LLNotificationPtr notification = LLNotificationsUtil::add(pAlertName); - if ((notification == NULL) || notification->isIgnored()) + if ((notification == nullptr) || notification->isIgnored()) { LLNotificationsUtil::add(pAlertName + "_Notify"); } @@ -6975,12 +5503,11 @@ bool handle_not_age_verified_alert(const std::string &pAlertName) return true; } -bool handle_special_alerts(const std::string &pAlertName) +bool handle_special_alerts(const std::string& pAlertName) { bool isHandled = false; if (LLStringUtil::compareStrings(pAlertName, "NotAgeVerified") == 0) { - isHandled = handle_not_age_verified_alert(pAlertName); } @@ -6989,16 +5516,6 @@ bool handle_special_alerts(const std::string &pAlertName) void process_alert_core(const std::string& message, BOOL modal) { - // HACK -- handle callbacks for specific alerts. It also is localized in notifications.xml - if ( message == "You died and have been teleported to your home location") - { - LLViewerStats::getInstance()->incStat(LLViewerStats::ST_KILLED_COUNT); - } - else if( message == "Home position set." ) - { - home_position_set(); - } - const std::string ALERT_PREFIX("ALERT: "); const std::string NOTIFY_PREFIX("NOTIFY: "); if (message.find(ALERT_PREFIX) == 0) @@ -7023,6 +5540,7 @@ void process_alert_core(const std::string& message, BOOL modal) // System message is important, show in upper-right box not tip std::string text(message.substr(1)); LLSD args; + if (text.substr(0,17) == "RESTART_X_MINUTES") { S32 mins = 0; @@ -7043,8 +5561,9 @@ void process_alert_core(const std::string& message, BOOL modal) } else { - // *NOTE: If the text from the server ever changes this line will need to be adjusted. - if (text.substr(0, 25) == "Region restart cancelled.") + // *NOTE: If the text from the server ever changes this line will need to be adjusted. + std::string restart_cancelled = "Region restart cancelled."; + if (text.substr(0, restart_cancelled.length()) == restart_cancelled) { LLFloaterRegionRestarting::hideInstance(); } @@ -7110,17 +5629,17 @@ void process_alert_core(const std::string& message, BOOL modal) mean_collision_list_t gMeanCollisionList; time_t gLastDisplayedTime = 0; -void handle_show_mean_events(void *) +void handle_show_mean_events(void*) { if (gNoRender) { return; } - LLFloaterBump::show(NULL); + LLFloaterBump::show(nullptr); } -void mean_name_callback(const LLUUID &id, const std::string& full_name, bool is_group) +void mean_name_callback(const LLUUID& id, const LLAvatarName& av_name) { if (gNoRender) { @@ -7131,18 +5650,16 @@ void mean_name_callback(const LLUUID &id, const std::string& full_name, bool is_ if (gMeanCollisionList.size() > max_collision_list_size) { mean_collision_list_t::iterator iter = gMeanCollisionList.begin(); - for (U32 i=0; imPerp == id) { - mcd->mFullName = full_name; + mcd->mFullName = av_name.getUserName(); } } } @@ -7172,7 +5689,7 @@ void chat_mean_collision(const LLUUID& id, const LLAvatarName& avname, const EMe LLFloaterChat::addChat(chat); } -void process_mean_collision_alert_message(LLMessageSystem *msgsystem, void **user_data) +void process_mean_collision_alert_message(LLMessageSystem* msgsystem, void** user_data) { if (gAgent.inPrelude()) { @@ -7206,10 +5723,8 @@ void process_mean_collision_alert_message(LLMessageSystem *msgsystem, void **use BOOL b_found = FALSE; - for (mean_collision_list_t::iterator iter = gMeanCollisionList.begin(); - iter != gMeanCollisionList.end(); ++iter) + for (auto mcd : gMeanCollisionList) { - LLMeanCollisionData *mcd = *iter; if ((mcd->mPerp == perp) && (mcd->mType == type)) { mcd->mTime = time; @@ -7221,14 +5736,14 @@ void process_mean_collision_alert_message(LLMessageSystem *msgsystem, void **use if (!b_found) { - LLMeanCollisionData *mcd = new LLMeanCollisionData(gAgentID, perp, time, type, mag); + LLMeanCollisionData* mcd = new LLMeanCollisionData(gAgentID, perp, time, type, mag); gMeanCollisionList.push_front(mcd); - gCacheName->get(perp, false, boost::bind(&mean_name_callback, _1, _2, _3)); + LLAvatarNameCache::get(perp, boost::bind(&mean_name_callback, _1, _2)); } } } -void process_frozen_message(LLMessageSystem *msgsystem, void **user_data) +void process_frozen_message(LLMessageSystem* msgsystem, void** user_data) { // make sure the cursor is back to the usual default since the // alert is probably due to some kind of error. @@ -7247,7 +5762,7 @@ void process_frozen_message(LLMessageSystem *msgsystem, void **user_data) } // do some extra stuff once we get our economy data -void process_economy_data(LLMessageSystem *msg, void** /*user_data*/) +void process_economy_data(LLMessageSystem* msg, void** /*user_data*/) { LLGlobalEconomy::processEconomyData(msg, LLGlobalEconomy::Singleton::getInstance()); @@ -7267,8 +5782,9 @@ void process_economy_data(LLMessageSystem *msg, void** /*user_data*/) void notify_cautioned_script_question(const LLSD& notification, const LLSD& response, S32 orig_questions, BOOL granted) { // NaCl - Antispam Registry - LLUUID task_id = notification["payload"]["task_id"].asUUID(); - if(NACLAntiSpamRegistry::checkQueue((U32)NACLAntiSpamRegistry::QUEUE_SCRIPT_DIALOG,task_id)) return; + if (auto antispam = NACLAntiSpamRegistry::getIfExists()) + if (antispam->checkQueue(NACLAntiSpamRegistry::QUEUE_SCRIPT_DIALOG, notification["payload"]["task_id"].asUUID(), LFIDBearer::OBJECT)) + return; // NaCl End // only continue if at least some permissions were requested if (orig_questions) @@ -7371,10 +5887,22 @@ void notify_cautioned_script_question(const LLSD& notification, const LLSD& resp } } +void script_question_mute(const LLUUID& item_id, const std::string& object_name); + +void experiencePermissionBlock(LLUUID experience, LLSD result) +{ + LLSD permission; + LLSD data; + permission["permission"] = "Block"; + data[experience.asString()] = permission; + data["experience"] = experience; + LLEventPumps::instance().obtain("experience_permission").post(data); +} + bool script_question_cb(const LLSD& notification, const LLSD& response) { S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - LLMessageSystem *msg = gMessageSystem; + LLMessageSystem* msg = gMessageSystem; S32 orig = notification["payload"]["questions"].asInteger(); S32 new_questions = orig; @@ -7388,6 +5916,12 @@ bool script_question_cb(const LLSD& notification, const LLSD& response) return false; } + LLUUID experience; + if (notification["payload"].has("experience")) + { + experience = notification["payload"]["experience"].asUUID(); + } + // check whether permissions were granted or denied BOOL allowed = TRUE; // the "yes/accept" button is the first button in the template, making it button 0 @@ -7396,7 +5930,17 @@ bool script_question_cb(const LLSD& notification, const LLSD& response) { new_questions = 0; allowed = FALSE; - } + } + else if (experience.notNull()) + { + LLSD permission; + LLSD data; + permission["permission"] = "Allow"; + + data[experience.asString()] = permission; + data["experience"] = experience; + LLEventPumps::instance().obtain("experience_permission").post(data); + } LLUUID task_id = notification["payload"]["task_id"].asUUID(); LLUUID item_id = notification["payload"]["item_id"].asUUID(); @@ -7429,38 +5973,74 @@ bool script_question_cb(const LLSD& notification, const LLSD& response) } // [/RLVa:KB] - if ( response["Mute"] ) // mute + if (response["Mute"]) // mute { - LLMuteList::getInstance()->add(LLMute(item_id, notification["payload"]["object_name"].asString(), LLMute::OBJECT)); - - // purge the message queue of any previously queued requests from the same source. DEV-4879 - class OfferMatcher : public LLNotifyBoxView::Matcher - { - public: - OfferMatcher(const LLUUID& to_block) : blocked_id(to_block) {} - bool matches(const LLNotificationPtr notification) const - { - if (notification->getName() == "ScriptQuestionCaution" - || notification->getName() == "ScriptQuestion") - { - return (notification->getPayload()["item_id"].asUUID() == blocked_id); - } - return false; - } - private: - const LLUUID& blocked_id; - }; - // should do this via the channel - gNotifyBoxView->purgeMessagesMatching(OfferMatcher(item_id)); + script_question_mute(task_id, notification["payload"]["object_name"].asString()); } + if (response["BlockExperience"]) + { + if (experience.notNull()) + { + LLViewerRegion* region = gAgent.getRegion(); + if (!region) + return false; + LLExperienceCache::instance().setExperiencePermission(experience, std::string("Block"), boost::bind(&experiencePermissionBlock, experience, _1)); + } + } return false; } +void script_question_mute(const LLUUID& task_id, const std::string& object_name) +{ + LLMuteList::getInstance()->add(LLMute(task_id, object_name, LLMute::OBJECT)); + + // purge the message queue of any previously queued requests from the same source. DEV-4879 + class OfferMatcher final : public LLNotifyBoxView::Matcher + { + public: + OfferMatcher(const LLUUID& to_block) : blocked_id(to_block) + { + } + + bool matches(const LLNotificationPtr notification) const override + { + if (notification->getName() == "ScriptQuestionCaution" + || notification->getName() == "ScriptQuestion") + { + return (notification->getPayload()["task_id"].asUUID() == blocked_id); + } + return false; + } + + private: + const LLUUID& blocked_id; + }; + + // should do this via the channel + gNotifyBoxView->purgeMessagesMatching(OfferMatcher(task_id)); +} + static LLNotificationFunctorRegistration script_question_cb_reg_1("ScriptQuestion", script_question_cb); static LLNotificationFunctorRegistration script_question_cb_reg_2("ScriptQuestionCaution", script_question_cb); +static LLNotificationFunctorRegistration script_question_cb_reg_3("ScriptQuestionExperience", script_question_cb); -void process_script_question(LLMessageSystem *msg, void **user_data) +void process_script_experience_details(const LLSD& experience_details, LLSD args, LLSD payload) +{ + if (experience_details[LLExperienceCache::PROPERTIES].asInteger() & LLExperienceCache::PROPERTY_GRID) + { + args["GRID_WIDE"] = LLTrans::getString("Grid-Scope"); + } + else + { + args["GRID_WIDE"] = LLTrans::getString("Land-Scope"); + } + args["EXPERIENCE"] = LLSLURL("experience", experience_details[LLExperienceCache::EXPERIENCE_ID].asUUID(), "profile").getSLURLString(); + + LLNotificationsUtil::add("ScriptQuestionExperience", args, payload); +} + +void process_script_question(LLMessageSystem* msg, void** user_data) { // *TODO: Translate owner name -> [FIRST] [LAST] @@ -7471,22 +6051,31 @@ void process_script_question(LLMessageSystem *msg, void **user_data) S32 questions; std::string object_name; std::string owner_name; + LLUUID experienceid; // taskid -> object key of object requesting permissions - msg->getUUIDFast(_PREHASH_Data, _PREHASH_TaskID, taskid ); + msg->getUUIDFast(_PREHASH_Data, _PREHASH_TaskID, taskid); // itemid -> script asset key of script requesting permissions - msg->getUUIDFast(_PREHASH_Data, _PREHASH_ItemID, itemid ); + msg->getUUIDFast(_PREHASH_Data, _PREHASH_ItemID, itemid); // NaCl - Antispam Registry - if((taskid.isNull() - && NACLAntiSpamRegistry::checkQueue((U32)NACLAntiSpamRegistry::QUEUE_SCRIPT_DIALOG,itemid)) - || NACLAntiSpamRegistry::checkQueue((U32)NACLAntiSpamRegistry::QUEUE_SCRIPT_DIALOG,taskid)) - return; + if (auto antispam = NACLAntiSpamRegistry::getIfExists()) + { + if ((taskid.isNull() + && antispam->checkQueue(NACLAntiSpamRegistry::QUEUE_SCRIPT_DIALOG, itemid, LFIDBearer::NONE)) + || antispam->checkQueue(NACLAntiSpamRegistry::QUEUE_SCRIPT_DIALOG, taskid, LFIDBearer::OBJECT)) + return; + } // NaCl End msg->getStringFast(_PREHASH_Data, _PREHASH_ObjectName, object_name); msg->getStringFast(_PREHASH_Data, _PREHASH_ObjectOwner, owner_name); - msg->getS32Fast(_PREHASH_Data, _PREHASH_Questions, questions ); + msg->getS32Fast(_PREHASH_Data, _PREHASH_Questions, questions); + + if (msg->has(_PREHASH_Experience)) + { + msg->getUUIDFast(_PREHASH_Experience, _PREHASH_ExperienceID, experienceid); + } // Special case. If the objects are owned by this agent, throttle per-object instead // of per-owner. It's common for residents to reset a ton of scripts that re-request @@ -7494,11 +6083,11 @@ void process_script_question(LLMessageSystem *msg, void **user_data) // so we'll reuse the same namespace for both throttle types. std::string throttle_name = owner_name; std::string self_name; - LLAgentUI::buildFullname( self_name ); + LLAgentUI::buildFullname(self_name); // NaCl - Antispam if (is_spam_filtered(IM_COUNT, false, owner_name == self_name)) return; // NaCl End - if( owner_name == self_name ) + if (owner_name == self_name) { throttle_name = taskid.getString(); } @@ -7508,7 +6097,7 @@ void process_script_question(LLMessageSystem *msg, void **user_data) // throttle excessive requests from any specific user's scripts typedef LLKeyThrottle LLStringThrottle; - static LLStringThrottle question_throttle( LLREQUEST_PERMISSION_THROTTLE_LIMIT, LLREQUEST_PERMISSION_THROTTLE_INTERVAL ); + static LLStringThrottle question_throttle(LLREQUEST_PERMISSION_THROTTLE_LIMIT, LLREQUEST_PERMISSION_THROTTLE_INTERVAL); switch (question_throttle.noteAction(throttle_name)) { @@ -7529,86 +6118,111 @@ void process_script_question(LLMessageSystem *msg, void **user_data) std::string script_question; if (questions) { - BOOL caution = FALSE; + bool caution = false; S32 count = 0; LLSD args; - args["OBJECTNAME"] = object_name; - args["NAME"] = LLCacheName::cleanFullName(owner_name); - - BOOL has_not_only_debit = questions ^ LSCRIPTRunTimePermissionBits[SCRIPT_PERMISSION_DEBIT]; + const std::string get_obj_slurl(const LLUUID& id, const std::string& name); + const std::string get_obj_owner_slurl(const LLUUID& obj_id, const std::string& name, bool* group_ownedp = nullptr); + args["OBJECTNAME"] = get_obj_slurl(taskid, object_name); + args["NAME"] = get_obj_owner_slurl(taskid, owner_name); + S32 known_questions = 0; + bool has_not_only_debit = questions ^ LSCRIPTRunTimePermissionBits[SCRIPT_PERMISSION_DEBIT]; // check the received permission flags against each permission for (S32 i = 0; i < SCRIPT_PERMISSION_EOF; i++) { if (questions & LSCRIPTRunTimePermissionBits[i]) { count++; - + known_questions |= LSCRIPTRunTimePermissionBits[i]; // check whether permission question should cause special caution dialog caution |= (SCRIPT_QUESTION_IS_CAUTION[i]); if (("ScriptTakeMoney" == SCRIPT_QUESTIONS[i]) && has_not_only_debit) continue; + if (SCRIPT_QUESTIONS[i] == "JoinAnExperience") + { // Some experience only permissions do not have an explicit permission bit. Add them here. + script_question += " " + LLTrans::getString("ForceSitAvatar") + "\n"; + } + script_question += " " + LLTrans::getString(SCRIPT_QUESTIONS[i]) + "\n"; } } + args["QUESTIONS"] = script_question; - LLSD payload; - payload["task_id"] = taskid; - payload["item_id"] = itemid; - payload["sender"] = sender.getIPandPort(); - payload["questions"] = questions; - payload["object_name"] = object_name; - payload["owner_name"] = owner_name; + if (known_questions != questions) + { + // This is in addition to the normal dialog. + // Viewer got a request for not supported/implemented permission + LL_WARNS("Messaging") << "Object \"" << object_name << "\" requested " << script_question + << " permission. Permission is unknown and can't be granted. Item id: " << itemid + << " taskid:" << taskid << LL_ENDL; + } + + if (known_questions) + { + LLSD payload; + payload["task_id"] = taskid; + payload["item_id"] = itemid; + payload["sender"] = sender.getIPandPort(); + payload["questions"] = known_questions; + payload["object_name"] = object_name; + payload["owner_name"] = owner_name; + + // check whether cautions are even enabled or not + const char* notification = "ScriptQuestion"; // [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7) - if (rlv_handler_t::isEnabled()) - { - RlvUtil::filterScriptQuestions(questions, payload); - - if ( (questions) && (gRlvHandler.hasBehaviour(RLV_BHVR_ACCEPTPERMISSION)) ) + if (rlv_handler_t::isEnabled()) { - const LLViewerObject* pObj = gObjectList.findObject(taskid); - if (pObj) + RlvUtil::filterScriptQuestions(questions, payload); + + if ( (questions) && (gRlvHandler.hasBehaviour(RLV_BHVR_ACCEPTPERMISSION)) ) { - if ( (pObj->permYouOwner()) && (!pObj->isAttachment()) ) + const LLViewerObject* pObj = gObjectList.findObject(taskid); + if (pObj) { - questions &= ~(LSCRIPTRunTimePermissionBits[SCRIPT_PERMISSION_TAKE_CONTROLS] | - LSCRIPTRunTimePermissionBits[SCRIPT_PERMISSION_ATTACH]); + if ( (pObj->permYouOwner()) && (!pObj->isAttachment()) ) + { + questions &= ~(LSCRIPTRunTimePermissionBits[SCRIPT_PERMISSION_TAKE_CONTROLS] | + LSCRIPTRunTimePermissionBits[SCRIPT_PERMISSION_ATTACH]); + } + else + { + questions &= ~(LSCRIPTRunTimePermissionBits[SCRIPT_PERMISSION_TAKE_CONTROLS]); + } + payload["rlv_notify"] = !pObj->permYouOwner(); } - else - { - questions &= ~(LSCRIPTRunTimePermissionBits[SCRIPT_PERMISSION_TAKE_CONTROLS]); - } - payload["rlv_notify"] = !pObj->permYouOwner(); } } - } - if ( (!caution) && (!questions) ) - { - LLNotifications::instance().forceResponse( - LLNotification::Params("ScriptQuestion").substitutions(args).payload(payload), 0/*YES*/); - } - else if (gSavedSettings.getBOOL("PermissionsCautionEnabled")) + if ( (!caution) && (!questions) ) + { + LLNotifications::instance().forceResponse( + LLNotification::Params(notification).substitutions(args).payload(payload), 0/*YES*/); + return; + } // [/RLVa:KB] - // check whether cautions are even enabled or not - //if (gSavedSettings.getBOOL("PermissionsCautionEnabled")) - { - // display the caution permissions prompt - LLNotificationsUtil::add(caution ? "ScriptQuestionCaution" : "ScriptQuestion", args, payload); - } - else - { - // fall back to default behavior if cautions are entirely disabled - LLNotificationsUtil::add("ScriptQuestion", args, payload); + if (caution && gSavedSettings.getBOOL("PermissionsCautionEnabled")) + { + args["FOOTERTEXT"] = (count > 1) ? LLTrans::getString("AdditionalPermissionsRequestHeader") + '\n' + script_question : LLStringUtil::null; + notification = "ScriptQuestionCaution"; + } + else if (experienceid.notNull()) + { + payload["experience"] = experienceid; + LLExperienceCache::instance().get(experienceid, boost::bind(process_script_experience_details, _1, args, payload)); + return; + } + + LLNotificationsUtil::add(notification, args, payload); } } } -void process_derez_container(LLMessageSystem *msg, void**) +void process_derez_container(LLMessageSystem* msg, void**) { LL_WARNS("Messaging") << "call to deprecated process_derez_container" << LL_ENDL; } @@ -7619,12 +6233,12 @@ void container_inventory_arrived(LLViewerObject* object, void* data) { LL_DEBUGS("Messaging") << "container_inventory_arrived()" << LL_ENDL; - if( gAgentCamera.cameraMouselook() ) + if (gAgentCamera.cameraMouselook()) { gAgentCamera.changeCameraToDefault(); } - LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(); + LLInventoryPanel* active_panel = LLInventoryPanel::getActiveInventoryPanel(); if (inventory->size() > 2) { @@ -7636,7 +6250,7 @@ void container_inventory_arrived(LLViewerObject* object, LLInventoryObject::object_list_t::const_iterator it = inventory->begin(); LLInventoryObject::object_list_t::const_iterator end = inventory->end(); - for ( ; it != end; ++it) + for (; it != end; ++it) { if ((*it)->getType() != LLAssetType::AT_CATEGORY) { @@ -7662,7 +6276,7 @@ void container_inventory_arrived(LLViewerObject* object, } } gInventory.notifyObservers(); - if(active_panel) + if (active_panel) { active_panel->setSelection(cat_id, TAKE_FOCUS_NO); } @@ -7698,7 +6312,7 @@ void container_inventory_arrived(LLViewerObject* object, new_item->updateServer(TRUE); gInventory.updateItem(new_item); gInventory.notifyObservers(); - if(active_panel) + if (active_panel) { active_panel->setSelection(item_id, TAKE_FOCUS_NO); } @@ -7706,7 +6320,7 @@ void container_inventory_arrived(LLViewerObject* object, // we've got the inventory, now delete this object if this was a take BOOL delete_object = (BOOL)(intptr_t)data; - LLViewerRegion *region = gAgent.getRegion(); + LLViewerRegion* region = gAgent.getRegion(); if (delete_object && region) { gMessageSystem->newMessageFast(_PREHASH_ObjectDelete); @@ -7733,7 +6347,7 @@ std::string formatted_time(const time_t& the_time) } -void process_teleport_failed(LLMessageSystem *msg, void**) +void process_teleport_failed(LLMessageSystem* msg, void**) { std::string message_id; // Tag from server, like "RegionEntryAccessBlocked" std::string big_reason; // Actual message to display @@ -7748,20 +6362,17 @@ void process_teleport_failed(LLMessageSystem *msg, void**) // Get the message ID msg->getStringFast(_PREHASH_AlertInfo, _PREHASH_Message, message_id); big_reason = LLAgent::sTeleportErrorMessages[message_id]; - if ( big_reason.size() > 0 ) - { // Substitute verbose reason from the local map - args["REASON"] = big_reason; - } - else - { // Nothing found in the map - use what the server returned in the original message block + if (big_reason.empty()) + { + // Nothing found in the map - use what the server returned in the original message block msg->getStringFast(_PREHASH_Info, _PREHASH_Reason, big_reason); - args["REASON"] = big_reason; } + args["REASON"] = big_reason; LLSD llsd_block; std::string llsd_raw; msg->getStringFast(_PREHASH_AlertInfo, _PREHASH_ExtraParams, llsd_raw); - if (llsd_raw.length()) + if (!llsd_raw.empty()) { std::istringstream llsd_data(llsd_raw); if (!LLSDSerialize::deserialize(llsd_block, llsd_data, llsd_raw.length())) @@ -7770,12 +6381,23 @@ void process_teleport_failed(LLMessageSystem *msg, void**) } else { + if(llsd_block.has("REGION_NAME")) + { + std::string region_name = llsd_block["REGION_NAME"].asString(); + if(!region_name.empty()) + { + LLStringUtil::format_map_t name_args; + name_args["[REGION_NAME]"] = region_name; + LLStringUtil::format(big_reason, name_args); + args["REASON"] = big_reason; + } + } // change notification name in this special case if (handle_teleport_access_blocked(llsd_block, message_id, args["REASON"])) { - if( gAgent.getTeleportState() != LLAgent::TELEPORT_NONE ) + if (gAgent.getTeleportState() != LLAgent::TELEPORT_NONE) { - gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); + gAgent.setTeleportState(LLAgent::TELEPORT_NONE); } return; } @@ -7788,7 +6410,7 @@ void process_teleport_failed(LLMessageSystem *msg, void**) msg->getStringFast(_PREHASH_Info, _PREHASH_Reason, message_id); big_reason = LLAgent::sTeleportErrorMessages[message_id]; - if ( big_reason.size() > 0 ) + if (!big_reason.empty()) { // Substitute verbose reason from the local map args["REASON"] = big_reason; } @@ -7800,13 +6422,13 @@ void process_teleport_failed(LLMessageSystem *msg, void**) LLNotificationsUtil::add("CouldNotTeleportReason", args); - if( gAgent.getTeleportState() != LLAgent::TELEPORT_NONE ) + if (gAgent.getTeleportState() != LLAgent::TELEPORT_NONE) { - gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); + gAgent.setTeleportState(LLAgent::TELEPORT_NONE); } } -void process_teleport_local(LLMessageSystem *msg,void**) +void process_teleport_local(LLMessageSystem* msg, void**) { LLUUID agent_id; msg->getUUIDFast(_PREHASH_Info, _PREHASH_AgentID, agent_id); @@ -7824,9 +6446,9 @@ void process_teleport_local(LLMessageSystem *msg,void**) msg->getVector3Fast(_PREHASH_Info, _PREHASH_LookAt, look_at); msg->getU32Fast(_PREHASH_Info, _PREHASH_TeleportFlags, teleport_flags); - if( gAgent.getTeleportState() != LLAgent::TELEPORT_NONE ) + if (gAgent.getTeleportState() != LLAgent::TELEPORT_NONE) { - if( gAgent.getTeleportState() == LLAgent::TELEPORT_LOCAL ) + if (gAgent.getTeleportState() == LLAgent::TELEPORT_LOCAL) { // To prevent TeleportStart messages re-activating the progress screen right // after tp, keep the teleport state and let progress screen clear it after a short delay @@ -7836,7 +6458,7 @@ void process_teleport_local(LLMessageSystem *msg,void**) } else { - gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); + gAgent.setTeleportState(LLAgent::TELEPORT_NONE); } } @@ -7853,7 +6475,7 @@ void process_teleport_local(LLMessageSystem *msg,void**) gAgent.setPositionAgent(pos); gAgentCamera.slamLookAt(look_at); - if ( !(gAgent.getTeleportKeepsLookAt() && LLViewerJoystick::getInstance()->getOverrideCamera()) && gSavedSettings.getBOOL("OptionRotateCamAfterLocalTP")) + if (!(gAgent.getTeleportKeepsLookAt() && LLViewerJoystick::getInstance()->getOverrideCamera()) && gSavedSettings.getBOOL("OptionRotateCamAfterLocalTP")) { gAgentCamera.resetView(TRUE, TRUE); } @@ -7922,7 +6544,7 @@ void send_group_notice(const LLUUID& group_id, } else { - bucket_to_send = (U8*) EMPTY_BINARY_BUCKET; + bucket_to_send = (U8*)EMPTY_BINARY_BUCKET; } @@ -7996,7 +6618,7 @@ void send_lures(const LLSD& notification, const LLSD& response) target_name = RlvStrings::getAnonym(target_name); else // [/RLVa:KB] - LLAvatarNameCache::getNSName(target_id, target_name); + target_name = LLAvatarActions::getSLURL(target_id); args["TO_NAME"] = target_name; LLSD payload; @@ -8021,7 +6643,7 @@ void send_lures(const LLSD& notification, const LLSD& response) bool handle_lure_callback(const LLSD& notification, const LLSD& response) { static const unsigned OFFER_RECIPIENT_LIMIT = 250; - if(notification["payload"]["ids"].size() > OFFER_RECIPIENT_LIMIT) + if (notification["payload"]["ids"].size() > OFFER_RECIPIENT_LIMIT) { // More than OFFER_RECIPIENT_LIMIT targets will overload the message // producing an llerror. @@ -8034,7 +6656,7 @@ bool handle_lure_callback(const LLSD& notification, const LLSD& response) S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if(0 == option) + if (0 == option) { send_lures(notification, response); } @@ -8058,28 +6680,34 @@ void handle_lure(const uuid_vec_t& ids) // [RLVa:KB] - Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.0.0a edit_args["REGION"] = (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) ? gAgent.getRegion()->getName() : RlvStrings::getString(RLV_STRING_HIDDEN); // [/RLVa:KB] - //edit_args["REGION"] = gAgent.getRegion()->getName(); +// edit_args["REGION"] = gAgent.getRegion()->getName(); LLSD payload; - for (uuid_vec_t::const_iterator it = ids.begin(); - it != ids.end(); - ++it) +// [RLVa:KB] - Checked: RLVa-2.0.1 + bool fRlvShouldHideNames = false; + for (const LLUUID& idAgent : ids) { -// [RLVa:KB] - Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.0.0a // Only allow offering teleports if everyone is a @tplure exception or able to map this avie under @showloc=n if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) { - const LLRelationship* pBuddyInfo = LLAvatarTracker::instance().getBuddyInfo(*it); - if ( (!gRlvHandler.isException(RLV_BHVR_TPLURE, *it, RLV_CHECK_PERMISSIVE)) && + const LLRelationship* pBuddyInfo = LLAvatarTracker::instance().getBuddyInfo(idAgent); + if ( (!gRlvHandler.isException(RLV_BHVR_TPLURE, idAgent, RLV_CHECK_PERMISSIVE)) && ((!pBuddyInfo) || (!pBuddyInfo->isOnline()) || (!pBuddyInfo->isRightGrantedTo(LLRelationship::GRANT_MAP_LOCATION))) ) { return; } } - payload["rlv_shownames"] = !RlvActions::canShowName(RlvActions::SNC_TELEPORTOFFER); -// [/RLVa:KB] - payload["ids"].append(*it); + fRlvShouldHideNames |= !RlvActions::canShowName(RlvActions::SNC_TELEPORTOFFER); + payload["ids"].append(idAgent); } + payload["rlv_shownames"] = fRlvShouldHideNames; +// [/RLVa:KB] +// for (std::vector::const_iterator it = ids.begin(); +// it != ids.end(); +// ++it) +// { +// payload["ids"].append(*it); +// } if (gAgent.isGodlike()) { LLNotificationsUtil::add("OfferTeleportFromGod", edit_args, payload, handle_lure_callback); @@ -8093,7 +6721,7 @@ void handle_lure(const uuid_vec_t& ids) bool teleport_request_callback(const LLSD& notification, const LLSD& response) { LLUUID from_id = notification["payload"]["from_id"].asUUID(); - if(from_id.isNull()) + if (from_id.isNull()) { LL_WARNS() << "from_id is NULL" << LL_ENDL; return false; @@ -8102,7 +6730,7 @@ bool teleport_request_callback(const LLSD& notification, const LLSD& response) std::string from_name; gCacheName->getFullName(from_id, from_name); - if(LLMuteList::getInstance()->isMuted(from_id) && !LLMuteList::getInstance()->isLinden(from_name)) + if (LLMuteList::getInstance()->isMuted(from_id) && !LLMuteList::getInstance()->isLinden(from_name)) { return false; } @@ -8117,7 +6745,7 @@ bool teleport_request_callback(const LLSD& notification, const LLSD& response) option = LLNotificationsUtil::getSelectedOption(notification, response); } - switch(option) + switch (option) { // Yes case 0: @@ -8132,14 +6760,6 @@ bool teleport_request_callback(const LLSD& notification, const LLSD& response) } break; - // Profile - case 3: - { - LLAvatarActions::showProfile(from_id); - LLNotificationsUtil::add(notification["name"], notification["substitutions"], notification["payload"]); //Respawn! - } - break; - // No case 1: default: @@ -8206,12 +6826,12 @@ void send_places_query(const LLUUID& query_id, gAgent.sendReliableMessage(); } - +// Deprecated in favor of cap "UserInfo" void process_user_info_reply(LLMessageSystem* msg, void**) { LLUUID agent_id; msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); - if(agent_id != gAgent.getID()) + if (agent_id != gAgent.getID()) { LL_WARNS("Messaging") << "process_user_info_reply - " << "wrong agent id." << LL_ENDL; @@ -8222,8 +6842,9 @@ void process_user_info_reply(LLMessageSystem* msg, void**) std::string email; msg->getStringFast(_PREHASH_UserData, _PREHASH_EMail, email); std::string dir_visibility; - msg->getString( "UserData", "DirectoryVisibility", dir_visibility); + msg->getString("UserData", "DirectoryVisibility", dir_visibility); + // For Message based user info information the is_verified is assumed to be false. LLFloaterPreference::updateUserInfo(dir_visibility, im_via_email, email); LLFloaterPostcard::updateUserInfo(email); } @@ -8270,6 +6891,7 @@ bool callback_script_dialog(const LLSD& notification, const LLSD& response) return false; } + static LLNotificationFunctorRegistration callback_script_dialog_reg_1("ScriptDialog", callback_script_dialog); static LLNotificationFunctorRegistration callback_script_dialog_reg_2("ScriptDialogGroup", callback_script_dialog); @@ -8282,10 +6904,15 @@ void process_script_dialog(LLMessageSystem* msg, void**) msg->getUUID("Data", "ObjectID", object_id); // NaCl - Antispam Registry - if(NACLAntiSpamRegistry::checkQueue((U32)NACLAntiSpamRegistry::QUEUE_SCRIPT_DIALOG,object_id)) + auto antispam = NACLAntiSpamRegistry::getIfExists(); + if (antispam && antispam->checkQueue(NACLAntiSpamRegistry::QUEUE_SCRIPT_DIALOG, object_id, LFIDBearer::OBJECT)) return; // NaCl End + std::string first_name; + msg->getString("Data", "FirstName", first_name); + bool const is_group = first_name.empty(); + // For compability with OS grids first check for presence of extended packet before fetching data. LLUUID owner_id; if (gMessageSystem->getNumberOfBlocks("OwnerData") > 0) @@ -8293,13 +6920,16 @@ void process_script_dialog(LLMessageSystem* msg, void**) msg->getUUID("OwnerData", "OwnerID", owner_id); // NaCl - Antispam Registry - if(NACLAntiSpamRegistry::checkQueue((U32)NACLAntiSpamRegistry::QUEUE_SCRIPT_DIALOG,owner_id)) + if (antispam && antispam->checkQueue(NACLAntiSpamRegistry::QUEUE_SCRIPT_DIALOG, owner_id, is_group ? LFIDBearer::GROUP : LFIDBearer::AVATAR)) return; // NaCl End } + bool has_owner = owner_id.notNull(); + // NaCl - Antispam - if (owner_id.isNull() ? is_spam_filtered(IM_COUNT, LLAvatarActions::isFriend(object_id), object_id == gAgentID) : is_spam_filtered(IM_COUNT, LLAvatarActions::isFriend(owner_id), owner_id == gAgentID)) return; + if (!has_owner ? is_spam_filtered(IM_COUNT, LLAvatarActions::isFriend(object_id), object_id == gAgentID) + : is_spam_filtered(IM_COUNT, LLAvatarActions::isFriend(owner_id), !is_group && owner_id == gAgentID)) return; // NaCl End if (LLMuteList::getInstance()->isMuted(object_id) || LLMuteList::getInstance()->isMuted(owner_id)) @@ -8307,13 +6937,15 @@ void process_script_dialog(LLMessageSystem* msg, void**) return; } + auto chatter = gObjectList.findObject(object_id); + // Singu Note: Try to get Owner whenever possible + if (chatter && has_owner) chatter->mOwnerID = owner_id; + std::string message; - std::string first_name; std::string last_name; std::string object_name; S32 chat_channel; - msg->getString("Data", "FirstName", first_name); msg->getString("Data", "LastName", last_name); msg->getString("Data", "ObjectName", object_name); msg->getString("Data", "Message", message); @@ -8361,21 +6993,50 @@ void process_script_dialog(LLMessageSystem* msg, void**) } } + LLSD query_string; + query_string["owner"] = owner_id; + if (rlv_handler_t::isEnabled() && (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES) || gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS)) && !is_group && RlvUtil::isNearbyAgent(owner_id)) + { + query_string["rlv_shownames"] = true; + } + + if (const auto& obj = chatter ? chatter : gObjectList.findObject(owner_id)) // Fallback on the owner, if the chatter isn't present + { + auto& slurl = query_string["slurl"]; + const auto& region = obj->getRegion(); + if (rlv_handler_t::isEnabled() && gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC) && LLWorld::instance().isRegionListed(region)) + slurl = RlvStrings::getString(RLV_STRING_HIDDEN_REGION); + else + { + const auto& pos = obj->getPositionRegion(); + S32 x = ll_round((F32)fmod((F64)pos.mV[VX], (F64)REGION_WIDTH_METERS)); + S32 y = ll_round((F32)fmod((F64)pos.mV[VY], (F64)REGION_WIDTH_METERS)); + S32 z = ll_round((F32)pos.mV[VZ]); + std::ostringstream location; + location << region->getName() << '/' << x << '/' << y << '/' << z; + if (chatter != obj) location << "?owner_not_object"; + slurl = location.str(); + } + } + query_string["name"] = object_name; + query_string["groupowned"] = is_group; + object_name = LLSLURL("objectim", object_id, LLURI::mapToQueryString(query_string)).getSLURLString(); + LLSD args; args["TITLE"] = object_name; args["MESSAGE"] = message; args["CHANNEL"] = chat_channel; LLNotificationPtr notification; - bool const is_group = first_name.empty(); char const* name = (is_group && !is_text_box) ? "GROUPNAME" : "NAME"; - args[name] = is_group ? last_name : LLCacheName::buildFullName(first_name, last_name); + args[name] = has_owner ? is_group ? LLGroupActions::getSLURL(owner_id) : LLAvatarActions::getSLURL(owner_id) : + is_group ? last_name : LLCacheName::buildFullName(first_name, last_name); if (is_text_box) { args["DEFAULT"] = default_text; payload["textbox"] = "true"; LLNotificationsUtil::add("ScriptTextBoxDialog", args, payload, callback_script_dialog); } - else if (!first_name.empty()) + else if (!is_group) { notification = LLNotifications::instance().add( LLNotification::Params("ScriptDialog").substitutions(args).payload(payload).form_elements(form.asLLSD())); @@ -8403,8 +7064,8 @@ bool callback_load_url(const LLSD& notification, const LLSD& response) return false; } -static LLNotificationFunctorRegistration callback_load_url_reg("LoadWebPage", callback_load_url); +static LLNotificationFunctorRegistration callback_load_url_reg("LoadWebPage", callback_load_url); // We've got the name of the person who owns the object hurling the url. // Display confirmation dialog. @@ -8435,7 +7096,7 @@ void callback_load_url_name(const LLUUID& id, const std::string& full_name, bool } LLSD args; args["URL"] = load_url_info["url"].asString(); - args["MESSAGE"] = load_url_info["message"].asString();; + args["MESSAGE"] = load_url_info["message"].asString(); args["OBJECTNAME"] = load_url_info["object_name"].asString(); args["NAME"] = owner_name; @@ -8458,21 +7119,25 @@ void process_load_url(LLMessageSystem* msg, void**) char url[256]; /* Flawfinder: ignore */ msg->getString("Data", "ObjectName", 256, object_name); - msg->getUUID( "Data", "ObjectID", object_id); - msg->getUUID( "Data", "OwnerID", owner_id); + msg->getUUID("Data", "ObjectID", object_id); + msg->getUUID("Data", "OwnerID", owner_id); // NaCl - Antispam - if (owner_id.isNull() ? is_spam_filtered(IM_COUNT, LLAvatarActions::isFriend(object_id), object_id == gAgentID) : is_spam_filtered(IM_COUNT, LLAvatarActions::isFriend(owner_id), owner_id == gAgentID)) return; + if (owner_id.isNull() ? is_spam_filtered(IM_COUNT, LLAvatarActions::isFriend(object_id), object_id == gAgentID) + : is_spam_filtered(IM_COUNT, LLAvatarActions::isFriend(owner_id), owner_id == gAgentID)) return; // NaCl End + msg->getBOOL("Data", "OwnerIsGroup", owner_is_group); // NaCl - Antispam Registry - if((owner_id.isNull() - && NACLAntiSpamRegistry::checkQueue((U32)NACLAntiSpamRegistry::QUEUE_SCRIPT_DIALOG,object_id)) - || NACLAntiSpamRegistry::checkQueue((U32)NACLAntiSpamRegistry::QUEUE_SCRIPT_DIALOG,owner_id)) - return; + if (auto antispam = NACLAntiSpamRegistry::getIfExists()) + { + if ((owner_id.isNull() + && antispam->checkQueue(NACLAntiSpamRegistry::QUEUE_SCRIPT_DIALOG, object_id, LFIDBearer::OBJECT)) + || antispam->checkQueue(NACLAntiSpamRegistry::QUEUE_SCRIPT_DIALOG, owner_id, owner_is_group ? LFIDBearer::GROUP : LFIDBearer::AVATAR)) + return; + } // NaCl End - msg->getBOOL( "Data", "OwnerIsGroup", owner_is_group); msg->getString("Data", "Message", 256, message); msg->getString("Data", "URL", 256, url); @@ -8490,7 +7155,7 @@ void process_load_url(LLMessageSystem* msg, void**) if (LLMuteList::getInstance()->isMuted(object_id, object_name) || LLMuteList::getInstance()->isMuted(owner_id)) { - LL_INFOS("Messaging")<<"Ignoring load_url from muted object/owner."<incStat( LLViewerStats::ST_DOWNLOAD_FAILED ); - if( LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status || + if (LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status || LL_ERR_FILE_EMPTY == status) { covenant_text = "Estate covenant notecard is missing from database."; @@ -8714,9 +7378,9 @@ void process_feature_disabled_message(LLMessageSystem* msg, void**) LLUUID agentID; LLUUID transactionID; std::string messageText; - msg->getStringFast(_PREHASH_FailureInfo,_PREHASH_ErrorMessage, messageText,0); - msg->getUUIDFast(_PREHASH_FailureInfo,_PREHASH_AgentID,agentID); - msg->getUUIDFast(_PREHASH_FailureInfo,_PREHASH_TransactionID,transactionID); + msg->getStringFast(_PREHASH_FailureInfo, _PREHASH_ErrorMessage, messageText, 0); + msg->getUUIDFast(_PREHASH_FailureInfo, _PREHASH_AgentID, agentID); + msg->getUUIDFast(_PREHASH_FailureInfo, _PREHASH_TransactionID, transactionID); LL_WARNS("Messaging") << "Blacklisted Feature Response:" << messageText << LL_ENDL; } diff --git a/indra/newview/llviewermessage.h b/indra/newview/llviewermessage.h index 2abbfbd69..acfb590b0 100644 --- a/indra/newview/llviewermessage.h +++ b/indra/newview/llviewermessage.h @@ -70,6 +70,11 @@ enum InventoryOfferResponse BOOL can_afford_transaction(S32 cost); void give_money(const LLUUID& uuid, LLViewerRegion* region, S32 amount, BOOL is_group = FALSE, S32 trx_type = TRANS_GIFT, const std::string& desc = LLStringUtil::null); +void send_join_group_response(const LLUUID& group_id, + const LLUUID& transaction_id, + bool accept_invite, + S32 fee, + bool use_offline_cap); void process_logout_reply(LLMessageSystem* msg, void**); void process_layer_data(LLMessageSystem *mesgsys, void **user_data); @@ -205,7 +210,6 @@ void process_decline_callingcard(LLMessageSystem* msg, void**); // Message system exception prototypes void invalid_message_callback(LLMessageSystem*, void*, EMessageException); - void process_initiate_download(LLMessageSystem* msg, void**); void start_new_inventory_observer(); void open_inventory_offer(const uuid_vec_t& items, const std::string& from_name); diff --git a/indra/newview/llviewernetwork.h b/indra/newview/llviewernetwork.h index bb15fd323..18a6e0c45 100644 --- a/indra/newview/llviewernetwork.h +++ b/indra/newview/llviewernetwork.h @@ -63,7 +63,7 @@ public: private: //void parseCommandLineURIs(); - bool mNameEditted; // Set if the user edits/sets the First or Last name field. + bool mNameEditted = false; // Set if the user edits/sets the First or Last name field. }; diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 8ba388e6e..8deaa7829 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -1258,6 +1258,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, mesgsys->getUUIDFast(_PREHASH_ObjectData, _PREHASH_Sound, audio_uuid, block_num ); // HACK: Owner id only valid if non-null sound id or particle system mesgsys->getUUIDFast(_PREHASH_ObjectData, _PREHASH_OwnerID, owner_id, block_num ); + if (owner_id.notNull()) mOwnerID = owner_id; // Singu Note: Try to get Owner whenever possible mesgsys->getF32Fast( _PREHASH_ObjectData, _PREHASH_Gain, gain, block_num ); mesgsys->getU8Fast( _PREHASH_ObjectData, _PREHASH_Flags, sound_flags, block_num ); mesgsys->getU8Fast( _PREHASH_ObjectData, _PREHASH_Material, material, block_num ); @@ -1620,7 +1621,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, retval |= checkMediaURL(media_url); // - // Unpack particle system data + // Unpack particle system data (legacy) // if (value & 0x8) { @@ -2188,23 +2189,22 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, mStatic = FALSE; } - // BUG: This code leads to problems during group rotate and any scale operation. - // Small discepencies between the simulator and viewer representations cause the - // selection center to creep, leading to objects moving around the wrong center. - // - // Removing this, however, means that if someone else drags an object you have - // selected, your selection center and dialog boxes will be wrong. It also means - // that higher precision information on selected objects will be ignored. - // - // I believe the group rotation problem is fixed. JNC 1.21.2002 - // +// BUG: This code leads to problems during group rotate and any scale operation. +// Small discepencies between the simulator and viewer representations cause the +// selection center to creep, leading to objects moving around the wrong center. +// +// Removing this, however, means that if someone else drags an object you have +// selected, your selection center and dialog boxes will be wrong. It also means +// that higher precision information on selected objects will be ignored. +// +// I believe the group rotation problem is fixed. JNC 1.21.2002 +// // Additionally, if any child is selected, need to update the dialogs and selection // center. BOOL needs_refresh = mUserSelected; - for (child_list_t::iterator iter = mChildList.begin(); - iter != mChildList.end(); iter++) + for (auto& iter : mChildList) { - LLViewerObject* child = *iter; + LLViewerObject* child = iter; needs_refresh = needs_refresh || child->mUserSelected; } @@ -2952,10 +2952,9 @@ void LLViewerObject::updateControlAvatar() { bool any_rigged_mesh = root->isRiggedMesh(); LLViewerObject::const_child_list_t& child_list = root->getChildren(); - for (LLViewerObject::const_child_list_t::const_iterator iter = child_list.begin(); - iter != child_list.end(); ++iter) + for (const auto& iter : child_list) { - const LLViewerObject* child = *iter; + const LLViewerObject* child = iter; any_rigged_mesh = any_rigged_mesh || child->isRiggedMesh(); } should_have_control_avatar = is_animated_object && any_rigged_mesh; @@ -3093,7 +3092,7 @@ void LLViewerObject::linkControlAvatar() { if (!getControlAvatar() && isRootEdit()) { - LLVOVolume *volp = dynamic_cast(this); + LLVOVolume *volp = asVolume(); if (!volp) { LL_WARNS() << "called with null or non-volume object" << LL_ENDL; @@ -3136,6 +3135,7 @@ void LLViewerObject::unlinkControlAvatar() if (mControlAvatar) { mControlAvatar->markForDeath(); + mControlAvatar->mRootVolp = NULL; mControlAvatar = NULL; } } @@ -3269,7 +3269,7 @@ void LLViewerObject::processTaskInvFile(void** user_data, S32 error_code, LLExtS LLInventoryObject::object_list_t::iterator end = object->mInventory->end(); std::list& pending_lst = object->mPendingInventoryItemsIDs; - for (; it != end && pending_lst.size(); ++it) + for (; it != end && !pending_lst.empty(); ++it) { LLViewerInventoryItem* item = dynamic_cast(it->get()); if(item && item->getType() != LLAssetType::AT_CATEGORY) @@ -3292,7 +3292,7 @@ void LLViewerObject::processTaskInvFile(void** user_data, S32 error_code, LLExtS } else { - // This Occurs When to requests were made, and the first one + // This Occurs When two requests were made, and the first one // has already handled it. LL_DEBUGS() << "Problem loading task inventory. Return code: " << error_code << LL_ENDL; @@ -3412,11 +3412,6 @@ void LLViewerObject::removeInventory(const LLUUID& item_id) msg->sendReliable(mRegionp->getHost()); deleteInventoryItem(item_id); ++mInventorySerialNum; - - // The viewer object should not refresh UI since this is a utility - // function. The UI functionality that called this method should - // refresh the views if necessary. - //gBuildView->refresh(); } bool LLViewerObject::isTextureInInventory(LLViewerInventoryItem* item) @@ -3531,7 +3526,7 @@ void LLViewerObject::getInventoryContents(LLInventoryObject::object_list_t& obje LLInventoryObject* LLViewerObject::getInventoryRoot() { - if (!mInventory || !mInventory->size()) + if (!mInventory || mInventory->empty()) { return NULL; } @@ -3587,8 +3582,8 @@ void LLViewerObject::setPixelAreaAndAngle(LLAgent &agent) return; } - LLVector3 viewer_pos_agent = gAgentCamera.getCameraPositionAgent(); - LLVector3 pos_agent = getRenderPosition(); + const LLVector3& viewer_pos_agent = gAgentCamera.getCameraPositionAgent(); + const LLVector3& pos_agent = getRenderPosition(); F32 dx = viewer_pos_agent.mV[VX] - pos_agent.mV[VX]; F32 dy = viewer_pos_agent.mV[VY] - pos_agent.mV[VY]; @@ -3602,7 +3597,7 @@ void LLViewerObject::setPixelAreaAndAngle(LLAgent &agent) // to try to get a min distance from face, subtract min_scale/2 from the range. // This means we'll load too much detail sometimes, but that's better than not enough // I don't think there's a better way to do this without calculating distance per-poly - F32 range = sqrt(dx*dx + dy*dy + dz*dz) - min_scale/2; + F32 range = sqrt(dx*dx + dy*dy + dz*dz) - min_scale/2.f; LLViewerCamera* camera = LLViewerCamera::getInstance(); if (range < 0.001f || isHUDAttachment()) // range == zero @@ -3781,10 +3776,9 @@ F32 LLViewerObject::getLinksetPhysicsCost() F32 LLViewerObject::recursiveGetEstTrianglesMax() const { F32 est_tris = getEstTrianglesMax(); - for (child_list_t::const_iterator iter = mChildList.begin(); - iter != mChildList.end(); iter++) + for (const auto& iter : mChildList) { - const LLViewerObject* child = *iter; + const LLViewerObject* child = iter; if (!child->isAvatar()) { est_tris += child->recursiveGetEstTrianglesMax(); @@ -3852,10 +3846,9 @@ U32 LLViewerObject::recursiveGetTriangleCount(S32* vcount) const { S32 total_tris = getTriangleCount(vcount); LLViewerObject::const_child_list_t& child_list = getChildren(); - for (LLViewerObject::const_child_list_t::const_iterator iter = child_list.begin(); - iter != child_list.end(); ++iter) + for (const auto& iter : child_list) { - LLViewerObject* childp = *iter; + LLViewerObject* childp = iter; if (childp) { total_tris += childp->getTriangleCount(vcount); @@ -3882,13 +3875,11 @@ F32 LLViewerObject::recursiveGetScaledSurfaceArea() const const LLVector3& scale = volume->getScale(); area += volume->getVolume()->getSurfaceArea() * llmax(llmax(scale.mV[0], scale.mV[1]), scale.mV[2]); } - LLViewerObject::const_child_list_t children = volume->getChildren(); - for (LLViewerObject::const_child_list_t::const_iterator child_iter = children.begin(); - child_iter != children.end(); - ++child_iter) + LLViewerObject::const_child_list_t const& children = volume->getChildren(); + for (const auto& child_iter : children) { - LLViewerObject* child_obj = *child_iter; - LLVOVolume *child = dynamic_cast( child_obj ); + LLViewerObject* child_obj = child_iter; + LLVOVolume *child = child_obj ? child_obj->asVolume() : nullptr; if (child && child->getVolume()) { const LLVector3& scale = child->getScale(); @@ -3899,6 +3890,7 @@ F32 LLViewerObject::recursiveGetScaledSurfaceArea() const } return area; } + void LLViewerObject::updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax) { if(mDrawable.isNull()) @@ -5592,6 +5584,12 @@ LLVOAvatar* LLViewerObject::asAvatar() return NULL; } +// virtual +LLVOVolume* LLViewerObject::asVolume() +{ + return nullptr; +} + // If this object is directly or indirectly parented by an avatar, // return it. Normally getAvatar() is the correct function to call; // it will give the avatar used for skinning. The exception is with diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index fb4b812c6..e95b25c42 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -69,6 +69,7 @@ class LLPrimitive; class LLTextureEntry; class LLVOAvatar; class LLVOInventoryListener; +class LLVOVolume; class LLViewerInventoryItem; class LLViewerObject; class LLViewerObjectMedia; @@ -157,6 +158,7 @@ public: BOOL isParticleSource() const; virtual LLVOAvatar* asAvatar(); + virtual LLVOVolume* asVolume(); LLVOAvatar* getAvatarAncestor(); diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp index 069f65310..e6a87fbd2 100644 --- a/indra/newview/llviewerparcelmgr.cpp +++ b/indra/newview/llviewerparcelmgr.cpp @@ -121,20 +121,18 @@ LLViewerParcelMgr::LLViewerParcelMgr() mHoverRequestResult(0), mHoverWestSouth(), mHoverEastNorth(), + mCollisionRegionHandle(0), + mCollisionUpdateSignal(nullptr), mRenderCollision(FALSE), mRenderSelection(TRUE), mCollisionBanned(0), mCollisionTimer(), -// [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-06-20 (Catznip-3.3.0) - mCollisionRegionHandle(0), - mCollisionUpdateSignal(NULL), -// [/SL:KB] mMediaParcelId(0), - mMediaRegionId(0), - mHighlightSegments(NULL), - mCollisionSegments(NULL), - mAgentParcelOverlay(NULL), - mParcelsPerEdge(0) + mHighlightSegments(nullptr), + mCollisionSegments(nullptr), + mAgentParcelOverlay(nullptr), + mParcelsPerEdge(0), + mMediaRegionId(0) { mCurrentParcel = new LLParcel(); mCurrentParcelSelection = new LLParcelSelection(mCurrentParcel); @@ -144,17 +142,12 @@ LLViewerParcelMgr::LLViewerParcelMgr() mHoverParcel = new LLParcel(); mCollisionParcel = new LLParcel(); -// Aurora Sim mParcelsPerEdge = S32(8192.f / PARCEL_GRID_STEP_METERS); // 8192 is the maximum region size on WhiteCore and solves the audio problem. - //mParcelsPerEdge = S32( REGION_WIDTH_METERS / PARCEL_GRID_STEP_METERS ); -// Aurora Sim mHighlightSegments = new U8[(mParcelsPerEdge+1)*(mParcelsPerEdge+1)]; resetSegments(mHighlightSegments); -// [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-06-20 (Catznip-3.3.0) mCollisionBitmap = new U8[getCollisionBitmapSize()]; memset(mCollisionBitmap, 0, getCollisionBitmapSize()); -// [/SL:KB] mCollisionSegments = new U8[(mParcelsPerEdge+1)*(mParcelsPerEdge+1)]; resetSegments(mCollisionSegments); @@ -175,19 +168,14 @@ LLViewerParcelMgr::LLViewerParcelMgr() mAgentParcelOverlay[i] = 0; } -// Aurora Sim mParcelsPerEdge = S32(REGION_WIDTH_METERS / PARCEL_GRID_STEP_METERS); -// Aurora Sim - mTeleportInProgress = TRUE; // the initial parcel update is treated like teleport } -// Aurora Sim void LLViewerParcelMgr::init(F32 region_size) { mParcelsPerEdge = S32(region_size / PARCEL_GRID_STEP_METERS); } -// Aurora Sim LLViewerParcelMgr::~LLViewerParcelMgr() { @@ -212,10 +200,8 @@ LLViewerParcelMgr::~LLViewerParcelMgr() delete[] mHighlightSegments; mHighlightSegments = NULL; -// [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-06-20 (Catznip-3.3.0) delete[] mCollisionBitmap; mCollisionBitmap = NULL; -// [/SL:KB] delete[] mCollisionSegments; mCollisionSegments = NULL; @@ -239,11 +225,9 @@ void LLViewerParcelMgr::dump() mCurrentParcel->dump(); LL_INFOS() << "banning " << mCurrentParcel->mBanList.size() << LL_ENDL; - access_map_const_iterator cit = mCurrentParcel->mBanList.begin(); - access_map_const_iterator end = mCurrentParcel->mBanList.end(); - for ( ; cit != end; ++cit) + for (const auto& pair : mCurrentParcel->mBanList) { - LL_INFOS() << "ban id " << (*cit).first << LL_ENDL; + LL_INFOS() << "ban id " << pair.first << LL_ENDL; } LL_INFOS() << "Hover parcel:" << LL_ENDL; mHoverParcel->dump(); @@ -252,7 +236,7 @@ void LLViewerParcelMgr::dump() } -LLViewerRegion* LLViewerParcelMgr::getSelectionRegion() +LLViewerRegion* LLViewerParcelMgr::getSelectionRegion() const { return LLWorld::getInstance()->getRegionFromPosGlobal( mWestSouth ); } @@ -472,14 +456,9 @@ LLParcelSelectionHandle LLViewerParcelMgr::selectParcelInRectangle() void LLViewerParcelMgr::selectCollisionParcel() { // BUG: Claim to be in the agent's region -// Aurora Sim - //mWestSouth = gAgent.getRegion()->getOriginGlobal(); - //mEastNorth = mWestSouth; - //mEastNorth += LLVector3d(PARCEL_GRID_STEP_METERS, PARCEL_GRID_STEP_METERS, 0.0); mWestSouth = getSelectionRegion()->getOriginGlobal(); mEastNorth = mWestSouth; mEastNorth += LLVector3d(getSelectionRegion()->getWidth()/REGION_WIDTH_METERS * PARCEL_GRID_STEP_METERS, getSelectionRegion()->getWidth()/REGION_WIDTH_METERS * PARCEL_GRID_STEP_METERS, 0.0); -// Aurora Sim // BUG: must be in the sim you are in LLMessageSystem *msg = gMessageSystem; @@ -891,8 +870,8 @@ LLParcel* LLViewerParcelMgr::getCollisionParcel() const void LLViewerParcelMgr::render() { - static const LLCachedControl RenderParcelSelection("RenderParcelSelection"); - if (mSelected && mRenderSelection && RenderParcelSelection) + static const LLCachedControl render_parcel_selection(gSavedSettings, "RenderParcelSelection"); + if (mSelected && mRenderSelection && render_parcel_selection) { // Rendering is done in agent-coordinates, so need to supply // an appropriate offset to the render code. @@ -912,8 +891,8 @@ void LLViewerParcelMgr::renderParcelCollision() mRenderCollision = FALSE; } - static const LLCachedControl ShowBanLines("ShowBanLines"); - if (mRenderCollision && ShowBanLines) + static const LLCachedControl render_ban_line(gSavedSettings, "ShowBanLines"); + if (mRenderCollision && render_ban_line) { LLViewerRegion* regionp = gAgent.getRegion(); if (regionp) @@ -936,7 +915,7 @@ void LLViewerParcelMgr::sendParcelAccessListRequest(U32 flags) if (!region) return; LLMessageSystem *msg = gMessageSystem; - + if (flags & AL_BAN) { @@ -946,6 +925,14 @@ void LLViewerParcelMgr::sendParcelAccessListRequest(U32 flags) { mCurrentParcel->mAccessList.clear(); } + if (flags & AL_ALLOW_EXPERIENCE) + { + mCurrentParcel->clearExperienceKeysByType(EXPERIENCE_KEY_TYPE_ALLOWED); + } + if (flags & AL_BLOCK_EXPERIENCE) + { + mCurrentParcel->clearExperienceKeysByType(EXPERIENCE_KEY_TYPE_BLOCKED); + } // Only the headers differ msg->newMessageFast(_PREHASH_ParcelAccessListRequest); @@ -1322,10 +1309,13 @@ const std::string& LLViewerParcelMgr::getAgentParcelName() const void LLViewerParcelMgr::sendParcelPropertiesUpdate(LLParcel* parcel, bool use_agent_region) { - if(!parcel) return; + if (!parcel) + return; LLViewerRegion *region = use_agent_region ? gAgent.getRegion() : LLWorld::getInstance()->getRegionFromPosGlobal( mWestSouth ); - if (!region) return; + if (!region) + return; + //LL_INFOS() << "found region: " << region->getName() << LL_ENDL; LLSD body; @@ -1338,6 +1328,7 @@ void LLViewerParcelMgr::sendParcelPropertiesUpdate(LLParcel* parcel, bool use_ag parcel->packMessage(body); LL_INFOS() << "Sending parcel properties update via capability to: " << url << LL_ENDL; + LLHTTPClient::post(url, body, new LLHTTPClient::ResponderIgnore); } else @@ -1365,10 +1356,8 @@ void LLViewerParcelMgr::setHoverParcel(const LLVector3d& pos) static U32 last_west, last_south; // only request parcel info when tooltip is shown - if (!gSavedSettings.getBOOL("ShowLandHoverTip")) - { - return; - } + if (!gSavedSettings.getBOOL("ShowLandHoverTip")) return; + // only request parcel info if position has changed outside of the // last parcel grid step U32 west_parcel_step = (U32) floor( pos.mdV[VX] / PARCEL_GRID_STEP_METERS ); @@ -1390,6 +1379,7 @@ void LLViewerParcelMgr::setHoverParcel(const LLVector3d& pos) return; } + // Send a rectangle around the point. // This means the parcel sent back is at least a rectangle around the point, // which is more efficient for public land. Fewer requests are sent. JC @@ -1437,11 +1427,7 @@ void LLViewerParcelMgr::processParcelOverlay(LLMessageSystem *msg, void **user) return; } -// Aurora Sim - //S32 parcels_per_edge = LLViewerParcelMgr::getInstance()->mParcelsPerEdge; - //S32 expected_size = parcels_per_edge * parcels_per_edge / PARCEL_OVERLAY_CHUNKS; S32 expected_size = 1024; -// Aurora Sim if (packed_overlay_size != expected_size) { LL_WARNS() << "Got parcel overlay size " << packed_overlay_size @@ -1504,13 +1490,11 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use S32 other_clean_time = 0; LLViewerParcelMgr& parcel_mgr = LLViewerParcelMgr::instance(); -// Aurora Sim LLViewerRegion* msg_region = LLWorld::getInstance()->getRegion(msg->getSender()); if(msg_region) parcel_mgr.mParcelsPerEdge = S32(msg_region->getWidth() / PARCEL_GRID_STEP_METERS); else parcel_mgr.mParcelsPerEdge = S32(gAgent.getRegion()->getWidth() / PARCEL_GRID_STEP_METERS); -// Aurora Sim msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_RequestResult, request_result ); msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_SequenceID, sequence_id ); @@ -1624,6 +1608,7 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use if (parcel == parcel_mgr.mAgentParcel) { + // new agent parcel S32 bitmap_size = parcel_mgr.mParcelsPerEdge * parcel_mgr.mParcelsPerEdge / 8; @@ -1636,6 +1621,7 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use // Let interesting parties know about agent parcel change. LLViewerParcelMgr* instance = LLViewerParcelMgr::getInstance(); + // Notify anything that wants to know when the agent changes parcels instance->mAgentParcelChangedSignal(); if (instance->mTeleportInProgress) @@ -1714,7 +1700,7 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use } // Request access list information for this land - parcel_mgr.sendParcelAccessListRequest(AL_ACCESS | AL_BAN); + parcel_mgr.sendParcelAccessListRequest(AL_ACCESS | AL_BAN | AL_ALLOW_EXPERIENCE | AL_BLOCK_EXPERIENCE); // Request dwell for this land, if it's not public land. parcel_mgr.mSelectedDwell = DWELL_NAN; @@ -1827,12 +1813,14 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use { LL_INFOS() << "Stopping parcel music (invalid audio stream URL)" << LL_ENDL; // clears the URL + // null value causes fade out gAudiop->startInternetStream(LLStringUtil::null); } } else if (!gAudiop->getInternetStreamURL().empty()) { LL_INFOS() << "Stopping parcel music (parcel stream URL is empty)" << LL_ENDL; + // null value causes fade out gAudiop->startInternetStream(LLStringUtil::null); } } @@ -1857,7 +1845,7 @@ void optionally_start_music(LLParcel* parcel) // changed as part of SL-4878 if (gOverlayBar && gOverlayBar->musicPlaying()) { - LLPanelNearByMedia* nearby_media_panel = LLFloaterNearbyMedia::instanceExists() ? LLFloaterNearbyMedia::getInstance()->getMediaPanel() : NULL; + LLPanelNearByMedia* nearby_media_panel = LLFloaterNearbyMedia::instanceExists() ? LLFloaterNearbyMedia::getInstance()->getMediaPanel() : nullptr; if ((nearby_media_panel && nearby_media_panel->getParcelAudioAutoStart()) || // or they have expressed no opinion in the UI, but have autoplay on... @@ -1865,6 +1853,7 @@ void optionally_start_music(LLParcel* parcel) /*gSavedSettings.getBOOL(LLViewerMedia::AUTO_PLAY_MEDIA_SETTING) &&*/ gSavedSettings.getBOOL("MediaTentativeAutoPlay"))) { + LL_INFOS() << "Starting parcel music " << parcel->getMusicURL() << LL_ENDL; LLViewerParcelMedia::playStreamingMusic(parcel); return; } @@ -1891,7 +1880,7 @@ void LLViewerParcelMgr::processParcelAccessListReply(LLMessageSystem *msg, void if (parcel_id != parcel->getLocalID()) { - LL_WARNS() << "processParcelAccessListReply for parcel " << parcel_id + LL_WARNS_ONCE("") << "processParcelAccessListReply for parcel " << parcel_id << " which isn't the selected parcel " << parcel->getLocalID()<< LL_ENDL; return; } @@ -1904,6 +1893,14 @@ void LLViewerParcelMgr::processParcelAccessListReply(LLMessageSystem *msg, void { parcel->unpackAccessEntries(msg, &(parcel->mBanList) ); } + else if (message_flags & AL_ALLOW_EXPERIENCE) + { + parcel->unpackExperienceEntries(msg, EXPERIENCE_KEY_TYPE_ALLOWED); + } + else if (message_flags & AL_BLOCK_EXPERIENCE) + { + parcel->unpackExperienceEntries(msg, EXPERIENCE_KEY_TYPE_BLOCKED); + } /*else if (message_flags & AL_RENTER) { parcel->unpackAccessEntries(msg, &(parcel->mRenterList) ); @@ -1938,10 +1935,6 @@ void LLViewerParcelMgr::processParcelDwellReply(LLMessageSystem* msg, void**) void LLViewerParcelMgr::sendParcelAccessListUpdate(U32 which) { - - LLUUID transactionUUID; - transactionUUID.generate(); - if (!mSelected) { return; @@ -1950,125 +1943,95 @@ void LLViewerParcelMgr::sendParcelAccessListUpdate(U32 which) LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal( mWestSouth ); if (!region) return; - LLMessageSystem* msg = gMessageSystem; - LLParcel* parcel = mCurrentParcel; if (!parcel) return; if (which & AL_ACCESS) - { - S32 count = parcel->mAccessList.size(); - S32 num_sections = (S32) ceil(count/PARCEL_MAX_ENTRIES_PER_PACKET); - S32 sequence_id = 1; - BOOL start_message = TRUE; - BOOL initial = TRUE; - - access_map_const_iterator cit = parcel->mAccessList.begin(); - access_map_const_iterator end = parcel->mAccessList.end(); - while ( (cit != end) || initial ) - { - if (start_message) - { - msg->newMessageFast(_PREHASH_ParcelAccessListUpdate); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() ); - msg->nextBlockFast(_PREHASH_Data); - msg->addU32Fast(_PREHASH_Flags, AL_ACCESS); - msg->addS32(_PREHASH_LocalID, parcel->getLocalID() ); - msg->addUUIDFast(_PREHASH_TransactionID, transactionUUID); - msg->addS32Fast(_PREHASH_SequenceID, sequence_id); - msg->addS32Fast(_PREHASH_Sections, num_sections); - start_message = FALSE; - - if (initial && (cit == end)) - { - // pack an empty block if there will be no data - msg->nextBlockFast(_PREHASH_List); - msg->addUUIDFast(_PREHASH_ID, LLUUID::null ); - msg->addS32Fast(_PREHASH_Time, 0 ); - msg->addU32Fast(_PREHASH_Flags, 0 ); - } - - initial = FALSE; - sequence_id++; - - } - - while ( (cit != end) && (msg->getCurrentSendTotal() < MTUBYTES)) - { - - const LLAccessEntry& entry = (*cit).second; - - msg->nextBlockFast(_PREHASH_List); - msg->addUUIDFast(_PREHASH_ID, entry.mID ); - msg->addS32Fast(_PREHASH_Time, entry.mTime ); - msg->addU32Fast(_PREHASH_Flags, entry.mFlags ); - ++cit; - } - - start_message = TRUE; - msg->sendReliable( region->getHost() ); - } + { + sendParcelAccessListUpdate(AL_ACCESS, parcel->mAccessList, region, parcel->getLocalID()); } if (which & AL_BAN) - { - S32 count = parcel->mBanList.size(); - S32 num_sections = (S32) ceil(count/PARCEL_MAX_ENTRIES_PER_PACKET); - S32 sequence_id = 1; - BOOL start_message = TRUE; - BOOL initial = TRUE; + { + sendParcelAccessListUpdate(AL_BAN, parcel->mBanList, region, parcel->getLocalID()); + } - access_map_const_iterator cit = parcel->mBanList.begin(); - access_map_const_iterator end = parcel->mBanList.end(); - while ( (cit != end) || initial ) - { - if (start_message) - { - msg->newMessageFast(_PREHASH_ParcelAccessListUpdate); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() ); - msg->nextBlockFast(_PREHASH_Data); - msg->addU32Fast(_PREHASH_Flags, AL_BAN); - msg->addS32(_PREHASH_LocalID, parcel->getLocalID() ); - msg->addUUIDFast(_PREHASH_TransactionID, transactionUUID); - msg->addS32Fast(_PREHASH_SequenceID, sequence_id); - msg->addS32Fast(_PREHASH_Sections, num_sections); - start_message = FALSE; + if (which & AL_ALLOW_EXPERIENCE) + { + sendParcelAccessListUpdate(AL_ALLOW_EXPERIENCE, parcel->getExperienceKeysByType(EXPERIENCE_KEY_TYPE_ALLOWED), region, parcel->getLocalID()); + } - if (initial && (cit == end)) - { - // pack an empty block if there will be no data - msg->nextBlockFast(_PREHASH_List); - msg->addUUIDFast(_PREHASH_ID, LLUUID::null ); - msg->addS32Fast(_PREHASH_Time, 0 ); - msg->addU32Fast(_PREHASH_Flags, 0 ); - } - - initial = FALSE; - sequence_id++; - - } - - while ( (cit != end) && (msg->getCurrentSendTotal() < MTUBYTES)) - { - const LLAccessEntry& entry = (*cit).second; - - msg->nextBlockFast(_PREHASH_List); - msg->addUUIDFast(_PREHASH_ID, entry.mID ); - msg->addS32Fast(_PREHASH_Time, entry.mTime ); - msg->addU32Fast(_PREHASH_Flags, entry.mFlags ); - ++cit; - } - - start_message = TRUE; - msg->sendReliable( region->getHost() ); - } + if (which & AL_BLOCK_EXPERIENCE) + { + sendParcelAccessListUpdate(AL_BLOCK_EXPERIENCE, parcel->getExperienceKeysByType(EXPERIENCE_KEY_TYPE_BLOCKED), region, parcel->getLocalID()); } } +void LLViewerParcelMgr::sendParcelAccessListUpdate(U32 flags, const LLAccessEntry::map& entries, LLViewerRegion* region, S32 parcel_local_id) +{ + S32 count = entries.size(); + S32 num_sections = (S32) ceil(count/PARCEL_MAX_ENTRIES_PER_PACKET); + S32 sequence_id = 1; + BOOL start_message = TRUE; + BOOL initial = TRUE; + + + LLUUID transactionUUID; + transactionUUID.generate(); + + + LLMessageSystem* msg = gMessageSystem; + + LLAccessEntry::map::const_iterator cit = entries.begin(); + LLAccessEntry::map::const_iterator end = entries.end(); + while ( (cit != end) || initial ) + { + if (start_message) + { + msg->newMessageFast(_PREHASH_ParcelAccessListUpdate); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() ); + msg->nextBlockFast(_PREHASH_Data); + msg->addU32Fast(_PREHASH_Flags, flags); + msg->addS32(_PREHASH_LocalID, parcel_local_id); + msg->addUUIDFast(_PREHASH_TransactionID, transactionUUID); + msg->addS32Fast(_PREHASH_SequenceID, sequence_id); + msg->addS32Fast(_PREHASH_Sections, num_sections); + start_message = FALSE; + + if (initial && (cit == end)) + { + // pack an empty block if there will be no data + msg->nextBlockFast(_PREHASH_List); + msg->addUUIDFast(_PREHASH_ID, LLUUID::null ); + msg->addS32Fast(_PREHASH_Time, 0 ); + msg->addU32Fast(_PREHASH_Flags, 0 ); + } + + initial = FALSE; + sequence_id++; + + } + + while ( (cit != end) && (msg->getCurrentSendTotal() < MTUBYTES)) + { + + const LLAccessEntry& entry = (*cit).second; + + msg->nextBlockFast(_PREHASH_List); + msg->addUUIDFast(_PREHASH_ID, entry.mID ); + msg->addS32Fast(_PREHASH_Time, entry.mTime ); + msg->addU32Fast(_PREHASH_Flags, entry.mFlags ); + ++cit; + } + + start_message = TRUE; + msg->sendReliable( region->getHost() ); + } +} + + void LLViewerParcelMgr::deedLandToGroup() { std::string group_name; @@ -2597,11 +2560,9 @@ void LLViewerParcelMgr::onTeleportFailed() mTeleportFailedSignal(); } -// [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-06-20 (Catznip-3.3.0) boost::signals2::connection LLViewerParcelMgr::setCollisionUpdateCallback(const collision_update_signal_t::slot_type & cb) { if (!mCollisionUpdateSignal) mCollisionUpdateSignal = new collision_update_signal_t(); return mCollisionUpdateSignal->connect(cb); } -// [/SL:KB] diff --git a/indra/newview/llviewerparcelmgr.h b/indra/newview/llviewerparcelmgr.h index b9520932d..fbd829718 100644 --- a/indra/newview/llviewerparcelmgr.h +++ b/indra/newview/llviewerparcelmgr.h @@ -33,12 +33,6 @@ #include "llparcelselection.h" #include "llui.h" -#ifndef BOOST_FUNCTION_HPP_INCLUDED -#include -#define BOOST_FUNCTION_HPP_INCLUDED -#endif -#include - class LLUUID; class LLMessageSystem; class LLParcel; @@ -78,26 +72,24 @@ public: class LLViewerParcelMgr : public LLSingleton { - -public: - typedef boost::function teleport_finished_callback_t; - typedef boost::signals2::signal teleport_finished_signal_t; - typedef boost::function parcel_changed_callback_t; - typedef boost::signals2::signal parcel_changed_signal_t; - + friend class LLSingleton; LLViewerParcelMgr(); ~LLViewerParcelMgr(); -// Aurora Sim +public: + typedef std::function teleport_finished_callback_t; + typedef boost::signals2::signal teleport_finished_signal_t; + typedef std::function parcel_changed_callback_t; + typedef boost::signals2::signal parcel_changed_signal_t; + void init(F32 region_size); -// Aurora Sim static void cleanupGlobals(); BOOL selectionEmpty() const; F32 getSelectionWidth() const { return F32(mEastNorth.mdV[VX] - mWestSouth.mdV[VX]); } F32 getSelectionHeight() const { return F32(mEastNorth.mdV[VY] - mWestSouth.mdV[VY]); } BOOL getSelection(LLVector3d &min, LLVector3d &max) { min = mWestSouth; max = mEastNorth; return !selectionEmpty();} - LLViewerRegion* getSelectionRegion(); + LLViewerRegion* getSelectionRegion() const; F32 getDwelling() const { return mSelectedDwell;} void getDisplayInfo(S32* area, S32* claim, S32* rent, BOOL* for_sale, F32* dwell); @@ -168,14 +160,13 @@ public: LLParcel* getHoverParcel() const; LLParcel* getCollisionParcel() const; -// [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-06-20 (Catznip-3.3.0) + const U8* getCollisionBitmap() const { return mCollisionBitmap; } size_t getCollisionBitmapSize() const { return mParcelsPerEdge * mParcelsPerEdge / 8; } U64 getCollisionRegionHandle() const { return mCollisionRegionHandle; } typedef boost::signals2::signal collision_update_signal_t; boost::signals2::connection setCollisionUpdateCallback(const collision_update_signal_t::slot_type & cb); -// [/SL:KB] // Can this agent build on the parcel he is on? // Used for parcel property icons in nav bar. @@ -304,6 +295,8 @@ public: static BOOL isParcelModifiableByAgent(const LLParcel* parcelp, U64 group_proxy_power); private: + static void sendParcelAccessListUpdate(U32 flags, const std::map& entries, LLViewerRegion* region, S32 parcel_local_id); + static void sendParcelExperienceUpdate( const U32 flags, uuid_vec_t experience_ids, LLViewerRegion* region, S32 parcel_local_id ); static bool releaseAlertCB(const LLSD& notification, const LLSD& response); // If the user is claiming land and the current selection @@ -368,11 +361,9 @@ private: // Watch for pending collisions with a parcel you can't access. // If it's coming, draw the parcel's boundaries. LLParcel* mCollisionParcel; -// [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-06-20 (Catznip-3.3.0) U8* mCollisionBitmap; U64 mCollisionRegionHandle; collision_update_signal_t* mCollisionUpdateSignal; -// [/SL:KB] U8* mCollisionSegments; BOOL mRenderCollision; BOOL mRenderSelection; diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index 6513c245f..ca1eb74ab 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -1972,6 +1972,9 @@ void LLViewerRegion::unpackRegionHandshake() void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) { + capabilityNames.append("AbuseCategories"); + capabilityNames.append("AcceptFriendship"); + capabilityNames.append("AcceptGroupInvite"); // ReadOfflineMsgs recieved messages only!!! capabilityNames.append("AgentPreferences"); capabilityNames.append("AgentState"); capabilityNames.append("AttachmentResources"); @@ -1982,6 +1985,8 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) capabilityNames.append("CopyInventoryFromNotecard"); capabilityNames.append("CreateInventoryCategory"); capabilityNames.append("CustomMenuAction"); + capabilityNames.append("DeclineFriendship"); + capabilityNames.append("DeclineGroupInvite"); // ReadOfflineMsgs recieved messages only!!! capabilityNames.append("DispatchRegionInfo"); capabilityNames.append("DirectDelivery"); capabilityNames.append("EnvironmentSettings"); @@ -1996,9 +2001,23 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) capabilityNames.append("IncrementCOFVersion"); capabilityNames.append("GamingData"); //Used by certain grids. AISAPI::getCapNames(capabilityNames); + capabilityNames.append("GetDisplayNames"); + capabilityNames.append("GetExperiences"); + capabilityNames.append("AgentExperiences"); + capabilityNames.append("FindExperienceByName"); + capabilityNames.append("GetExperienceInfo"); + capabilityNames.append("GetAdminExperiences"); + capabilityNames.append("GetCreatorExperiences"); + capabilityNames.append("ExperiencePreferences"); + capabilityNames.append("GroupExperiences"); + capabilityNames.append("UpdateExperience"); + capabilityNames.append("IsExperienceAdmin"); + capabilityNames.append("IsExperienceContributor"); + capabilityNames.append("RegionExperiences"); capabilityNames.append("GetMesh"); - capabilityNames.append("GetMesh2"); // Used on SecondLife(tm) sim versions 280647 and higher (13.09.17). + capabilityNames.append("GetMesh2"); + capabilityNames.append("GetMetadata"); capabilityNames.append("GetObjectCost"); capabilityNames.append("GetObjectPhysicsData"); capabilityNames.append("GetTexture"); @@ -2051,6 +2070,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) capabilityNames.append("UpdateScriptAgent"); capabilityNames.append("UpdateScriptTask"); capabilityNames.append("UploadBakedTexture"); + capabilityNames.append("UserInfo"); capabilityNames.append("ViewerAsset"); capabilityNames.append("ViewerMetrics"); capabilityNames.append("ViewerStartAuction"); diff --git a/indra/newview/llviewertexteditor.h b/indra/newview/llviewertexteditor.h index a7741502f..9b5edcc88 100644 --- a/indra/newview/llviewertexteditor.h +++ b/indra/newview/llviewertexteditor.h @@ -39,7 +39,7 @@ // // Classes // -class LLViewerTextEditor : public LLTextEditor +class LLViewerTextEditor final : public LLTextEditor { public: diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 608a4529a..8fdd639f1 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -1116,7 +1116,8 @@ LLWindowCallbacks::DragNDropResult LLViewerWindow::handleDragNDrop( LLWindow *wi LL_DEBUGS() << "Object: picked at " << pos.mX << ", " << pos.mY << " - face = " << object_face << " - URL = " << url << LL_ENDL; - LLVOVolume *obj = dynamic_cast(static_cast(pick_info.getObject())); + LLViewerObject* vobjp = static_cast(pick_info.getObject()); + LLVOVolume *obj = vobjp ? vobjp->asVolume() : nullptr; if (obj && !obj->getRegion()->getCapability("ObjectMedia").empty()) { @@ -2080,8 +2081,6 @@ void LLViewerWindow::adjustRectanglesForFirstUse(const LLRect& window) adjust_rect_top_right("FloaterMiniMapRect", window); - adjust_rect_top_right("FloaterLagMeter", window); - adjust_rect_top_left("FloaterBuildOptionsRect", window); adjust_rect_bottom_left("FloaterActiveSpeakersRect", window); diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index f9b36e00d..bd43feff0 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -4153,10 +4153,7 @@ void LLVOAvatar::clearNameTag() //static void LLVOAvatar::invalidateNameTag(const LLUUID& agent_id) { - LLViewerObject* obj = gObjectList.findObject(agent_id); - if (!obj) return; - - LLVOAvatar* avatar = dynamic_cast(obj); + LLVOAvatar* avatar = gObjectList.findAvatar(agent_id); if (!avatar) return; avatar->clearNameTag(); @@ -6923,7 +6920,7 @@ void LLVOAvatar::addAttachmentOverridesForObject(LLViewerObject *vo, uuid_set_t* } } - LLVOVolume *vobj = dynamic_cast(vo); + LLVOVolume *vobj = vo->asVolume(); if (vobj && vobj->isRiggedMesh() && vobj->getVolume() && vobj->getVolume()->isMeshAssetLoaded() && gMeshRepo.meshRezEnabled()) { @@ -8661,11 +8658,13 @@ bool LLVOAvatar::isTooComplex() const { static const LLCachedControl always_render_friends("AlwaysRenderFriends", 0); bool too_complex; - if (isSelf() || (always_render_friends && always_render_friends != 3 && LLAvatarTracker::instance().isBuddy(getID()))) + // 'AlwaysRenderFriends' == 0, or an animesh, falls through to the complexity limits, if not self. Self is always rendered. + // 1 always render friends, 2 render only friends, 3 render only self + if (isSelf() || (always_render_friends && always_render_friends != 3 && !isControlAvatar() && LLAvatarTracker::instance().isBuddy(getID()))) { too_complex = false; } - else if (always_render_friends >= 2) + else if (always_render_friends >= 2 && !isControlAvatar()) { too_complex = true; } @@ -9012,7 +9011,7 @@ void LLVOAvatar::updateMeshTextures() // set texture and color of hair manually if we are not using a baked image. // This can happen while loading hair for yourself, or for clients that did not // bake a hair texture. Still needed for yourself after 1.22 is depricated. - if (!is_layer_baked[BAKED_HAIR] || isEditingAppearance()) + if (!is_layer_baked[BAKED_HAIR]) { const LLColor4 color = mTexHairColor ? mTexHairColor->getColor() : LLColor4(1,1,1,1); LLViewerTexture* hair_img = getImage( TEX_HAIR, 0 ); @@ -10565,7 +10564,7 @@ void LLVOAvatar::getAssociatedVolumes(std::vector& volumes) {{ LLViewerObject* attached_object = iter.first; #endif - LLVOVolume *volume = dynamic_cast(attached_object); + LLVOVolume *volume = attached_object->asVolume(); if (volume) { volumes.push_back(volume); @@ -10578,11 +10577,12 @@ void LLVOAvatar::getAssociatedVolumes(std::vector& volumes) } } LLViewerObject::const_child_list_t& children = attached_object->getChildren(); - for (LLViewerObject::const_child_list_t::const_iterator it = children.begin(); - it != children.end(); ++it) + for (LLViewerObject* childp : children) { - LLViewerObject *childp = *it; - LLVOVolume *volume = dynamic_cast(childp); + if (!childp) + continue; + + LLVOVolume *volume = childp->asVolume(); if (volume) { volumes.push_back(volume); @@ -10599,11 +10599,9 @@ void LLVOAvatar::getAssociatedVolumes(std::vector& volumes) { volumes.push_back(volp); LLViewerObject::const_child_list_t& children = volp->getChildren(); - for (LLViewerObject::const_child_list_t::const_iterator it = children.begin(); - it != children.end(); ++it) + for (LLViewerObject* childp : children) { - LLViewerObject *childp = *it; - LLVOVolume *volume = dynamic_cast(childp); + LLVOVolume *volume = childp ? childp->asVolume() : nullptr; if (volume) { volumes.push_back(volume); @@ -10948,7 +10946,7 @@ void LLVOAvatar::accountRenderComplexityForObject( ++child_iter) { LLViewerObject* child_obj = *child_iter; - LLVOVolume *child = dynamic_cast(child_obj); + LLVOVolume *child = child_obj ? child_obj->asVolume() : nullptr; if (child) { attachment_children_cost += child->getRenderCost(textures); @@ -11005,7 +11003,7 @@ void LLVOAvatar::accountRenderComplexityForObject( iter != child_list.end(); ++iter) { LLViewerObject* childp = *iter; - const LLVOVolume* chld_volume = dynamic_cast(childp); + const LLVOVolume* chld_volume = childp ? childp->asVolume() : nullptr; if (chld_volume) { // get cost and individual textures diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 2a847c4a5..d28527499 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -555,7 +555,7 @@ private: // Impostors //-------------------------------------------------------------------- public: - BOOL isImpostor() const; + virtual BOOL isImpostor() const; BOOL shouldImpostor(const U32 rank_factor = 1) const; BOOL needsImpostorUpdate() const; const LLVector3& getImpostorOffset() const; @@ -570,6 +570,7 @@ public: F32SecondsImplicit mLastImpostorUpdateFrameTime; const LLVector3* getLastAnimExtents() const { return mLastAnimExtents; } void setNeedsExtentUpdate(bool val) { mNeedsExtentUpdate = val; } + private: LLVector3 mImpostorOffset; LLVector2 mImpostorDim; diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index 292524dd8..406d25b80 100644 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -869,6 +869,7 @@ void LLVOAvatarSelf::updateRegion(LLViewerRegion *regionp) } mRegionCrossingTimer.reset(); LLViewerObject::updateRegion(regionp); + gAgent.setIsCrossingRegion(false); // Attachments getting lost on TP } //-------------------------------------------------------------------- diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index af81a0faf..722aaca16 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -265,6 +265,11 @@ LLVOVolume::~LLVOVolume() } } +LLVOVolume* LLVOVolume::asVolume() +{ + return this; +} + void LLVOVolume::markDead() { if (!mDead) @@ -3494,8 +3499,6 @@ bool LLVOVolume::isAnimatedObject() const // virtual void LLVOVolume::onReparent(LLViewerObject *old_parent, LLViewerObject *new_parent) { - LLVOVolume *old_volp = dynamic_cast(old_parent); - if (new_parent && !new_parent->isAvatar()) { if (mControlAvatar.notNull()) @@ -3507,6 +3510,7 @@ void LLVOVolume::onReparent(LLViewerObject *old_parent, LLViewerObject *new_pare av->markForDeath(); } } + LLVOVolume *old_volp = old_parent ? old_parent->asVolume() : nullptr; if (old_volp && old_volp->isAnimatedObject()) { if (old_volp->getControlAvatar()) @@ -5245,7 +5249,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) if (bridge) { vobj = bridge->mDrawable->getVObj(); - vol_obj = dynamic_cast(vobj); + vol_obj = vobj ? vobj->asVolume() : nullptr; } if (vol_obj) { diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h index ab2065ca8..db91548e8 100644 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -94,7 +94,7 @@ public: }; // Class which embodies all Volume objects (with pcode LL_PCODE_VOLUME) -class LLVOVolume : public LLViewerObject +class LLVOVolume final : public LLViewerObject { LOG_CLASS(LLVOVolume); protected: @@ -126,7 +126,9 @@ public: public: LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp); - /*virtual*/ void markDead(); // Override (and call through to parent) to clean up media references + + LLVOVolume* asVolume() final; + /*virtual*/ void markDead() override; // Override (and call through to parent) to clean up media references /*virtual*/ LLDrawable* createDrawable(LLPipeline *pipeline); diff --git a/indra/newview/llwebprofile.cpp b/indra/newview/llwebprofile.cpp index 92df639a6..02799cfd0 100644 --- a/indra/newview/llwebprofile.cpp +++ b/indra/newview/llwebprofile.cpp @@ -82,7 +82,13 @@ public: return; } - auto root = LlsdFromJson(nlohmann::json::parse(body)); + auto root = LlsdFromJsonString(body); + if (root.isUndefined()) + { + LL_WARNS() << "Failed to get valid json body" << LL_ENDL; + LLWebProfile::reportImageUploadStatus(false); + return; + } // *TODO: 404 = not supported by the grid // *TODO: increase timeout or handle HTTP_INTERNAL_ERROR_* time errors. diff --git a/indra/newview/rlvactions.cpp b/indra/newview/rlvactions.cpp index b746cda4a..6dd15cf49 100644 --- a/indra/newview/rlvactions.cpp +++ b/indra/newview/rlvactions.cpp @@ -1,6 +1,6 @@ /** * - * Copyright (c) 2009-2013, Kitty Barnett + * Copyright (c) 2009-2016, Kitty Barnett * * The source code in this file is provided to you under the terms of the * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY; @@ -38,6 +38,13 @@ bool RlvActions::canReceiveIM(const LLUUID& idSender) ( (!gRlvHandler.hasBehaviour(RLV_BHVR_RECVIMFROM)) || (!gRlvHandler.isException(RLV_BHVR_RECVIMFROM, idSender)) ) ); } +bool RlvActions::canSendChannel(int nChannel) +{ + return + ( (!gRlvHandler.hasBehaviour(RLV_BHVR_SENDCHANNEL)) || (gRlvHandler.isException(RLV_BHVR_SENDCHANNEL, nChannel)) ) /*&& + ( (!gRlvHandler.hasBehaviour(RLV_BHVR_SENDCHANNELEXCEPT)) || (!gRlvHandler.isException(RLV_BHVR_SENDCHANNELEXCEPT, nChannel)) )*/; +} + // Checked: 2010-11-30 (RLVa-1.3.0) bool RlvActions::canSendIM(const LLUUID& idRecipient) { @@ -62,29 +69,44 @@ bool RlvActions::canStartIM(const LLUUID& idRecipient) ( (!gRlvHandler.hasBehaviour(RLV_BHVR_STARTIMTO)) || (!gRlvHandler.isException(RLV_BHVR_STARTIMTO, idRecipient)) ) ); } +// Handles: @chatwhisper, @chatnormal and @chatshout +EChatType RlvActions::checkChatVolume(EChatType chatType) +{ + // In vs Bhvr | whisper | normal | shout | n+w | n+s | s+w | s+n+w | + // --------------------------------------------------------------------------------- + // whisper | normal | - | - | normal | - | normal | normal | + // normal | - | whisper | - | whisper | whisper | - | whisper | + // shout | - | whisper | normal | whisper | whisper | normal | whisper | + + RlvHandler& rlvHandler = gRlvHandler; + if ( ((CHAT_TYPE_SHOUT == chatType) || (CHAT_TYPE_NORMAL == chatType)) && (rlvHandler.hasBehaviour(RLV_BHVR_CHATNORMAL)) ) + chatType = CHAT_TYPE_WHISPER; + else if ( (CHAT_TYPE_SHOUT == chatType) && (rlvHandler.hasBehaviour(RLV_BHVR_CHATSHOUT)) ) + chatType = CHAT_TYPE_NORMAL; + else if ( (CHAT_TYPE_WHISPER == chatType) && (rlvHandler.hasBehaviour(RLV_BHVR_CHATWHISPER)) ) + chatType = CHAT_TYPE_NORMAL; + return chatType; +} + // ============================================================================ // Movement // -// Checked: 2010-12-11 (RLVa-1.2.2) bool RlvActions::canAcceptTpOffer(const LLUUID& idSender) { return ((!gRlvHandler.hasBehaviour(RLV_BHVR_TPLURE)) || (gRlvHandler.isException(RLV_BHVR_TPLURE, idSender))) && (canStand()); } -// Checked: 2013-11-08 (RLVa-1.4.9) bool RlvActions::autoAcceptTeleportOffer(const LLUUID& idSender) { return ((idSender.notNull()) && (gRlvHandler.isException(RLV_BHVR_ACCEPTTP, idSender))) || (gRlvHandler.hasBehaviour(RLV_BHVR_ACCEPTTP)); } -// Checked: 2013-11-08 (RLVa-1.4.9) bool RlvActions::canAcceptTpRequest(const LLUUID& idSender) { return (!gRlvHandler.hasBehaviour(RLV_BHVR_TPREQUEST)) || (gRlvHandler.isException(RLV_BHVR_TPREQUEST, idSender)); } -// Checked: 2013-11-08 (RLVa-1.4.9) bool RlvActions::autoAcceptTeleportRequest(const LLUUID& idRequester) { return ((idRequester.notNull()) && (gRlvHandler.isException(RLV_BHVR_ACCEPTTPREQUEST, idRequester))) || (gRlvHandler.hasBehaviour(RLV_BHVR_ACCEPTTPREQUEST)); diff --git a/indra/newview/rlvactions.h b/indra/newview/rlvactions.h index fbc8ab12b..175926797 100644 --- a/indra/newview/rlvactions.h +++ b/indra/newview/rlvactions.h @@ -1,6 +1,6 @@ /** * - * Copyright (c) 2009-2013, Kitty Barnett + * Copyright (c) 2009-2016, Kitty Barnett * * The source code in this file is provided to you under the terms of the * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY; @@ -17,6 +17,7 @@ #ifndef RLV_ACTIONS_H #define RLV_ACTIONS_H +#include "llchat.h" #include "rlvdefines.h" // ============================================================================ @@ -34,6 +35,11 @@ public: */ static bool canReceiveIM(const LLUUID& idSender); + /* + * Returns true if the user is allowed to chat on the specified channel + */ + static bool canSendChannel(int nChannel); + /* * Returns true if the user is allowed to send IMs to the specified recipient (can be an avatar or a group) */ @@ -53,6 +59,11 @@ public: static bool canShowName(EShowNamesContext eContext) { return (eContext < SNC_COUNT) ? !s_BlockNamesContexts[eContext] : false; } static void setShowName(EShowNamesContext eContext, bool fShowName) { if ( (eContext < SNC_COUNT) && (isRlvEnabled()) ) { s_BlockNamesContexts[eContext] = !fShowName; } } + /* + * Checks if the user is allowed to use the specified volume in (main) chat and returns the appropriate chat volume type + */ + static EChatType checkChatVolume(EChatType chatType); + protected: // Backwards logic so that we can initialize to 0 and it won't block when we forget to/don't check if RLVa is disabled static bool s_BlockNamesContexts[SNC_COUNT]; @@ -108,7 +119,7 @@ public: static bool hasBehaviour(ERlvBehaviour eBhvr); /* - * Returns true if a - P2P or group - IM session is open with the specified UUID. + * Returns true if a - P2P or group - IM session is open with the specified UUID */ static bool hasOpenP2PSession(const LLUUID& idAgent); static bool hasOpenGroupSession(const LLUUID& idGroup); diff --git a/indra/newview/rlvhelper.cpp b/indra/newview/rlvhelper.cpp index fcffd476a..ebe57b279 100644 --- a/indra/newview/rlvhelper.cpp +++ b/indra/newview/rlvhelper.cpp @@ -210,6 +210,10 @@ RlvCommandOptionGeneric::RlvCommandOptionGeneric(const std::string& strOption): m_fValid = true; } +// ============================================================================ +// RlvCommandOption structures +// + // Checked: 2012-07-28 (RLVa-1.4.7) class RlvCommandOptionGetPathCallback { @@ -269,6 +273,14 @@ RlvCommandOptionGetPath::RlvCommandOptionGetPath(const RlvCommand& rlvCmd, getpa { getItemIDs(rlvCmdOption.getAttachmentPoint(), m_idItems); } + else if (rlvCmdOption.isUUID()) // ... or it can specify a specific attachment + { + const LLViewerObject* pAttachObj = gObjectList.findObject(rlvCmdOption.getUUID()); + if ( (pAttachObj) && (pAttachObj->isAttachment()) && (pAttachObj->permYouOwner()) ) + m_idItems.push_back(pAttachObj->getAttachmentItemID()); + else + m_fValid = false; + } else if (rlvCmdOption.isEmpty()) // ... or it can be empty (in which case we act on the object that issued the command) { const LLViewerObject* pObj = gObjectList.findObject(rlvCmd.getObjectID()); @@ -434,9 +446,19 @@ bool RlvObject::hasBehaviour(ERlvBehaviour eBehaviour, bool fStrictOnly) const bool RlvObject::hasBehaviour(ERlvBehaviour eBehaviour, const std::string& strOption, bool fStrictOnly) const { - for (rlv_command_list_t::const_iterator itCmd = m_Commands.begin(); itCmd != m_Commands.end(); ++itCmd) - if ( (itCmd->getBehaviourType() == eBehaviour) && (itCmd->getOption() == strOption) && ((!fStrictOnly) || (itCmd->isStrict())) ) + for (const RlvCommand& rlvCmd : m_Commands) + { + // The specified behaviour is contained within the current object if: + // - the (parsed) behaviour matches + // - the option matches (or we're checking for an empty option and the command was reference counted) + // - we're not matching on strict (or it is a strict command) + if ( (rlvCmd.getBehaviourType() == eBehaviour) && + ( (rlvCmd.getOption() == strOption) /*|| ((strOption.empty()) && (rlvCmd.isRefCounted()))*/ ) && + ( (!fStrictOnly) ||(rlvCmd.isStrict()) ) ) + { return true; + } + } return false; } diff --git a/indra/newview/roles_constants.h b/indra/newview/roles_constants.h index a75ad6b5b..a79eda07c 100644 --- a/indra/newview/roles_constants.h +++ b/indra/newview/roles_constants.h @@ -146,6 +146,9 @@ const U64 GP_SESSION_JOIN = 0x1LL << 16; //can join session const U64 GP_SESSION_VOICE = 0x1LL << 27; //can hear/talk const U64 GP_SESSION_MODERATOR = 0x1LL << 37; //can mute people's session +const U64 GP_EXPERIENCE_ADMIN = 0x1LL << 49; // has admin rights to any experiences owned by this group +const U64 GP_EXPERIENCE_CREATOR = 0x1LL << 50; // can sign scripts for experiences owned by this group + // Group Banning const U64 GP_GROUP_BAN_ACCESS = 0x1LL << 51; // Allows access to ban / un-ban agents from a group. diff --git a/indra/newview/scriptcounter.cpp b/indra/newview/scriptcounter.cpp index 62c7b75bb..9e25512df 100644 --- a/indra/newview/scriptcounter.cpp +++ b/indra/newview/scriptcounter.cpp @@ -33,6 +33,7 @@ #include "scriptcounter.h" +#include "llavataractions.h" #include "llavatarnamecache.h" #include "llviewerregion.h" #include "llselectmgr.h" @@ -44,15 +45,6 @@ void cmdline_printchat(const std::string& message); LLVOAvatar* find_avatar_from_object( LLViewerObject* object ); -namespace -{ - void countedScriptsOnAvatar(LLStringUtil::format_map_t args, const LLAvatarName& av_name) - { - args["NAME"] = av_name.getNSName(); - cmdline_printchat(LLTrans::getString("ScriptCountAvatar", args)); - } -} - std::map ScriptCounter::sCheckMap; ScriptCounter::ScriptCounter(bool do_delete, LLViewerObject* object) @@ -82,22 +74,23 @@ void ScriptCounter::requestInventories() LLVOAvatar* av = static_cast(foo); // Iterate through all the attachment points - for (LLVOAvatar::attachment_map_t::iterator i = av->mAttachmentPoints.begin(); i != av->mAttachmentPoints.end(); ++i) + for (const auto& i : av->mAttachmentPoints) { - if (LLViewerJointAttachment* attachment = i->second) + if (LLViewerJointAttachment* attachment = i.second) { if (!attachment->getValid()) continue; // Iterate through all the attachments on this point - for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator j = attachment->mAttachedObjects.begin(); j != attachment->mAttachedObjects.end(); ++j) - if (LLViewerObject* object = *j) + for (const auto& object : attachment->mAttachedObjects) + if (object) requestInventoriesFor(object); } } } else // Iterate through all the selected objects { - for (LLObjectSelection::valid_root_iterator i = LLSelectMgr::getInstance()->getSelection()->valid_root_begin(); i != LLSelectMgr::getInstance()->getSelection()->valid_root_end(); ++i) + auto selection = LLSelectMgr::getInstance()->getSelection(); + for (auto i = selection->valid_root_begin(), end = selection->valid_root_end(); i != end; ++i) if (LLSelectNode* selectNode = *i) if (LLViewerObject* object = selectNode->getObject()) requestInventoriesFor(object); @@ -111,10 +104,8 @@ void ScriptCounter::requestInventoriesFor(LLViewerObject* object) { ++objectCount; requestInventoryFor(object); - LLViewerObject::child_list_t child_list = object->getChildren(); - for (LLViewerObject::child_list_t::iterator i = child_list.begin(); i != child_list.end(); ++i) + for (auto child : object->getChildren()) { - LLViewerObject* child = *i; if (child->isAvatar()) continue; requestInventoryFor(child); } @@ -140,41 +131,55 @@ void ScriptCounter::inventoryChanged(LLViewerObject* obj, LLInventoryObject::obj if (inv) { - LLInventoryObject::object_list_t::const_iterator end = inv->end(); - for (LLInventoryObject::object_list_t::const_iterator i = inv->begin(); i != end; ++i) - if (LLInventoryObject* asset = (*i)) - if (asset->getType() == LLAssetType::AT_LSL_TEXT) + uuid_vec_t ids; + + for (auto asset : *inv) + { + const LLUUID& id = asset->getUUID(); + if (asset->getType() == LLAssetType::AT_LSL_TEXT && id.notNull()) + { + ++scriptcount; + if (doDelete) + ids.push_back(id); + else { - ++scriptcount; - if (doDelete) - { - const LLUUID& id = asset->getUUID(); - if (id.notNull()) - { - //LL_INFOS() << "Deleting script " << id << " in " << objid << LL_ENDL; - obj->removeInventory(id); - --i; // Avoid iteration when removing, everything has shifted - end = inv->end(); - } - } - else - { - const LLUUID& id = asset->getUUID(); - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_GetScriptRunning); - msg->nextBlockFast(_PREHASH_Script); - msg->addUUIDFast(_PREHASH_ObjectID, obj->getID()); - msg->addUUIDFast(_PREHASH_ItemID, id); - msg->sendReliable(obj->getRegion()->getHost()); - sCheckMap[id] = this; - ++checking; - } + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_GetScriptRunning); + msg->nextBlockFast(_PREHASH_Script); + msg->addUUIDFast(_PREHASH_ObjectID, obj->getID()); + msg->addUUIDFast(_PREHASH_ItemID, id); + msg->sendReliable(obj->getRegion()->getHost()); + sCheckMap[id] = this; + ++checking; } + } + } + + for (const auto& id : ids) + { + //LL_INFOS() << "Deleting script " << id << " in " << objid << LL_ENDL; + obj->removeInventory(id); + } } summarize(); } +void ScriptCounter::processScriptRunningReply(LLMessageSystem* msg) +{ + if (!sCheckMap.empty()) + { + LLUUID item_id; + msg->getUUIDFast(_PREHASH_Script, _PREHASH_ItemID, item_id); + auto it = sCheckMap.find(item_id); + if (it != sCheckMap.end()) + { + it->second->processRunningReply(msg); + sCheckMap.erase(it); + } + } +} + void ScriptCounter::processRunningReply(LLMessageSystem* msg) { BOOL is; @@ -199,7 +204,10 @@ void ScriptCounter::summarize() args["RUNNING"] = stringize(mRunningCount); args["MONO"] = stringize(mMonoCount); if (foo->isAvatar()) - LLAvatarNameCache::get(foo->getID(), boost::bind(countedScriptsOnAvatar, args, _2)); + { + args["NAME"] = LLAvatarActions::getSLURL(foo->getID()); + cmdline_printchat(LLTrans::getString("ScriptCountAvatar", args)); + } else cmdline_printchat(LLTrans::getString(doDelete ? "ScriptDeleteObject" : "ScriptCountObject", args)); diff --git a/indra/newview/scriptcounter.h b/indra/newview/scriptcounter.h index 78fd32058..90dedfbb0 100644 --- a/indra/newview/scriptcounter.h +++ b/indra/newview/scriptcounter.h @@ -33,19 +33,19 @@ #include "llvoinventorylistener.h" -class ScriptCounter : public LLInstanceTracker, public LLVOInventoryListener +class ScriptCounter final : public LLInstanceTracker, public LLVOInventoryListener { public: ScriptCounter(bool do_delete, LLViewerObject* object); ~ScriptCounter(); - /*virtual*/ void inventoryChanged(LLViewerObject* obj, LLInventoryObject::object_list_t* inv, S32, void*); + void inventoryChanged(LLViewerObject* obj, LLInventoryObject::object_list_t* inv, S32, void*) override; void requestInventories(); + static void processScriptRunningReply(LLMessageSystem* msg); private: void requestInventoriesFor(LLViewerObject* object); void requestInventoryFor(LLViewerObject* object); - friend void process_script_running_reply(LLMessageSystem* msg, void**); void processRunningReply(LLMessageSystem* msg); void summarize(); // Check if finished, if so, output and destroy. diff --git a/indra/newview/shupdatechecker.cpp b/indra/newview/shupdatechecker.cpp index 497439f24..f13760760 100644 --- a/indra/newview/shupdatechecker.cpp +++ b/indra/newview/shupdatechecker.cpp @@ -1,128 +1,102 @@ #include "llviewerprecompiledheaders.h" -#include "llviewerwindow.h" -#include "llwindow.h" -#include "llpanelgeneral.h" -#include "llappviewer.h" -#include "llbutton.h" -#include "llviewercontrol.h" -#include "llnotificationsutil.h" -#include "llstartup.h" -#include "llviewerwindow.h" // to link into child list -#include "llnotify.h" -#include "lluictrlfactory.h" -#include "llhttpclient.h" -#include "llversioninfo.h" #include "llbufferstream.h" +#include "llhttpclient.h" +#include "llnotificationsutil.h" +#include "llversioninfo.h" +#include "llviewerwindow.h" +#include "llsdjson.h" #include "llweb.h" +#include "llwindow.h" -#include + +void onNotifyButtonPress(const LLSD& notification, const LLSD& response, std::string name, std::string url) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option == 0) // URL + { + if (gViewerWindow) + { + gViewerWindow->getWindow()->spawnWebBrowser(LLWeb::escapeURL(url), true); + } + } +} + +void onCompleted(const LLSD& data, bool release) +{ + S32 build(LLVersionInfo::getBuild()); + std::string viewer_version = llformat("%s (%i)", LLVersionInfo::getShortVersion().c_str(), build); + +#if LL_WINDOWS + constexpr auto platform = "windows"; +#elif LL_LINUX + constexpr auto platform = "linux"; +#elif LL_DARWIN + constexpr auto platform = "apple"; +#endif + std::string recommended_version = data["recommended"][platform]; + std::string minimum_version = data["minimum"][platform]; + + S32 minimum_build, recommended_build; + sscanf(recommended_version.c_str(), "%*i.%*i.%*i (%i)", &recommended_build); + sscanf(minimum_version.c_str(), "%*i.%*i.%*i (%i)", &minimum_build); + + LL_INFOS("GetUpdateInfoResponder") << build << LL_ENDL; + LLSD args; + args["CURRENT_VER"] = viewer_version; + args["RECOMMENDED_VER"] = recommended_version; + args["MINIMUM_VER"] = minimum_version; + args["URL"] = data["url"].asString(); + + static LLCachedControl lastver(release ? "SinguLastKnownReleaseBuild" : "SinguLastKnownAlphaBuild", 0); + + if (build < minimum_build || build < recommended_build) + { + if (lastver.get() < recommended_build) + { + lastver = recommended_build; + LLUI::sIgnoresGroup->setWarning("UrgentUpdateModal", true); + LLUI::sIgnoresGroup->setWarning("UrgentUpdate", true); + LLUI::sIgnoresGroup->setWarning("RecommendedUpdate", true); + } + const std::string&& notification = build < minimum_build ? + LLUI::sIgnoresGroup->getWarning("UrgentUpdateModal") ? "UrgentUpdateModal" : "UrgentUpdate" : + "RecommendedUpdate"; //build < recommended_build + LLNotificationsUtil::add(notification, args, LLSD(), boost::bind(onNotifyButtonPress, _1, _2, notification, data["url"].asString())); + } +} extern AIHTTPTimeoutPolicy getUpdateInfoResponder_timeout; /////////////////////////////////////////////////////////////////////////////// // GetUpdateInfoResponder -class GetUpdateInfoResponder : public LLHTTPClient::ResponderWithCompleted +class GetUpdateInfoResponder final : public LLHTTPClient::ResponderWithCompleted { LOG_CLASS(GetUpdateInfoResponder); - public: - GetUpdateInfoResponder(std::string type) - : mType(type) - {} - void onNotifyButtonPress(const LLSD& notification, const LLSD& response, std::string name, std::string url) + GetUpdateInfoResponder(std::string type) : mType(type) {} + void completedRaw(LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) override { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (option == 0) // URL - { - std::string escaped_url = LLWeb::escapeURL(url); - if (gViewerWindow) - { - gViewerWindow->getWindow()->spawnWebBrowser(escaped_url, true); - } - } - if (option == 1) // Later - {} - } - /*virtual*/ void completedRaw(LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) - { - LLBufferStream istr(channels, buffer.get()); - std::stringstream strstrm; - strstrm << istr.rdbuf(); - const std::string body = strstrm.str(); - if (mStatus != HTTP_OK) { LL_WARNS() << "Failed to get update info (" << mStatus << ")" << LL_ENDL; return; } - auto root = nlohmann::json::parse(body); - - std::string viewer_version = llformat("%s (%i)", LLVersionInfo::getShortVersion().c_str(), LLVersionInfo::getBuild()); - - const auto data = root[mType]; -#if LL_WINDOWS - constexpr auto platform = "windows"; -#elif LL_LINUX - constexpr auto platform = "linux"; -#elif LL_DARWIN - constexpr auto platform = "apple"; -#endif - std::string recommended_version = data["recommended"][platform]; - std::string minimum_version = data["minimum"][platform]; - - S32 minimum_build, recommended_build; - sscanf(recommended_version.c_str(), "%*i.%*i.%*i (%i)", &recommended_build); - sscanf(minimum_version.c_str(), "%*i.%*i.%*i (%i)", &minimum_build); - - LL_INFOS() << LLVersionInfo::getBuild() << LL_ENDL; - LLSD args; - args["CURRENT_VER"] = viewer_version; - args["RECOMMENDED_VER"] = recommended_version; - args["MINIMUM_VER"] = minimum_version; - args["URL"] = data["url"].get(); - args["TYPE"] = mType == "release" ? "Viewer" : "Alpha"; - - static LLCachedControl sLastKnownReleaseBuild("SinguLastKnownReleaseBuild", 0); - static LLCachedControl sLastKnownAlphaBuild("SinguLastKnownAlphaBuild", 0); - - LLCachedControl& lastver = mType == "release" ? sLastKnownReleaseBuild : sLastKnownAlphaBuild; - - if (LLVersionInfo::getBuild() < minimum_build || LLVersionInfo::getBuild() < recommended_build) + LLBufferStream istr(channels, buffer.get()); + std::stringstream strstrm; + strstrm << istr.rdbuf(); + LLSD data = LlsdFromJsonString(strstrm.str()); + if (data.isUndefined()) { - if (lastver.get() < recommended_build) - { - lastver = recommended_build; - LLUI::sIgnoresGroup->setWarning("UrgentUpdateModal", true); - LLUI::sIgnoresGroup->setWarning("UrgentUpdate", true); - LLUI::sIgnoresGroup->setWarning("RecommendedUpdate", true); - } - std::string notificaiton; - if (LLVersionInfo::getBuild() < minimum_build) - { - if (LLUI::sIgnoresGroup->getWarning("UrgentUpdateModal")) - { - notificaiton = "UrgentUpdateModal"; - } - else - { - notificaiton = "UrgentUpdate"; - } - } - else if (LLVersionInfo::getBuild() < recommended_build) - { - notificaiton = "RecommendedUpdate"; - } - if (!notificaiton.empty()) - { - LLNotificationsUtil::add(notificaiton, args, LLSD(), boost::bind(&GetUpdateInfoResponder::onNotifyButtonPress, this, _1, _2, notificaiton, data["url"])); - } - } + LL_WARNS() << "Failed to parse json string from body." << LL_ENDL; + // TODO: Should we say something here for the user? + } + else onCompleted(data[mType], mType == "release"); } protected: - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return getUpdateInfoResponder_timeout; } - /*virtual*/ char const* getName(void) const { return "GetUpdateInfoResponder"; } + AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy() const override { return getUpdateInfoResponder_timeout; } + char const* getName() const override { return "GetUpdateInfoResponder"; } private: std::string mType; @@ -136,18 +110,15 @@ void check_for_updates() { std::string type; auto& channel = LLVersionInfo::getChannel(); - if (channel == std::string("Singularity")) + if (channel == "Singularity") { type = "release"; } - else if (channel == std::string("Singularity Test") || channel == std::string("Singularity Alpha")) + else if (channel == "Singularity Test" || channel == "Singularity Alpha" || channel == "Singularity Beta") { type = "alpha"; } - else - { - return; - } + else return; LLHTTPClient::get(url, new GetUpdateInfoResponder(type)); } } diff --git a/indra/newview/skins/default/textures/Blank.png b/indra/newview/skins/default/textures/Blank.png new file mode 100644 index 000000000..f38e9f910 Binary files /dev/null and b/indra/newview/skins/default/textures/Blank.png differ diff --git a/indra/newview/skins/default/textures/FMOD Logo.png b/indra/newview/skins/default/textures/FMOD Logo.png new file mode 100644 index 000000000..3ddda90e2 Binary files /dev/null and b/indra/newview/skins/default/textures/FMOD Logo.png differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_experiences.tga b/indra/newview/skins/default/textures/icn_toolbar_experiences.tga new file mode 100644 index 000000000..0a1a235f3 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_experiences.tga differ diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index 6e7f64881..e91c1b3c3 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -57,6 +57,8 @@ with the same filename but different name + + @@ -297,6 +299,8 @@ with the same filename but different name + + @@ -371,6 +375,8 @@ with the same filename but different name + + diff --git a/indra/newview/skins/default/xui/de/floater_report_abuse.xml b/indra/newview/skins/default/xui/de/floater_report_abuse.xml index a91e1dc47..9dd2b1dc4 100644 --- a/indra/newview/skins/default/xui/de/floater_report_abuse.xml +++ b/indra/newview/skins/default/xui/de/floater_report_abuse.xml @@ -1,7 +1,9 @@ Foto - + Belästigung > Nutzer leckt wiederholt Finger und berührt mich + Land > Anmaßung > Nutzer will nicht auf seiner Seite des Fahrzeug bleiben + Freud > Nutzer bekundet Interesse an Ihrer Mutter Melder: Loremipsum Dolorsitamut diff --git a/indra/newview/skins/default/xui/de/menu_radar.xml b/indra/newview/skins/default/xui/de/menu_radar.xml index 9f3510a2d..836611bb9 100644 --- a/indra/newview/skins/default/xui/de/menu_radar.xml +++ b/indra/newview/skins/default/xui/de/menu_radar.xml @@ -25,7 +25,6 @@ - diff --git a/indra/newview/skins/default/xui/de/mime_types_linux.xml b/indra/newview/skins/default/xui/de/mime_types_linux.xml index 9ef29c407..1b16f6c08 100644 --- a/indra/newview/skins/default/xui/de/mime_types_linux.xml +++ b/indra/newview/skins/default/xui/de/mime_types_linux.xml @@ -2,7 +2,7 @@ (unbekannt) keine - media_plugin_webkit + media_plugin_cef icn_media_web.tga @@ -47,12 +47,12 @@ keine - media_plugin_webkit + media_plugin_cef keine - media_plugin_webkit + media_plugin_cef @@ -67,7 +67,7 @@ Bild - media_plugin_webkit + media_plugin_cef @@ -77,7 +77,7 @@ Web - media_plugin_webkit + media_plugin_cef @@ -87,32 +87,32 @@ Bild - media_plugin_webkit + media_plugin_cef Bild - media_plugin_webkit + media_plugin_cef Bild - media_plugin_webkit + media_plugin_cef Film - media_plugin_webkit + media_plugin_cef Web - media_plugin_webkit + media_plugin_cef Bild - media_plugin_webkit + media_plugin_cef @@ -137,47 +137,47 @@ Bild - media_plugin_webkit + media_plugin_cef Bild - media_plugin_webkit + media_plugin_cef Bild - media_plugin_webkit + media_plugin_cef Bild - media_plugin_webkit + media_plugin_cef Bild - media_plugin_webkit + media_plugin_cef Bild - media_plugin_webkit + media_plugin_cef Web - media_plugin_webkit + media_plugin_cef text - media_plugin_webkit + media_plugin_cef text - media_plugin_webkit + media_plugin_cef @@ -189,8 +189,8 @@ Film media_plugin_gstreamer - - + + Film media_plugin_gstreamer diff --git a/indra/newview/skins/default/xui/de/mime_types_mac.xml b/indra/newview/skins/default/xui/de/mime_types_mac.xml index 8836f42c6..662b416f2 100644 --- a/indra/newview/skins/default/xui/de/mime_types_mac.xml +++ b/indra/newview/skins/default/xui/de/mime_types_mac.xml @@ -2,7 +2,7 @@ (unbekannt) keine - media_plugin_webkit + media_plugin_cef icn_media_web.tga @@ -52,7 +52,7 @@ keine - media_plugin_webkit + media_plugin_cef @@ -67,7 +67,7 @@ Bild - media_plugin_webkit + media_plugin_cef @@ -77,7 +77,7 @@ Web - media_plugin_webkit + media_plugin_cef @@ -87,32 +87,32 @@ Bild - media_plugin_webkit + media_plugin_cef Bild - media_plugin_webkit + media_plugin_cef Bild - media_plugin_webkit + media_plugin_cef Film - media_plugin_webkit + media_plugin_cef Web - media_plugin_webkit + media_plugin_cef Bild - media_plugin_webkit + media_plugin_cef @@ -137,47 +137,47 @@ Bild - media_plugin_webkit + media_plugin_cef Bild - media_plugin_webkit + media_plugin_cef Bild - media_plugin_webkit + media_plugin_cef Bild - media_plugin_webkit + media_plugin_cef Bild - media_plugin_webkit + media_plugin_cef Bild - media_plugin_webkit + media_plugin_cef Web - media_plugin_webkit + media_plugin_cef text - media_plugin_webkit + media_plugin_cef text - media_plugin_webkit + media_plugin_cef @@ -189,8 +189,8 @@ Film media_plugin_libvlc - - + + Film media_plugin_libvlc diff --git a/indra/newview/skins/default/xui/de/mime_types_windows.xml b/indra/newview/skins/default/xui/de/mime_types_windows.xml index 378021609..83288c3ee 100644 --- a/indra/newview/skins/default/xui/de/mime_types_windows.xml +++ b/indra/newview/skins/default/xui/de/mime_types_windows.xml @@ -2,7 +2,7 @@ (unbekannt) keine - media_plugin_webkit + media_plugin_cef icn_media_web.tga @@ -47,12 +47,12 @@ keine - media_plugin_webkit + media_plugin_cef keine - media_plugin_webkit + media_plugin_cef @@ -67,7 +67,7 @@ Bild - media_plugin_webkit + media_plugin_cef @@ -77,7 +77,7 @@ Web - media_plugin_webkit + media_plugin_cef @@ -87,32 +87,32 @@ Bild - media_plugin_webkit + media_plugin_cef Bild - media_plugin_webkit + media_plugin_cef Bild - media_plugin_webkit + media_plugin_cef Film - media_plugin_webkit + media_plugin_cef Web - media_plugin_webkit + media_plugin_cef Bild - media_plugin_webkit + media_plugin_cef @@ -137,47 +137,47 @@ Bild - media_plugin_webkit + media_plugin_cef Bild - media_plugin_webkit + media_plugin_cef Bild - media_plugin_webkit + media_plugin_cef Bild - media_plugin_webkit + media_plugin_cef Bild - media_plugin_webkit + media_plugin_cef Bild - media_plugin_webkit + media_plugin_cef Web - media_plugin_webkit + media_plugin_cef text - media_plugin_webkit + media_plugin_cef text - media_plugin_webkit + media_plugin_cef @@ -189,8 +189,8 @@ Film media_plugin_libvlc - - + + Film media_plugin_libvlc diff --git a/indra/newview/skins/default/xui/de/notifications.xml b/indra/newview/skins/default/xui/de/notifications.xml index c876d0ea9..8de81768d 100644 --- a/indra/newview/skins/default/xui/de/notifications.xml +++ b/indra/newview/skins/default/xui/de/notifications.xml @@ -2406,7 +2406,10 @@ Klicken Sie auf „Akzeptieren“, um dem Chat beizutreten, oder auf & Mehrere SLurls wurden von einem nicht vertrauten Browser innerhalb einer kurzen Zeitspanne empfangen. Sie wurden aus Sicherheitsgründen geblockt für ein paar Minuten.Sicherheit - Die Region, die Sie betreten haben, verwendet eine andere Simulatorversion. Klicken Sie auf diese Nachricht, um weitere Informationen zu erhalten. + Die Region, die Sie betreten haben, verwendet eine andere Simulatorversion. +Current simulator: [NEW_VERSION] +Previous simulator: [OLD_VERSION] + Server Fehler: Media update oder download fehlgeschlagen. '[ERROR]'fehlgeschlagen diff --git a/indra/newview/skins/default/xui/de/panel_preferences_ascent_vanity.xml b/indra/newview/skins/default/xui/de/panel_preferences_ascent_vanity.xml index c403b9c11..3a170dae1 100644 --- a/indra/newview/skins/default/xui/de/panel_preferences_ascent_vanity.xml +++ b/indra/newview/skins/default/xui/de/panel_preferences_ascent_vanity.xml @@ -11,7 +11,6 @@ - diff --git a/indra/newview/skins/default/xui/en-us/floater_about.xml b/indra/newview/skins/default/xui/en-us/floater_about.xml index 6d84f026c..2d39317cf 100644 --- a/indra/newview/skins/default/xui/en-us/floater_about.xml +++ b/indra/newview/skins/default/xui/en-us/floater_about.xml @@ -5,15 +5,15 @@ title="About [SHORT_APP_NAME]" width="470"> - + - + + + + + Script: + + + Associated with: + + + You can contribute: + + + Associate with: + + + + + + EasySit Animator 1.2.4 + + + Kyle's Superhero RPG + + + Yes + + + + + + You are not a contributor to any experiences. + + diff --git a/indra/newview/skins/default/xui/en-us/panel_toolbar.xml b/indra/newview/skins/default/xui/en-us/panel_toolbar.xml index 069b308b2..69883f018 100644 --- a/indra/newview/skins/default/xui/en-us/panel_toolbar.xml +++ b/indra/newview/skins/default/xui/en-us/panel_toolbar.xml @@ -145,6 +145,11 @@ + + + - - - + + +