Added viewer-release.release-viewer.jira parameter to write build comment to DRTVWR-13
commit
5bfa6095db
8
.hgtags
8
.hgtags
|
|
@ -29,4 +29,12 @@ c6e6324f5be1401f077ad18a4a0f6b46451c2f7b last_sprint
|
|||
9822eb3e25f7fe0c28ffd8aba45c507caa383cbc 2.2.0-beta2
|
||||
b0cd7e150009809a0b5b0a9d5785cd4bb230413a 2.2.0-beta3
|
||||
00a831292231faad7e44c69f76cb96f175b8dfad 2.2.0-beta4
|
||||
<<<<<<< /var/tmp/dessie/hg/viewer-release/.hgtags
|
||||
1415e6538d54fd5d568ee88343424d57c6803c2c 2.2.0-release
|
||||
=======
|
||||
1415e6538d54fd5d568ee88343424d57c6803c2c 2.2.0-release
|
||||
98e0d6df638429fd2f0476667504bd5a6b298def 2.3.0-start
|
||||
a3c12342b1af0951b8aa3b828aacef17fcea8178 2.3.0-beta1
|
||||
db0fe9bb65187f365e58a717dd23d0f4754a9c1d 2.3.0-beta2
|
||||
6ad3d6fa35a4e320e9ce442fce2bf9c7fc852556 2.3.0-beta3
|
||||
>>>>>>> /tmp/.hgtags~other.m_FhNW
|
||||
|
|
|
|||
22
BuildParams
22
BuildParams
|
|
@ -51,6 +51,7 @@ viewer-release.viewer_channel = "Second Life Release"
|
|||
viewer-release.login_channel = "Second Life Release"
|
||||
viewer-release.build_debug_release_separately = true
|
||||
viewer-release.build_viewer_update_version_manager = true
|
||||
viewer-release.release-viewer.jira = DRTVWR-13
|
||||
|
||||
# ========================================
|
||||
# aimee
|
||||
|
|
@ -86,6 +87,7 @@ brad-parabuild.build_server_tests = false
|
|||
|
||||
cg_viewer-development_lenny.collect_metrics = true
|
||||
cg_viewer-development_lenny.show_changes_since = 4b140ce7839d
|
||||
cg_viewer-development_lenny.email = cg@lindenlab.com
|
||||
|
||||
# ========================================
|
||||
# gooey
|
||||
|
|
@ -101,6 +103,26 @@ gooey.login_channel = "Second Life Alpha"
|
|||
gooey.viewer_grid = agni
|
||||
gooey.build_viewer_update_version_manager = false
|
||||
|
||||
# ========================================
|
||||
# Display Names project
|
||||
# ========================================
|
||||
|
||||
#viewer-identity-evolution.email = leyla@lindenlab.com
|
||||
viewer-identity.build_Debug = false
|
||||
viewer-identity.build_RelWithDebInfo = false
|
||||
viewer-identity.build_viewer = true
|
||||
viewer-identity.build_server = false
|
||||
viewer-identity.build_server_tests = false
|
||||
viewer-identity.build_Linux = true
|
||||
viewer-identity.build_hg_bundle = true
|
||||
viewer-identity.bulld_docs = true
|
||||
viewer-identity.viewer_channel = "Second Life Project Viewer"
|
||||
viewer-identity.login_channel = "Second Life Project Viewer"
|
||||
viewer-identity.viewer_grid = aditi
|
||||
viewer-identity.build_viewer_update_version_manager = false
|
||||
|
||||
|
||||
|
||||
# ========================================
|
||||
# palange
|
||||
# ========================================
|
||||
|
|
|
|||
8
build.sh
8
build.sh
|
|
@ -59,6 +59,7 @@ pre_build()
|
|||
-t $variant \
|
||||
-G "$cmake_generator" \
|
||||
configure \
|
||||
-DGRID:STRING="$viewer_grid" \
|
||||
-DVIEWER_CHANNEL:STRING="$viewer_channel" \
|
||||
-DVIEWER_LOGIN_CHANNEL:STRING="$login_channel" \
|
||||
-DINSTALL_PROPRIETARY:BOOL=ON \
|
||||
|
|
@ -114,11 +115,15 @@ then
|
|||
if [ -x "$top/../buildscripts/hg/bin/build.sh" ]
|
||||
then
|
||||
exec "$top/../buildscripts/hg/bin/build.sh" "$top"
|
||||
elif [ -r "$top/README" ]
|
||||
then
|
||||
cat "$top/README"
|
||||
exit 1
|
||||
else
|
||||
cat <<EOF
|
||||
This script, if called in a development environment, requires that the branch
|
||||
independent build script repository be checked out next to this repository.
|
||||
This repository is located at http://hg.lindenlab.com/parabuild/buildscripts
|
||||
This repository is located at http://hg.secondlife.com/buildscripts
|
||||
EOF
|
||||
exit 1
|
||||
fi
|
||||
|
|
@ -284,6 +289,7 @@ then
|
|||
succeeded=$build_coverity
|
||||
else
|
||||
upload_item installer "$package" binary/octet-stream
|
||||
upload_item quicklink "$package" binary/octet-stream
|
||||
|
||||
# Upload crash reporter files.
|
||||
case "$last_built_variant" in
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ Aimee Trescothick
|
|||
SNOW-227
|
||||
SNOW-570
|
||||
SNOW-572
|
||||
SNOW-575
|
||||
VWR-3321
|
||||
VWR-3336
|
||||
VWR-3903
|
||||
|
|
@ -33,6 +34,7 @@ Aimee Trescothick
|
|||
VWR-6550
|
||||
VWR-6583
|
||||
VWR-6482
|
||||
VWR-6918
|
||||
VWR-7109
|
||||
VWR-7383
|
||||
VWR-7800
|
||||
|
|
@ -59,13 +61,18 @@ Aimee Trescothick
|
|||
Alejandro Rosenthal
|
||||
VWR-1184
|
||||
Aleric Inglewood
|
||||
SNOW-522
|
||||
SNOW-756
|
||||
SNOW-764
|
||||
VWR-10001
|
||||
VWR-10759
|
||||
VWR-10837
|
||||
VWR-12691
|
||||
VWR-13996
|
||||
VWR-14426
|
||||
SNOW-84
|
||||
SNOW-766
|
||||
STORM-163
|
||||
Ales Beaumont
|
||||
VWR-9352
|
||||
SNOW-240
|
||||
|
|
@ -165,6 +172,7 @@ Boroondas Gupte
|
|||
SNOW-737
|
||||
VWR-233
|
||||
VWR-20583
|
||||
VWR-20891
|
||||
WEB-262
|
||||
Bulli Schumann
|
||||
CT-218
|
||||
|
|
@ -381,6 +389,7 @@ Matthew Dowd
|
|||
VWR-1761
|
||||
VWR-2681
|
||||
McCabe Maxsted
|
||||
SNOW-387
|
||||
VWR-1318
|
||||
VWR-4065
|
||||
VWR-4826
|
||||
|
|
@ -541,14 +550,18 @@ Ringo Tuxing
|
|||
Robin Cornelius
|
||||
SNOW-108
|
||||
SNOW-204
|
||||
SNOW-287
|
||||
SNOW-484
|
||||
SNOW-504
|
||||
SNOW-506
|
||||
SNOW-507
|
||||
SNOW-511
|
||||
SNOW-512
|
||||
SNOW-514
|
||||
SNOW-520
|
||||
SNOW-585
|
||||
SNOW-599
|
||||
SNOW-747
|
||||
VWR-2488
|
||||
VWR-9557
|
||||
VWR-11128
|
||||
|
|
@ -557,6 +570,7 @@ Robin Cornelius
|
|||
VWR-12758
|
||||
VWR-12763
|
||||
VWR-12995
|
||||
VWR-20911
|
||||
Ryozu Kojima
|
||||
VWR-53
|
||||
VWR-287
|
||||
|
|
@ -646,12 +660,19 @@ Teardrops Fall
|
|||
VWR-5366
|
||||
Techwolf Lupindo
|
||||
SNOW-92
|
||||
SNOW-592
|
||||
SNOW-649
|
||||
SNOW-650
|
||||
SNOW-651
|
||||
SNOW-654
|
||||
SNOW-687
|
||||
SNOW-680
|
||||
SNOW-681
|
||||
SNOW-685
|
||||
SNOW-690
|
||||
SNOW-746
|
||||
VWR-12385
|
||||
VWR-20893
|
||||
tenebrous pau
|
||||
VWR-247
|
||||
Tharax Ferraris
|
||||
|
|
@ -661,8 +682,9 @@ Thickbrick Sleaford
|
|||
SNOW-390
|
||||
SNOW-421
|
||||
SNOW-462
|
||||
SNOW-635
|
||||
SNOW-586
|
||||
SNOW-592
|
||||
SNOW-635
|
||||
SNOW-743
|
||||
VWR-7109
|
||||
VWR-9287
|
||||
|
|
|
|||
|
|
@ -370,6 +370,14 @@
|
|||
</map>
|
||||
|
||||
<!-- Server to client -->
|
||||
<key>DisplayNameUpdate</key>
|
||||
<map>
|
||||
<key>flavor</key>
|
||||
<string>llsd</string>
|
||||
<key>trusted-sender</key>
|
||||
<boolean>true</boolean>
|
||||
</map>
|
||||
|
||||
<key>ParcelVoiceInfo</key>
|
||||
<map>
|
||||
<key>flavor</key>
|
||||
|
|
@ -426,6 +434,14 @@
|
|||
<boolean>true</boolean>
|
||||
</map>
|
||||
|
||||
<key>SetDisplayNameReply</key>
|
||||
<map>
|
||||
<key>flavor</key>
|
||||
<string>llsd</string>
|
||||
<key>trusted-sender</key>
|
||||
<boolean>true</boolean>
|
||||
</map>
|
||||
|
||||
<key>DirLandReply</key>
|
||||
<map>
|
||||
<key>flavor</key>
|
||||
|
|
|
|||
|
|
@ -123,6 +123,8 @@ if (SERVER)
|
|||
endif (WINDOWS)
|
||||
endif (SERVER)
|
||||
|
||||
# Define after the custom viewer and server targets are created so individual
|
||||
# apps can add themselves as dependencies
|
||||
add_subdirectory(${INTEGRATION_TESTS_PREFIX}integration_tests)
|
||||
if (LL_TESTS)
|
||||
# Define after the custom viewer and server targets are created so
|
||||
# individual apps can add themselves as dependencies
|
||||
add_subdirectory(${INTEGRATION_TESTS_PREFIX}integration_tests)
|
||||
endif (LL_TESTS)
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ set(cmake_SOURCE_FILES
|
|||
FindBerkeleyDB.cmake
|
||||
FindCARes.cmake
|
||||
FindELFIO.cmake
|
||||
FindFMOD.cmake
|
||||
FindGooglePerfTools.cmake
|
||||
FindMono.cmake
|
||||
FindMT.cmake
|
||||
|
|
|
|||
|
|
@ -55,9 +55,10 @@ if(WINDOWS)
|
|||
set(release_files ${release_files} libtcmalloc_minimal.dll)
|
||||
endif(USE_GOOGLE_PERFTOOLS)
|
||||
|
||||
if (FMOD_SDK_DIR)
|
||||
set(fmod_files fmod.dll)
|
||||
endif (FMOD_SDK_DIR)
|
||||
if (FMOD)
|
||||
set(debug_files ${debug_files} fmod.dll)
|
||||
set(release_files ${release_files} fmod.dll)
|
||||
endif (FMOD)
|
||||
|
||||
#*******************************
|
||||
# LLKDU
|
||||
|
|
@ -237,9 +238,9 @@ elseif(LINUX)
|
|||
libssl.so.0.9.7
|
||||
)
|
||||
|
||||
if (FMOD_SDK_DIR)
|
||||
set(fmod_files "libfmod-3.75.so")
|
||||
endif (FMOD_SDK_DIR)
|
||||
if (FMOD)
|
||||
set(release_files ${release_files} "libfmod-3.75.so")
|
||||
endif (FMOD)
|
||||
|
||||
#*******************************
|
||||
# LLKDU
|
||||
|
|
@ -333,30 +334,6 @@ copy_if_different(
|
|||
)
|
||||
set(third_party_targets ${third_party_targets} ${out_targets})
|
||||
|
||||
if (FMOD_SDK_DIR)
|
||||
copy_if_different(
|
||||
${FMOD_SDK_DIR}
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/Debug"
|
||||
out_targets
|
||||
${fmod_files}
|
||||
)
|
||||
set(all_targets ${all_targets} ${out_targets})
|
||||
copy_if_different(
|
||||
${FMOD_SDK_DIR}
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/Release"
|
||||
out_targets
|
||||
${fmod_files}
|
||||
)
|
||||
set(all_targets ${all_targets} ${out_targets})
|
||||
copy_if_different(
|
||||
${FMOD_SDK_DIR}
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/RelWithDbgInfo"
|
||||
out_targets
|
||||
${fmod_files}
|
||||
)
|
||||
set(all_targets ${all_targets} ${out_targets})
|
||||
endif (FMOD_SDK_DIR)
|
||||
|
||||
#*******************************
|
||||
# LLKDU
|
||||
set(internal_llkdu_path "${CMAKE_SOURCE_DIR}/llkdu")
|
||||
|
|
|
|||
|
|
@ -1,64 +1,24 @@
|
|||
# -*- cmake -*-
|
||||
|
||||
include(Linking)
|
||||
|
||||
if(INSTALL_PROPRIETARY)
|
||||
include(Prebuilt)
|
||||
use_prebuilt_binary(fmod)
|
||||
endif(INSTALL_PROPRIETARY)
|
||||
|
||||
find_library(FMOD_LIBRARY_RELEASE
|
||||
NAMES fmod fmodvc fmod-3.75
|
||||
PATHS
|
||||
${ARCH_PREBUILT_DIRS_RELEASE}
|
||||
)
|
||||
|
||||
find_library(FMOD_LIBRARY_DEBUG
|
||||
NAMES fmod fmodvc fmod-3.75
|
||||
PATHS
|
||||
${ARCH_PREBUILT_DIRS_DEBUG}
|
||||
)
|
||||
|
||||
if (FMOD_LIBRARY_RELEASE AND FMOD_LIBRARY_DEBUG)
|
||||
set(FMOD_LIBRARY
|
||||
debug ${FMOD_LIBRARY_DEBUG}
|
||||
optimized ${FMOD_LIBRARY_RELEASE})
|
||||
elseif (FMOD_LIBRARY_RELEASE)
|
||||
set(FMOD_LIBRARY ${FMOD_LIBRARY_RELEASE})
|
||||
endif (FMOD_LIBRARY_RELEASE AND FMOD_LIBRARY_DEBUG)
|
||||
|
||||
if (NOT FMOD_LIBRARY)
|
||||
set(FMOD_SDK_DIR CACHE PATH "Path to the FMOD SDK.")
|
||||
if (FMOD_SDK_DIR)
|
||||
find_library(FMOD_LIBRARY
|
||||
NAMES fmodvc fmod-3.75 fmod
|
||||
PATHS
|
||||
${FMOD_SDK_DIR}/api/lib
|
||||
${FMOD_SDK_DIR}/api
|
||||
${FMOD_SDK_DIR}/lib
|
||||
${FMOD_SDK_DIR}
|
||||
)
|
||||
endif (FMOD_SDK_DIR)
|
||||
endif (NOT FMOD_LIBRARY)
|
||||
|
||||
find_path(FMOD_INCLUDE_DIR fmod.h
|
||||
${LIBS_PREBUILT_DIR}/include
|
||||
${FMOD_SDK_DIR}/api/inc
|
||||
${FMOD_SDK_DIR}/inc
|
||||
${FMOD_SDK_DIR}
|
||||
)
|
||||
|
||||
if (FMOD_LIBRARY AND FMOD_INCLUDE_DIR)
|
||||
set(FMOD ON CACHE BOOL "Use closed source FMOD sound library.")
|
||||
else (FMOD_LIBRARY AND FMOD_INCLUDE_DIR)
|
||||
set(FMOD_LIBRARY "")
|
||||
set(FMOD_INCLUDE_DIR "")
|
||||
if (FMOD)
|
||||
message(STATUS "No support for FMOD audio (need to set FMOD_SDK_DIR?)")
|
||||
endif (FMOD)
|
||||
set(FMOD OFF CACHE BOOL "Use closed source FMOD sound library.")
|
||||
endif (FMOD_LIBRARY AND FMOD_INCLUDE_DIR)
|
||||
set(FMOD ON CACHE BOOL "Use FMOD sound library.")
|
||||
|
||||
if (FMOD)
|
||||
message(STATUS "Building with FMOD audio support")
|
||||
if (STANDALONE)
|
||||
set(FMOD_FIND_REQUIRED ON)
|
||||
include(FindFMOD)
|
||||
else (STANDALONE)
|
||||
include(Prebuilt)
|
||||
use_prebuilt_binary(fmod)
|
||||
|
||||
if (WINDOWS)
|
||||
set(FMOD_LIBRARY fmod)
|
||||
elseif (DARWIN)
|
||||
set(FMOD_LIBRARY fmod)
|
||||
elseif (LINUX)
|
||||
set(FMOD_LIBRARY fmod-3.75)
|
||||
endif (WINDOWS)
|
||||
|
||||
SET(FMOD_LIBRARIES ${FMOD_LIBRARY})
|
||||
set(FMOD_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include)
|
||||
endif (STANDALONE)
|
||||
endif (FMOD)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
# -*- cmake -*-
|
||||
|
||||
# - Find FMOD
|
||||
# Find the FMOD includes and library
|
||||
# This module defines
|
||||
# FMOD_INCLUDE_DIR, where to find fmod.h and fmod_errors.h
|
||||
# FMOD_LIBRARIES, the libraries needed to use FMOD.
|
||||
# FMOD, If false, do not try to use FMOD.
|
||||
# also defined, but not for general use are
|
||||
# FMOD_LIBRARY, where to find the FMOD library.
|
||||
|
||||
FIND_PATH(FMOD_INCLUDE_DIR fmod.h PATH_SUFFIXES fmod)
|
||||
|
||||
SET(FMOD_NAMES ${FMOD_NAMES} fmod fmodvc fmod-3.75)
|
||||
FIND_LIBRARY(FMOD_LIBRARY
|
||||
NAMES ${FMOD_NAMES}
|
||||
PATH_SUFFIXES fmod
|
||||
)
|
||||
|
||||
IF (FMOD_LIBRARY AND FMOD_INCLUDE_DIR)
|
||||
SET(FMOD_LIBRARIES ${FMOD_LIBRARY})
|
||||
SET(FMOD_FOUND "YES")
|
||||
ELSE (FMOD_LIBRARY AND FMOD_INCLUDE_DIR)
|
||||
SET(FMOD_FOUND "NO")
|
||||
ENDIF (FMOD_LIBRARY AND FMOD_INCLUDE_DIR)
|
||||
|
||||
IF (FMOD_FOUND)
|
||||
IF (NOT FMOD_FIND_QUIETLY)
|
||||
MESSAGE(STATUS "Found FMOD: ${FMOD_LIBRARIES}")
|
||||
ENDIF (NOT FMOD_FIND_QUIETLY)
|
||||
ELSE (FMOD_FOUND)
|
||||
IF (FMOD_FIND_REQUIRED)
|
||||
MESSAGE(FATAL_ERROR "Could not find FMOD library")
|
||||
ENDIF (FMOD_FIND_REQUIRED)
|
||||
ENDIF (FMOD_FOUND)
|
||||
|
||||
# Deprecated declarations.
|
||||
SET (NATIVE_FMOD_INCLUDE_PATH ${FMOD_INCLUDE_DIR} )
|
||||
GET_FILENAME_COMPONENT (NATIVE_FMOD_LIB_PATH ${FMOD_LIBRARY} PATH)
|
||||
|
||||
MARK_AS_ADVANCED(
|
||||
FMOD_LIBRARY
|
||||
FMOD_INCLUDE_DIR
|
||||
)
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
# -*- cmake -*-
|
||||
|
||||
# - Find Google BreakPad
|
||||
# Find the Google BreakPad includes and library
|
||||
# This module defines
|
||||
# BREAKPAD_EXCEPTION_HANDLER_INCLUDE_DIR, where to find exception_handler.h, etc.
|
||||
# BREAKPAD_EXCEPTION_HANDLER_LIBRARIES, the libraries needed to use Google BreakPad.
|
||||
# BREAKPAD_EXCEPTION_HANDLER_FOUND, If false, do not try to use Google BreakPad.
|
||||
# also defined, but not for general use are
|
||||
# BREAKPAD_EXCEPTION_HANDLER_LIBRARY, where to find the Google BreakPad library.
|
||||
|
||||
FIND_PATH(BREAKPAD_EXCEPTION_HANDLER_INCLUDE_DIR google_breakpad/exception_handler.h)
|
||||
|
||||
SET(BREAKPAD_EXCEPTION_HANDLER_NAMES ${BREAKPAD_EXCEPTION_HANDLER_NAMES} breakpad_client)
|
||||
FIND_LIBRARY(BREAKPAD_EXCEPTION_HANDLER_LIBRARY
|
||||
NAMES ${BREAKPAD_EXCEPTION_HANDLER_NAMES}
|
||||
)
|
||||
|
||||
IF (BREAKPAD_EXCEPTION_HANDLER_LIBRARY AND BREAKPAD_EXCEPTION_HANDLER_INCLUDE_DIR)
|
||||
SET(BREAKPAD_EXCEPTION_HANDLER_LIBRARIES ${BREAKPAD_EXCEPTION_HANDLER_LIBRARY})
|
||||
SET(BREAKPAD_EXCEPTION_HANDLER_FOUND "YES")
|
||||
ELSE (BREAKPAD_EXCEPTION_HANDLER_LIBRARY AND BREAKPAD_EXCEPTION_HANDLER_INCLUDE_DIR)
|
||||
SET(BREAKPAD_EXCEPTION_HANDLER_FOUND "NO")
|
||||
ENDIF (BREAKPAD_EXCEPTION_HANDLER_LIBRARY AND BREAKPAD_EXCEPTION_HANDLER_INCLUDE_DIR)
|
||||
|
||||
|
||||
IF (BREAKPAD_EXCEPTION_HANDLER_FOUND)
|
||||
IF (NOT BREAKPAD_EXCEPTION_HANDLER_FIND_QUIETLY)
|
||||
MESSAGE(STATUS "Found Google BreakPad: ${BREAKPAD_EXCEPTION_HANDLER_LIBRARIES}")
|
||||
ENDIF (NOT BREAKPAD_EXCEPTION_HANDLER_FIND_QUIETLY)
|
||||
ELSE (BREAKPAD_EXCEPTION_HANDLER_FOUND)
|
||||
IF (BREAKPAD_EXCEPTION_HANDLER_FIND_REQUIRED)
|
||||
MESSAGE(FATAL_ERROR "Could not find Google BreakPad library")
|
||||
ENDIF (BREAKPAD_EXCEPTION_HANDLER_FIND_REQUIRED)
|
||||
ENDIF (BREAKPAD_EXCEPTION_HANDLER_FOUND)
|
||||
|
||||
MARK_AS_ADVANCED(
|
||||
BREAKPAD_EXCEPTION_HANDLER_LIBRARY
|
||||
BREAKPAD_EXCEPTION_HANDLER_INCLUDE_DIR
|
||||
)
|
||||
|
|
@ -2,8 +2,8 @@
|
|||
include(Prebuilt)
|
||||
|
||||
if (STANDALONE)
|
||||
MESSAGE(FATAL_ERROR "*TODO standalone support for google breakad is unimplemented")
|
||||
# *TODO - implement this include(FindGoogleBreakpad)
|
||||
set(BREAKPAD_EXCEPTION_HANDLER_FIND_REQUIRED ON)
|
||||
include(FindGoogleBreakpad)
|
||||
else (STANDALONE)
|
||||
use_prebuilt_binary(google_breakpad)
|
||||
if (DARWIN)
|
||||
|
|
|
|||
|
|
@ -256,6 +256,10 @@ MACRO(SET_TEST_PATH LISTVAR)
|
|||
set(${LISTVAR} ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/Resources ${SHARED_LIB_STAGING_DIR}/Release/Resources /usr/lib)
|
||||
ELSE(WINDOWS)
|
||||
# Linux uses a single staging directory anyway.
|
||||
set(${LISTVAR} ${SHARED_LIB_STAGING_DIR} /usr/lib)
|
||||
IF (STANDALONE)
|
||||
set(${LISTVAR} ${CMAKE_BINARY_DIR}/llcommon /usr/lib /usr/local/lib)
|
||||
ELSE (STANDALONE)
|
||||
set(${LISTVAR} ${SHARED_LIB_STAGING_DIR} /usr/lib)
|
||||
ENDIF (STANDALONE)
|
||||
ENDIF(WINDOWS)
|
||||
ENDMACRO(SET_TEST_PATH)
|
||||
|
|
|
|||
|
|
@ -1,28 +1,28 @@
|
|||
# -*- cmake -*-
|
||||
include(Prebuilt)
|
||||
|
||||
if (STANDALONE)
|
||||
include(FindPkgConfig)
|
||||
|
||||
pkg_check_modules(PULSEAUDIO REQUIRED libpulse-mainloop-glib)
|
||||
|
||||
elseif (LINUX)
|
||||
use_prebuilt_binary(pulseaudio)
|
||||
set(PULSEAUDIO_FOUND ON FORCE BOOL)
|
||||
set(PULSEAUDIO_INCLUDE_DIRS
|
||||
${LIBS_PREBUILT_DIR}/include
|
||||
)
|
||||
# We don't need to explicitly link against pulseaudio itself, because
|
||||
# the viewer probes for the system's copy at runtime.
|
||||
set(PULSEAUDIO_LIBRARIES
|
||||
# none needed!
|
||||
)
|
||||
endif (STANDALONE)
|
||||
|
||||
if (PULSEAUDIO_FOUND)
|
||||
set(PULSEAUDIO ON CACHE BOOL "Build with PulseAudio support, if available.")
|
||||
endif (PULSEAUDIO_FOUND)
|
||||
set(PULSEAUDIO ON CACHE BOOL "Build with PulseAudio support, if available.")
|
||||
|
||||
if (PULSEAUDIO)
|
||||
add_definitions(-DLL_PULSEAUDIO_ENABLED=1)
|
||||
if (STANDALONE)
|
||||
include(FindPkgConfig)
|
||||
|
||||
pkg_check_modules(PULSEAUDIO libpulse)
|
||||
|
||||
elseif (LINUX)
|
||||
use_prebuilt_binary(pulseaudio)
|
||||
set(PULSEAUDIO_FOUND ON FORCE BOOL)
|
||||
set(PULSEAUDIO_INCLUDE_DIRS
|
||||
${LIBS_PREBUILT_DIR}/include
|
||||
)
|
||||
# We don't need to explicitly link against pulseaudio itself, because
|
||||
# the viewer probes for the system's copy at runtime.
|
||||
set(PULSEAUDIO_LIBRARIES
|
||||
# none needed!
|
||||
)
|
||||
endif (STANDALONE)
|
||||
endif (PULSEAUDIO)
|
||||
|
||||
if (PULSEAUDIO_FOUND)
|
||||
add_definitions(-DLL_PULSEAUDIO_ENABLED=1)
|
||||
endif (PULSEAUDIO_FOUND)
|
||||
|
|
|
|||
|
|
@ -54,19 +54,20 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
|||
set(LINUX ON BOOl FORCE)
|
||||
|
||||
# If someone has specified a word size, use that to determine the
|
||||
# architecture. Otherwise, let the architecture specify the word size.
|
||||
# architecture. Otherwise, let the compiler specify the word size.
|
||||
# Using uname will break under chroots and other cross arch compiles. RC
|
||||
if (WORD_SIZE EQUAL 32)
|
||||
set(ARCH i686)
|
||||
elseif (WORD_SIZE EQUAL 64)
|
||||
set(ARCH x86_64)
|
||||
else (WORD_SIZE EQUAL 32)
|
||||
execute_process(COMMAND uname -m COMMAND sed s/i.86/i686/
|
||||
OUTPUT_VARIABLE ARCH OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
if (ARCH STREQUAL x86_64)
|
||||
set(WORD_SIZE 64)
|
||||
else (ARCH STREQUAL x86_64)
|
||||
if(CMAKE_SIZEOF_VOID_P MATCHES 4)
|
||||
set(ARCH i686)
|
||||
set(WORD_SIZE 32)
|
||||
endif (ARCH STREQUAL x86_64)
|
||||
else(CMAKE_SIZEOF_VOID_P MATCHES 4)
|
||||
set(ARCH x86_64)
|
||||
set(WORD_SIZE 64)
|
||||
endif(CMAKE_SIZEOF_VOID_P MATCHES 4)
|
||||
endif (WORD_SIZE EQUAL 32)
|
||||
|
||||
set(LL_ARCH ${ARCH}_linux)
|
||||
|
|
@ -86,7 +87,7 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
|||
if (NOT CMAKE_OSX_DEPLOYMENT_TARGET)
|
||||
# NOTE: setting -isysroot is NOT adequate: http://lists.apple.com/archives/Xcode-users/2007/Oct/msg00696.html
|
||||
# see http://public.kitware.com/Bug/view.php?id=9959 + poppy
|
||||
set(CMAKE_OSX_SYSROOT /Developer/SDKs/MacOSX10.4u.sdk)
|
||||
set(CMAKE_OSX_SYSROOT /Developer/SDKs/MacOSX10.5.sdk)
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.4)
|
||||
endif (NOT CMAKE_OSX_DEPLOYMENT_TARGET)
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ myprog somearg otherarg
|
|||
|
||||
$LicenseInfo:firstyear=2009&license=viewerlgpl$
|
||||
Second Life Viewer Source Code
|
||||
Copyright (C) 2010, Linden Research, Inc.
|
||||
Copyright (C) 2009-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
|
||||
|
|
|
|||
|
|
@ -185,10 +185,9 @@ void export_test_floaters()
|
|||
// Build a floater and output new attributes
|
||||
LLXMLNodePtr output_node = new LLXMLNode();
|
||||
LLFloater* floater = new LLFloater(LLSD());
|
||||
LLUICtrlFactory::getInstance()->buildFloater(floater,
|
||||
filename,
|
||||
// FALSE, // don't open floater
|
||||
output_node);
|
||||
floater->buildFromFile( filename,
|
||||
// FALSE, // don't open floater
|
||||
output_node);
|
||||
std::string out_filename = xui_dir + filename;
|
||||
std::string::size_type extension_pos = out_filename.rfind(".xml");
|
||||
out_filename.resize(extension_pos);
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ void LLWidgetReg::initClass(bool register_widgets)
|
|||
LLDefaultChildRegistry::Register<LLMultiSlider> multi_slider_bar("multi_slider_bar");
|
||||
LLDefaultChildRegistry::Register<LLMultiSliderCtrl> multi_slider("multi_slider");
|
||||
LLDefaultChildRegistry::Register<LLPanel> panel("panel", &LLPanel::fromXML);
|
||||
LLDefaultChildRegistry::Register<LLLayoutStack> layout_stack("layout_stack", &LLLayoutStack::fromXML);
|
||||
LLDefaultChildRegistry::Register<LLLayoutStack> layout_stack("layout_stack");
|
||||
LLDefaultChildRegistry::Register<LLProgressBar> progress_bar("progress_bar");
|
||||
LLDefaultChildRegistry::Register<LLRadioGroup> radio_group("radio_group");
|
||||
LLDefaultChildRegistry::Register<LLSearchEditor> search_editor("search_editor");
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
$LicenseInfo:firstyear=2006&license=viewerlgpl$
|
||||
Second Life Viewer Source Code
|
||||
Copyright (C) 2010, Linden Research, Inc.
|
||||
Copyright (C) 2006-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
|
||||
|
|
|
|||
|
|
@ -36,14 +36,6 @@ import os.path
|
|||
import re
|
||||
import time
|
||||
|
||||
#import sys # *TODO: remove. only used in testing.
|
||||
#import pprint # *TODO: remove. only used in testing.
|
||||
|
||||
try:
|
||||
set = set
|
||||
except NameError:
|
||||
from sets import Set as set
|
||||
|
||||
from indra.base import llsd
|
||||
from indra.base import config
|
||||
|
||||
|
|
@ -195,8 +187,6 @@ class NamedQuery(object):
|
|||
style. It also has to look for %:name% and :name% and
|
||||
ready them for use in LIKE statements"""
|
||||
if sql:
|
||||
#print >>sys.stderr, "sql:",sql
|
||||
|
||||
# This first sub is to properly escape any % signs that
|
||||
# are meant to be literally passed through to mysql in the
|
||||
# query. It leaves any %'s that are used for
|
||||
|
|
@ -408,7 +398,6 @@ class NamedQuery(object):
|
|||
# build the query from the options available and the params
|
||||
base_query = []
|
||||
base_query.append(self._base_query)
|
||||
#print >>sys.stderr, "base_query:",base_query
|
||||
for opt, extra_where in self._options.items():
|
||||
if type(extra_where) in (dict, list, tuple):
|
||||
if opt in params:
|
||||
|
|
@ -418,7 +407,6 @@ class NamedQuery(object):
|
|||
base_query.append(extra_where)
|
||||
if self._query_suffix:
|
||||
base_query.append(self._query_suffix)
|
||||
#print >>sys.stderr, "base_query:",base_query
|
||||
full_query = '\n'.join(base_query)
|
||||
|
||||
# Go through the query and rewrite all of the ones with the
|
||||
|
|
|
|||
|
|
@ -446,8 +446,14 @@ def uuid1(node=None, clock_seq=None):
|
|||
|
||||
def uuid3(namespace, name):
|
||||
"""Generate a UUID from the MD5 hash of a namespace UUID and a name."""
|
||||
import md5
|
||||
hash = md5.md5(namespace.bytes + name).digest()
|
||||
try:
|
||||
# Python 2.6
|
||||
from hashlib import md5
|
||||
except ImportError:
|
||||
# Python 2.5 and earlier
|
||||
from md5 import new as md5
|
||||
|
||||
hash = md5(namespace.bytes + name).digest()
|
||||
return UUID(bytes=hash[:16], version=3)
|
||||
|
||||
def uuid4():
|
||||
|
|
|
|||
|
|
@ -97,6 +97,7 @@ void LLAudioEngine::setDefaults()
|
|||
}
|
||||
|
||||
mMasterGain = 1.f;
|
||||
mInternalGain = 0.f;
|
||||
mNextWindUpdate = 0.f;
|
||||
|
||||
mStreamingAudioImpl = NULL;
|
||||
|
|
@ -247,15 +248,6 @@ void LLAudioEngine::idle(F32 max_decode_time)
|
|||
// Primarily does position updating, cleanup of unused audio sources.
|
||||
// Also does regeneration of the current priority of each audio source.
|
||||
|
||||
if (getMuted())
|
||||
{
|
||||
setInternalGain(0.f);
|
||||
}
|
||||
else
|
||||
{
|
||||
setInternalGain(getMasterGain());
|
||||
}
|
||||
|
||||
S32 i;
|
||||
for (i = 0; i < MAX_BUFFERS; i++)
|
||||
{
|
||||
|
|
@ -284,6 +276,12 @@ void LLAudioEngine::idle(F32 max_decode_time)
|
|||
continue;
|
||||
}
|
||||
|
||||
if (sourcep->isMuted())
|
||||
{
|
||||
++iter;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!sourcep->getChannel() && sourcep->getCurrentBuffer())
|
||||
{
|
||||
// We could potentially play this sound if its priority is high enough.
|
||||
|
|
@ -336,9 +334,9 @@ void LLAudioEngine::idle(F32 max_decode_time)
|
|||
// attached to each channel, since only those with active channels
|
||||
// can have anything interesting happen with their queue? (Maybe not true)
|
||||
LLAudioSource *sourcep = iter->second;
|
||||
if (!sourcep->mQueuedDatap)
|
||||
if (!sourcep->mQueuedDatap || sourcep->isMuted())
|
||||
{
|
||||
// Nothing queued, so we don't care.
|
||||
// Muted, or nothing queued, so we don't care.
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -418,6 +416,10 @@ void LLAudioEngine::idle(F32 max_decode_time)
|
|||
for (iter = mAllSources.begin(); iter != mAllSources.end(); ++iter)
|
||||
{
|
||||
LLAudioSource *sourcep = iter->second;
|
||||
if (sourcep->isMuted())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (sourcep->isSyncMaster())
|
||||
{
|
||||
if (sourcep->getPriority() > max_sm_priority)
|
||||
|
|
@ -691,15 +693,23 @@ bool LLAudioEngine::isWindEnabled()
|
|||
|
||||
void LLAudioEngine::setMuted(bool muted)
|
||||
{
|
||||
mMuted = muted;
|
||||
if (muted != mMuted)
|
||||
{
|
||||
mMuted = muted;
|
||||
setMasterGain(mMasterGain);
|
||||
}
|
||||
enableWind(!mMuted);
|
||||
}
|
||||
|
||||
|
||||
void LLAudioEngine::setMasterGain(const F32 gain)
|
||||
{
|
||||
mMasterGain = gain;
|
||||
setInternalGain(gain);
|
||||
F32 internal_gain = getMuted() ? 0.f : gain;
|
||||
if (internal_gain != mInternalGain)
|
||||
{
|
||||
mInternalGain = internal_gain;
|
||||
setInternalGain(mInternalGain);
|
||||
}
|
||||
}
|
||||
|
||||
F32 LLAudioEngine::getMasterGain()
|
||||
|
|
@ -1243,13 +1253,14 @@ LLAudioSource::LLAudioSource(const LLUUID& id, const LLUUID& owner_id, const F32
|
|||
mOwnerID(owner_id),
|
||||
mPriority(0.f),
|
||||
mGain(gain),
|
||||
mType(type),
|
||||
mSourceMuted(false),
|
||||
mAmbient(false),
|
||||
mLoop(false),
|
||||
mSyncMaster(false),
|
||||
mSyncSlave(false),
|
||||
mQueueSounds(false),
|
||||
mPlayedOnce(false),
|
||||
mType(type),
|
||||
mChannelp(NULL),
|
||||
mCurrentDatap(NULL),
|
||||
mQueuedDatap(NULL)
|
||||
|
|
@ -1301,6 +1312,10 @@ void LLAudioSource::updatePriority()
|
|||
{
|
||||
mPriority = 1.f;
|
||||
}
|
||||
else if (isMuted())
|
||||
{
|
||||
mPriority = 0.f;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Priority is based on distance
|
||||
|
|
@ -1349,25 +1364,33 @@ bool LLAudioSource::setupChannel()
|
|||
|
||||
bool LLAudioSource::play(const LLUUID &audio_uuid)
|
||||
{
|
||||
// Special abuse of play(); don't play a sound, but kill it.
|
||||
if (audio_uuid.isNull())
|
||||
{
|
||||
if (getChannel())
|
||||
{
|
||||
getChannel()->setSource(NULL);
|
||||
setChannel(NULL);
|
||||
addAudioData(NULL, true);
|
||||
if (!isMuted())
|
||||
{
|
||||
mCurrentDatap = NULL;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Reset our age timeout if someone attempts to play the source.
|
||||
mAgeTimer.reset();
|
||||
|
||||
LLAudioData *adp = gAudiop->getAudioData(audio_uuid);
|
||||
|
||||
bool has_buffer = gAudiop->updateBufferForData(adp, audio_uuid);
|
||||
|
||||
|
||||
addAudioData(adp);
|
||||
|
||||
if (isMuted())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool has_buffer = gAudiop->updateBufferForData(adp, audio_uuid);
|
||||
if (!has_buffer)
|
||||
{
|
||||
// Don't bother trying to set up a channel or anything, we don't have an audio buffer.
|
||||
|
|
@ -1392,10 +1415,11 @@ bool LLAudioSource::play(const LLUUID &audio_uuid)
|
|||
}
|
||||
|
||||
|
||||
bool LLAudioSource::isDone()
|
||||
bool LLAudioSource::isDone() const
|
||||
{
|
||||
const F32 MAX_AGE = 60.f;
|
||||
const F32 MAX_UNPLAYED_AGE = 15.f;
|
||||
const F32 MAX_MUTED_AGE = 11.f;
|
||||
|
||||
if (isLoop())
|
||||
{
|
||||
|
|
@ -1403,7 +1427,6 @@ bool LLAudioSource::isDone()
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (hasPendingPreloads())
|
||||
{
|
||||
return false;
|
||||
|
|
@ -1420,10 +1443,10 @@ bool LLAudioSource::isDone()
|
|||
// This is a single-play source
|
||||
if (!mChannelp)
|
||||
{
|
||||
if ((elapsed > MAX_UNPLAYED_AGE) || mPlayedOnce)
|
||||
if ((elapsed > (mSourceMuted ? MAX_MUTED_AGE : MAX_UNPLAYED_AGE)) || mPlayedOnce)
|
||||
{
|
||||
// We don't have a channel assigned, and it's been
|
||||
// over 5 seconds since we tried to play it. Don't bother.
|
||||
// over 15 seconds since we tried to play it. Don't bother.
|
||||
//llinfos << "No channel assigned, source is done" << llendl;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1449,7 +1472,7 @@ bool LLAudioSource::isDone()
|
|||
|
||||
if ((elapsed > MAX_UNPLAYED_AGE) || mPlayedOnce)
|
||||
{
|
||||
// The sound isn't playing back after 5 seconds or we're already done playing it, kill it.
|
||||
// The sound isn't playing back after 15 seconds or we're already done playing it, kill it.
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -118,8 +118,8 @@ public:
|
|||
// Use these for temporarily muting the audio system.
|
||||
// Does not change buffers, initialization, etc. but
|
||||
// stops playing new sounds.
|
||||
virtual void setMuted(bool muted);
|
||||
virtual bool getMuted() const { return mMuted; }
|
||||
void setMuted(bool muted);
|
||||
bool getMuted() const { return mMuted; }
|
||||
#ifdef USE_PLUGIN_MEDIA
|
||||
LLPluginClassMedia* initializeMedia(const std::string& media_type);
|
||||
#endif
|
||||
|
|
@ -239,6 +239,7 @@ protected:
|
|||
LLAudioBuffer *mBuffers[MAX_BUFFERS];
|
||||
|
||||
F32 mMasterGain;
|
||||
F32 mInternalGain; // Actual gain set; either mMasterGain or 0 when mMuted is true.
|
||||
F32 mSecondaryGain[AUDIO_TYPE_COUNT];
|
||||
|
||||
F32 mNextWindUpdate;
|
||||
|
|
@ -303,7 +304,8 @@ public:
|
|||
virtual void setGain(const F32 gain) { mGain = llclamp(gain, 0.f, 1.f); }
|
||||
|
||||
const LLUUID &getID() const { return mID; }
|
||||
bool isDone();
|
||||
bool isDone() const;
|
||||
bool isMuted() const { return mSourceMuted; }
|
||||
|
||||
LLAudioData *getCurrentData();
|
||||
LLAudioData *getQueuedData();
|
||||
|
|
@ -325,6 +327,7 @@ protected:
|
|||
LLUUID mOwnerID; // owner of the object playing the sound
|
||||
F32 mPriority;
|
||||
F32 mGain;
|
||||
bool mSourceMuted;
|
||||
bool mAmbient;
|
||||
bool mLoop;
|
||||
bool mSyncMaster;
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ set(llcommon_SOURCE_FILES
|
|||
llapp.cpp
|
||||
llapr.cpp
|
||||
llassettype.cpp
|
||||
llavatarname.cpp
|
||||
llbase32.cpp
|
||||
llbase64.cpp
|
||||
llcommon.cpp
|
||||
|
|
@ -115,6 +116,7 @@ set(llcommon_HEADER_FILES
|
|||
llallocator.h
|
||||
llallocator_heap_profile.h
|
||||
llagentconstants.h
|
||||
llavatarname.h
|
||||
llapp.h
|
||||
llapr.h
|
||||
llassettype.h
|
||||
|
|
@ -157,6 +159,7 @@ set(llcommon_HEADER_FILES
|
|||
lleventemitter.h
|
||||
llextendedstatus.h
|
||||
llfasttimer.h
|
||||
llfasttimer_class.h
|
||||
llfile.h
|
||||
llfindlocale.h
|
||||
llfixedbuffer.h
|
||||
|
|
@ -251,8 +254,15 @@ set_source_files_properties(${llcommon_HEADER_FILES}
|
|||
list(APPEND llcommon_SOURCE_FILES ${llcommon_HEADER_FILES})
|
||||
|
||||
if(LLCOMMON_LINK_SHARED)
|
||||
add_library (llcommon SHARED ${llcommon_SOURCE_FILES})
|
||||
ll_stage_sharedlib(llcommon)
|
||||
add_library (llcommon SHARED ${llcommon_SOURCE_FILES})
|
||||
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)
|
||||
ll_stage_sharedlib(llcommon)
|
||||
else(LLCOMMON_LINK_SHARED)
|
||||
add_library (llcommon ${llcommon_SOURCE_FILES})
|
||||
endif(LLCOMMON_LINK_SHARED)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,113 @@
|
|||
/**
|
||||
* @file llavatarname.cpp
|
||||
* @brief Represents name-related data for an avatar, such as the
|
||||
* username/SLID ("bobsmith123" or "james.linden") and the display
|
||||
* name ("James Cook")
|
||||
*
|
||||
* $LicenseInfo:firstyear=2010&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 "llavatarname.h"
|
||||
|
||||
#include "lldate.h"
|
||||
#include "llsd.h"
|
||||
|
||||
// Store these in pre-built std::strings to avoid memory allocations in
|
||||
// LLSD map lookups
|
||||
static const std::string USERNAME("username");
|
||||
static const std::string DISPLAY_NAME("display_name");
|
||||
static const std::string LEGACY_FIRST_NAME("legacy_first_name");
|
||||
static const std::string LEGACY_LAST_NAME("legacy_last_name");
|
||||
static const std::string IS_DISPLAY_NAME_DEFAULT("is_display_name_default");
|
||||
static const std::string DISPLAY_NAME_EXPIRES("display_name_expires");
|
||||
static const std::string DISPLAY_NAME_NEXT_UPDATE("display_name_next_update");
|
||||
|
||||
LLAvatarName::LLAvatarName()
|
||||
: mUsername(),
|
||||
mDisplayName(),
|
||||
mLegacyFirstName(),
|
||||
mLegacyLastName(),
|
||||
mIsDisplayNameDefault(false),
|
||||
mIsDummy(false),
|
||||
mExpires(F64_MAX),
|
||||
mNextUpdate(0.0)
|
||||
{ }
|
||||
|
||||
bool LLAvatarName::operator<(const LLAvatarName& rhs) const
|
||||
{
|
||||
if (mUsername == rhs.mUsername)
|
||||
return mDisplayName < rhs.mDisplayName;
|
||||
else
|
||||
return mUsername < rhs.mUsername;
|
||||
}
|
||||
|
||||
LLSD LLAvatarName::asLLSD() const
|
||||
{
|
||||
LLSD sd;
|
||||
sd[USERNAME] = mUsername;
|
||||
sd[DISPLAY_NAME] = mDisplayName;
|
||||
sd[LEGACY_FIRST_NAME] = mLegacyFirstName;
|
||||
sd[LEGACY_LAST_NAME] = mLegacyLastName;
|
||||
sd[IS_DISPLAY_NAME_DEFAULT] = mIsDisplayNameDefault;
|
||||
sd[DISPLAY_NAME_EXPIRES] = LLDate(mExpires);
|
||||
sd[DISPLAY_NAME_NEXT_UPDATE] = LLDate(mNextUpdate);
|
||||
return sd;
|
||||
}
|
||||
|
||||
void LLAvatarName::fromLLSD(const LLSD& sd)
|
||||
{
|
||||
mUsername = sd[USERNAME].asString();
|
||||
mDisplayName = sd[DISPLAY_NAME].asString();
|
||||
mLegacyFirstName = sd[LEGACY_FIRST_NAME].asString();
|
||||
mLegacyLastName = sd[LEGACY_LAST_NAME].asString();
|
||||
mIsDisplayNameDefault = sd[IS_DISPLAY_NAME_DEFAULT].asBoolean();
|
||||
LLDate expires = sd[DISPLAY_NAME_EXPIRES];
|
||||
mExpires = expires.secondsSinceEpoch();
|
||||
LLDate next_update = sd[DISPLAY_NAME_NEXT_UPDATE];
|
||||
mNextUpdate = next_update.secondsSinceEpoch();
|
||||
}
|
||||
|
||||
std::string LLAvatarName::getCompleteName() const
|
||||
{
|
||||
std::string name;
|
||||
if (!mUsername.empty())
|
||||
{
|
||||
name = mDisplayName + " (" + mUsername + ")";
|
||||
}
|
||||
else
|
||||
{
|
||||
// ...display names are off, legacy name is in mDisplayName
|
||||
name = mDisplayName;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
std::string LLAvatarName::getLegacyName() const
|
||||
{
|
||||
std::string name;
|
||||
name.reserve( mLegacyFirstName.size() + 1 + mLegacyLastName.size() );
|
||||
name = mLegacyFirstName;
|
||||
name += " ";
|
||||
name += mLegacyLastName;
|
||||
return name;
|
||||
}
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
/**
|
||||
* @file llavatarname.h
|
||||
* @brief Represents name-related data for an avatar, such as the
|
||||
* username/SLID ("bobsmith123" or "james.linden") and the display
|
||||
* name ("James Cook")
|
||||
*
|
||||
* $LicenseInfo:firstyear=2010&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 LLAVATARNAME_H
|
||||
#define LLAVATARNAME_H
|
||||
|
||||
#include <string>
|
||||
|
||||
class LLSD;
|
||||
|
||||
class LL_COMMON_API LLAvatarName
|
||||
{
|
||||
public:
|
||||
LLAvatarName();
|
||||
|
||||
bool operator<(const LLAvatarName& rhs) const;
|
||||
|
||||
LLSD asLLSD() const;
|
||||
|
||||
void fromLLSD(const LLSD& sd);
|
||||
|
||||
// For normal names, returns "James Linden (james.linden)"
|
||||
// When display names are disabled returns just "James Linden"
|
||||
std::string getCompleteName() const;
|
||||
|
||||
// Returns "James Linden" or "bobsmith123 Resident" for backwards
|
||||
// compatibility with systems like voice and muting
|
||||
// *TODO: Eliminate this in favor of username only
|
||||
std::string getLegacyName() const;
|
||||
|
||||
// "bobsmith123" or "james.linden", US-ASCII only
|
||||
std::string mUsername;
|
||||
|
||||
// "Jose' Sanchez" or "James Linden", UTF-8 encoded Unicode
|
||||
// Contains data whether or not user has explicitly set
|
||||
// a display name; may duplicate their username.
|
||||
std::string mDisplayName;
|
||||
|
||||
// For "James Linden", "James"
|
||||
// For "bobsmith123", "bobsmith123"
|
||||
// Used to communicate with legacy systems like voice and muting which
|
||||
// rely on old-style names.
|
||||
// *TODO: Eliminate this in favor of username only
|
||||
std::string mLegacyFirstName;
|
||||
|
||||
// For "James Linden", "Linden"
|
||||
// For "bobsmith123", "Resident"
|
||||
// see above for rationale
|
||||
std::string mLegacyLastName;
|
||||
|
||||
// If true, both display name and SLID were generated from
|
||||
// a legacy first and last name, like "James Linden (james.linden)"
|
||||
bool mIsDisplayNameDefault;
|
||||
|
||||
// Under error conditions, we may insert "dummy" records with
|
||||
// names like "???" into caches as placeholders. These can be
|
||||
// shown in UI, but are not serialized.
|
||||
bool mIsDummy;
|
||||
|
||||
// Names can change, so need to keep track of when name was
|
||||
// last checked.
|
||||
// Unix time-from-epoch seconds for efficiency
|
||||
F64 mExpires;
|
||||
|
||||
// You can only change your name every N hours, so record
|
||||
// when the next update is allowed
|
||||
// Unix time-from-epoch seconds
|
||||
F64 mNextUpdate;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -28,7 +28,6 @@
|
|||
#ifndef LL_LLCHAT_H
|
||||
#define LL_LLCHAT_H
|
||||
|
||||
#include "llstring.h"
|
||||
#include "lluuid.h"
|
||||
#include "v3math.h"
|
||||
|
||||
|
|
@ -71,7 +70,7 @@ typedef enum e_chat_style
|
|||
class LLChat
|
||||
{
|
||||
public:
|
||||
LLChat(const std::string& text = LLStringUtil::null)
|
||||
LLChat(const std::string& text = std::string())
|
||||
: mText(text),
|
||||
mFromName(),
|
||||
mFromID(),
|
||||
|
|
|
|||
|
|
@ -78,7 +78,9 @@ protected:
|
|||
virtual Index notFound() const
|
||||
{
|
||||
// default is to assert
|
||||
llassert(false);
|
||||
// don't assert -- makes it impossible to work on mesh-development and viewer-development simultaneously
|
||||
// -- davep 2010.10.29
|
||||
//llassert(false);
|
||||
return Index(-1);
|
||||
}
|
||||
void addEntry(Index index, Entry *entry)
|
||||
|
|
|
|||
|
|
@ -469,9 +469,9 @@ void LLFastTimer::NamedTimer::accumulateTimings()
|
|||
int hidx = cur_frame % HISTORY_NUM;
|
||||
|
||||
timerp->mCountHistory[hidx] = timerp->mTotalTimeCounter;
|
||||
timerp->mCountAverage = (timerp->mCountAverage * cur_frame + timerp->mTotalTimeCounter) / (cur_frame+1);
|
||||
timerp->mCountAverage = ((U64)timerp->mCountAverage * cur_frame + timerp->mTotalTimeCounter) / (cur_frame+1);
|
||||
timerp->mCallHistory[hidx] = timerp->getFrameState().mCalls;
|
||||
timerp->mCallAverage = (timerp->mCallAverage * cur_frame + timerp->getFrameState().mCalls) / (cur_frame+1);
|
||||
timerp->mCallAverage = ((U64)timerp->mCallAverage * cur_frame + timerp->getFrameState().mCalls) / (cur_frame+1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -731,14 +731,17 @@ void LLStringOps::setupDatetimeInfo (bool daylight)
|
|||
|
||||
nowT = time (NULL);
|
||||
|
||||
tmpT = localtime (&nowT);
|
||||
localT = mktime (tmpT);
|
||||
|
||||
tmpT = gmtime (&nowT);
|
||||
gmtT = mktime (tmpT);
|
||||
|
||||
tmpT = localtime (&nowT);
|
||||
localT = mktime (tmpT);
|
||||
|
||||
sLocalTimeOffset = (long) (gmtT - localT);
|
||||
|
||||
if (tmpT->tm_isdst)
|
||||
{
|
||||
sLocalTimeOffset -= 60 * 60; // 1 hour
|
||||
}
|
||||
|
||||
sPacificDaylightTime = daylight;
|
||||
sPacificTimeOffset = (sPacificDaylightTime? 7 : 8 ) * 60 * 60;
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@
|
|||
#define LL_LLVERSIONVIEWER_H
|
||||
|
||||
const S32 LL_VERSION_MAJOR = 2;
|
||||
const S32 LL_VERSION_MINOR = 2;
|
||||
const S32 LL_VERSION_MINOR = 3;
|
||||
const S32 LL_VERSION_PATCH = 0;
|
||||
const S32 LL_VERSION_BUILD = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -52,7 +52,6 @@ enum LLRoleChangeType
|
|||
//
|
||||
|
||||
// KNOWN HOLES: use these for any single bit powers you need
|
||||
// bit 0x1 << 41
|
||||
// bit 0x1 << 46
|
||||
// bit 0x1 << 49 and above
|
||||
|
||||
|
|
@ -103,6 +102,8 @@ const U64 GP_LAND_ALLOW_FLY = 0x1 << 24; // Bypass Fly Restriction
|
|||
const U64 GP_LAND_ALLOW_CREATE = 0x1 << 25; // Bypass Create/Edit Objects Restriction
|
||||
const U64 GP_LAND_ALLOW_LANDMARK = 0x1 << 26; // Bypass Landmark Restriction
|
||||
const U64 GP_LAND_ALLOW_SET_HOME = 0x1 << 28; // Bypass Set Home Point Restriction
|
||||
const U64 GP_LAND_ALLOW_HOLD_EVENT = 0x1LL << 41; // Allowed to hold events on group-owned land
|
||||
|
||||
|
||||
// Parcel Access
|
||||
const U64 GP_LAND_MANAGE_ALLOWED = 0x1 << 29; // Manage Allowed List
|
||||
|
|
|
|||
|
|
@ -113,8 +113,8 @@ enum EObjectPropertiesExtraID
|
|||
enum EAddPosition
|
||||
{
|
||||
ADD_TOP,
|
||||
ADD_SORTED,
|
||||
ADD_BOTTOM
|
||||
ADD_BOTTOM,
|
||||
ADD_DEFAULT
|
||||
};
|
||||
|
||||
enum LLGroupChange
|
||||
|
|
|
|||
|
|
@ -108,6 +108,9 @@ std::string build_transfer_message_to_source(
|
|||
std::ostringstream ostr;
|
||||
if(dest_id.isNull())
|
||||
{
|
||||
// *NOTE: Do not change these strings! The viewer matches
|
||||
// them in llviewermessage.cpp to perform localization.
|
||||
// If you need to make changes, add a new, localizable message. JC
|
||||
ostr << "You paid L$" << amount;
|
||||
switch(transaction_type)
|
||||
{
|
||||
|
|
@ -154,6 +157,9 @@ std::string build_transfer_message_to_destination(
|
|||
return description;
|
||||
}
|
||||
std::ostringstream ostr;
|
||||
// *NOTE: Do not change these strings! The viewer matches
|
||||
// them in llviewermessage.cpp to perform localization.
|
||||
// If you need to make changes, add a new, localizable message. JC
|
||||
ostr << source_name << " paid you L$" << amount;
|
||||
append_reason(ostr, transaction_type, description);
|
||||
ostr << ".";
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ set(llmessage_SOURCE_FILES
|
|||
llares.cpp
|
||||
llareslistener.cpp
|
||||
llassetstorage.cpp
|
||||
llavatarnamecache.cpp
|
||||
llblowfishcipher.cpp
|
||||
llbuffer.cpp
|
||||
llbufferstream.cpp
|
||||
|
|
@ -110,6 +111,7 @@ set(llmessage_HEADER_FILES
|
|||
llares.h
|
||||
llareslistener.h
|
||||
llassetstorage.h
|
||||
llavatarnamecache.h
|
||||
llblowfishcipher.h
|
||||
llbuffer.h
|
||||
llbufferstream.h
|
||||
|
|
@ -248,6 +250,7 @@ if (LL_TESTS)
|
|||
"${CMAKE_CURRENT_SOURCE_DIR}/tests/test_llsdmessage_peer.py"
|
||||
)
|
||||
|
||||
LL_ADD_INTEGRATION_TEST(llavatarnamecache "" "${test_libs}")
|
||||
LL_ADD_INTEGRATION_TEST(llhost "" "${test_libs}")
|
||||
LL_ADD_INTEGRATION_TEST(llpartdata "" "${test_libs}")
|
||||
LL_ADD_INTEGRATION_TEST(llxfer_file "" "${test_libs}")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,822 @@
|
|||
/**
|
||||
* @file llavatarnamecache.cpp
|
||||
* @brief Provides lookup of avatar SLIDs ("bobsmith123") and display names
|
||||
* ("James Cook") from avatar UUIDs.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2010&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 "llavatarnamecache.h"
|
||||
|
||||
#include "llcachename.h" // we wrap this system
|
||||
#include "llframetimer.h"
|
||||
#include "llhttpclient.h"
|
||||
#include "llsd.h"
|
||||
#include "llsdserialize.h"
|
||||
|
||||
#include <boost/tokenizer.hpp>
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
namespace LLAvatarNameCache
|
||||
{
|
||||
use_display_name_signal_t mUseDisplayNamesSignal;
|
||||
|
||||
// Manual override for display names - can disable even if the region
|
||||
// supports it.
|
||||
bool sUseDisplayNames = true;
|
||||
|
||||
// Cache starts in a paused state until we can determine if the
|
||||
// current region supports display names.
|
||||
bool sRunning = false;
|
||||
|
||||
// Base lookup URL for name service.
|
||||
// On simulator, loaded from indra.xml
|
||||
// On viewer, usually a simulator capability (at People API team's request)
|
||||
// Includes the trailing slash, like "http://pdp60.lindenlab.com:8000/agents/"
|
||||
std::string sNameLookupURL;
|
||||
|
||||
// accumulated agent IDs for next query against service
|
||||
typedef std::set<LLUUID> ask_queue_t;
|
||||
ask_queue_t sAskQueue;
|
||||
|
||||
// agent IDs that have been requested, but with no reply
|
||||
// maps agent ID to frame time request was made
|
||||
typedef std::map<LLUUID, F64> pending_queue_t;
|
||||
pending_queue_t sPendingQueue;
|
||||
|
||||
// Callbacks to fire when we received a name.
|
||||
// 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<LLUUID, callback_signal_t*> signal_map_t;
|
||||
signal_map_t sSignalMap;
|
||||
|
||||
// names we know about
|
||||
typedef std::map<LLUUID, LLAvatarName> cache_t;
|
||||
cache_t sCache;
|
||||
|
||||
// Send bulk lookup requests a few times a second at most
|
||||
// only need per-frame timing resolution
|
||||
LLFrameTimer sRequestTimer;
|
||||
|
||||
// Periodically clean out expired entries from the cache
|
||||
//LLFrameTimer sEraseExpiredTimer;
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Internal methods
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
// Handle name response off network.
|
||||
// Optionally skip adding to cache, used when this is a fallback to the
|
||||
// legacy name system.
|
||||
void processName(const LLUUID& agent_id,
|
||||
const LLAvatarName& av_name,
|
||||
bool add_to_cache);
|
||||
|
||||
void requestNamesViaCapability();
|
||||
|
||||
// Legacy name system callback
|
||||
void legacyNameCallback(const LLUUID& agent_id,
|
||||
const std::string& full_name,
|
||||
bool is_group);
|
||||
|
||||
void requestNamesViaLegacy();
|
||||
|
||||
// Fill in an LLAvatarName with the legacy name data
|
||||
void buildLegacyName(const std::string& full_name,
|
||||
LLAvatarName* av_name);
|
||||
|
||||
// Do a single callback to a given slot
|
||||
void fireSignal(const LLUUID& agent_id,
|
||||
const callback_slot_t& slot,
|
||||
const LLAvatarName& av_name);
|
||||
|
||||
// Is a request in-flight over the network?
|
||||
bool isRequestPending(const LLUUID& agent_id);
|
||||
|
||||
// Erase expired names from cache
|
||||
void eraseExpired();
|
||||
|
||||
bool expirationFromCacheControl(LLSD headers, F64 *expires);
|
||||
}
|
||||
|
||||
/* Sample response:
|
||||
<?xml version="1.0"?>
|
||||
<llsd>
|
||||
<map>
|
||||
<key>agents</key>
|
||||
<array>
|
||||
<map>
|
||||
<key>display_name_next_update</key>
|
||||
<date>2010-04-16T21:34:02+00:00Z</date>
|
||||
<key>display_name_expires</key>
|
||||
<date>2010-04-16T21:32:26.142178+00:00Z</date>
|
||||
<key>display_name</key>
|
||||
<string>MickBot390 LLQABot</string>
|
||||
<key>sl_id</key>
|
||||
<string>mickbot390.llqabot</string>
|
||||
<key>id</key>
|
||||
<string>0012809d-7d2d-4c24-9609-af1230a37715</string>
|
||||
<key>is_display_name_default</key>
|
||||
<boolean>false</boolean>
|
||||
</map>
|
||||
<map>
|
||||
<key>display_name_next_update</key>
|
||||
<date>2010-04-16T21:34:02+00:00Z</date>
|
||||
<key>display_name_expires</key>
|
||||
<date>2010-04-16T21:32:26.142178+00:00Z</date>
|
||||
<key>display_name</key>
|
||||
<string>Bjork Gudmundsdottir</string>
|
||||
<key>sl_id</key>
|
||||
<string>sardonyx.linden</string>
|
||||
<key>id</key>
|
||||
<string>3941037e-78ab-45f0-b421-bd6e77c1804d</string>
|
||||
<key>is_display_name_default</key>
|
||||
<boolean>true</boolean>
|
||||
</map>
|
||||
</array>
|
||||
</map>
|
||||
</llsd>
|
||||
*/
|
||||
|
||||
class LLAvatarNameResponder : public LLHTTPClient::Responder
|
||||
{
|
||||
private:
|
||||
// need to store agent ids that are part of this request in case of
|
||||
// an error, so we can flag them as unavailable
|
||||
std::vector<LLUUID> mAgentIDs;
|
||||
|
||||
// Need the headers to look up Expires: and Retry-After:
|
||||
LLSD mHeaders;
|
||||
|
||||
public:
|
||||
LLAvatarNameResponder(const std::vector<LLUUID>& agent_ids)
|
||||
: mAgentIDs(agent_ids),
|
||||
mHeaders()
|
||||
{ }
|
||||
|
||||
/*virtual*/ void completedHeader(U32 status, const std::string& reason,
|
||||
const LLSD& headers)
|
||||
{
|
||||
mHeaders = headers;
|
||||
}
|
||||
|
||||
/*virtual*/ void result(const LLSD& content)
|
||||
{
|
||||
// Pull expiration out of headers if available
|
||||
F64 expires = LLAvatarNameCache::nameExpirationFromHeaders(mHeaders);
|
||||
|
||||
LLSD agents = content["agents"];
|
||||
LLSD::array_const_iterator it = agents.beginArray();
|
||||
for ( ; it != agents.endArray(); ++it)
|
||||
{
|
||||
const LLSD& row = *it;
|
||||
LLUUID agent_id = row["id"].asUUID();
|
||||
|
||||
LLAvatarName av_name;
|
||||
av_name.fromLLSD(row);
|
||||
|
||||
// Use expiration time from header
|
||||
av_name.mExpires = expires;
|
||||
|
||||
// Some avatars don't have explicit display names set
|
||||
if (av_name.mDisplayName.empty())
|
||||
{
|
||||
av_name.mDisplayName = av_name.mUsername;
|
||||
}
|
||||
|
||||
// cache it and fire signals
|
||||
LLAvatarNameCache::processName(agent_id, av_name, true);
|
||||
}
|
||||
|
||||
// Same logic as error response case
|
||||
LLSD unresolved_agents = content["bad_ids"];
|
||||
if (unresolved_agents.size() > 0)
|
||||
{
|
||||
const std::string DUMMY_NAME("\?\?\?");
|
||||
LLAvatarName av_name;
|
||||
av_name.mUsername = DUMMY_NAME;
|
||||
av_name.mDisplayName = DUMMY_NAME;
|
||||
av_name.mIsDisplayNameDefault = false;
|
||||
av_name.mIsDummy = true;
|
||||
av_name.mExpires = expires;
|
||||
|
||||
it = unresolved_agents.beginArray();
|
||||
for ( ; it != unresolved_agents.endArray(); ++it)
|
||||
{
|
||||
const LLUUID& agent_id = *it;
|
||||
// cache it and fire signals
|
||||
LLAvatarNameCache::processName(agent_id, av_name, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*virtual*/ void error(U32 status, const std::string& reason)
|
||||
{
|
||||
// We're going to construct a dummy record and cache it for a while,
|
||||
// either briefly for a 503 Service Unavailable, or longer for other
|
||||
// errors.
|
||||
F64 retry_timestamp = errorRetryTimestamp(status);
|
||||
|
||||
// *NOTE: "??" starts trigraphs in C/C++, escape the question marks.
|
||||
const std::string DUMMY_NAME("\?\?\?");
|
||||
LLAvatarName av_name;
|
||||
av_name.mUsername = DUMMY_NAME;
|
||||
av_name.mDisplayName = DUMMY_NAME;
|
||||
av_name.mIsDisplayNameDefault = false;
|
||||
av_name.mIsDummy = true;
|
||||
av_name.mExpires = retry_timestamp;
|
||||
|
||||
// Add dummy records for all agent IDs in this request
|
||||
std::vector<LLUUID>::const_iterator it = mAgentIDs.begin();
|
||||
for ( ; it != mAgentIDs.end(); ++it)
|
||||
{
|
||||
const LLUUID& agent_id = *it;
|
||||
// cache it and fire signals
|
||||
LLAvatarNameCache::processName(agent_id, av_name, true);
|
||||
}
|
||||
}
|
||||
|
||||
// Return time to retry a request that generated an error, based on
|
||||
// error type and headers. Return value is seconds-since-epoch.
|
||||
F64 errorRetryTimestamp(S32 status)
|
||||
{
|
||||
F64 now = LLFrameTimer::getTotalSeconds();
|
||||
|
||||
// Retry-After takes priority
|
||||
LLSD retry_after = mHeaders["retry-after"];
|
||||
if (retry_after.isDefined())
|
||||
{
|
||||
// We only support the delta-seconds type
|
||||
S32 delta_seconds = retry_after.asInteger();
|
||||
if (delta_seconds > 0)
|
||||
{
|
||||
// ...valid delta-seconds
|
||||
return now + F64(delta_seconds);
|
||||
}
|
||||
}
|
||||
|
||||
// If no Retry-After, look for Cache-Control max-age
|
||||
F64 expires = 0.0;
|
||||
if (LLAvatarNameCache::expirationFromCacheControl(mHeaders, &expires))
|
||||
{
|
||||
return expires;
|
||||
}
|
||||
|
||||
// No information in header, make a guess
|
||||
if (status == 503)
|
||||
{
|
||||
// ...service unavailable, retry soon
|
||||
const F64 SERVICE_UNAVAILABLE_DELAY = 600.0; // 10 min
|
||||
return now + SERVICE_UNAVAILABLE_DELAY;
|
||||
}
|
||||
else
|
||||
{
|
||||
// ...other unexpected error
|
||||
const F64 DEFAULT_DELAY = 3600.0; // 1 hour
|
||||
return now + DEFAULT_DELAY;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void LLAvatarNameCache::processName(const LLUUID& agent_id,
|
||||
const LLAvatarName& av_name,
|
||||
bool add_to_cache)
|
||||
{
|
||||
if (add_to_cache)
|
||||
{
|
||||
sCache[agent_id] = av_name;
|
||||
}
|
||||
|
||||
sPendingQueue.erase(agent_id);
|
||||
|
||||
// signal everyone waiting on this name
|
||||
signal_map_t::iterator sig_it = sSignalMap.find(agent_id);
|
||||
if (sig_it != sSignalMap.end())
|
||||
{
|
||||
callback_signal_t* signal = sig_it->second;
|
||||
(*signal)(agent_id, av_name);
|
||||
|
||||
sSignalMap.erase(agent_id);
|
||||
|
||||
delete signal;
|
||||
signal = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void LLAvatarNameCache::requestNamesViaCapability()
|
||||
{
|
||||
F64 now = LLFrameTimer::getTotalSeconds();
|
||||
|
||||
// URL format is like:
|
||||
// http://pdp60.lindenlab.com:8000/agents/?ids=3941037e-78ab-45f0-b421-bd6e77c1804d&ids=0012809d-7d2d-4c24-9609-af1230a37715&ids=0019aaba-24af-4f0a-aa72-6457953cf7f0
|
||||
//
|
||||
// Apache can handle URLs of 4096 chars, but let's be conservative
|
||||
const U32 NAME_URL_MAX = 4096;
|
||||
const U32 NAME_URL_SEND_THRESHOLD = 3000;
|
||||
std::string url;
|
||||
url.reserve(NAME_URL_MAX);
|
||||
|
||||
std::vector<LLUUID> agent_ids;
|
||||
agent_ids.reserve(128);
|
||||
|
||||
ask_queue_t::const_iterator it = sAskQueue.begin();
|
||||
for ( ; it != sAskQueue.end(); ++it)
|
||||
{
|
||||
const LLUUID& agent_id = *it;
|
||||
|
||||
if (url.empty())
|
||||
{
|
||||
// ...starting new request
|
||||
url += sNameLookupURL;
|
||||
url += "?ids=";
|
||||
}
|
||||
else
|
||||
{
|
||||
// ...continuing existing request
|
||||
url += "&ids=";
|
||||
}
|
||||
url += agent_id.asString();
|
||||
agent_ids.push_back(agent_id);
|
||||
|
||||
// mark request as pending
|
||||
sPendingQueue[agent_id] = now;
|
||||
|
||||
if (url.size() > NAME_URL_SEND_THRESHOLD)
|
||||
{
|
||||
//llinfos << "requestNames " << url << llendl;
|
||||
LLHTTPClient::get(url, new LLAvatarNameResponder(agent_ids));
|
||||
url.clear();
|
||||
agent_ids.clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (!url.empty())
|
||||
{
|
||||
//llinfos << "requestNames " << url << llendl;
|
||||
LLHTTPClient::get(url, new LLAvatarNameResponder(agent_ids));
|
||||
url.clear();
|
||||
agent_ids.clear();
|
||||
}
|
||||
|
||||
// We've moved all asks to the pending request queue
|
||||
sAskQueue.clear();
|
||||
}
|
||||
|
||||
void LLAvatarNameCache::legacyNameCallback(const LLUUID& agent_id,
|
||||
const std::string& full_name,
|
||||
bool is_group)
|
||||
{
|
||||
// Construct a dummy record for this name. By convention, SLID is blank
|
||||
// Never expires, but not written to disk, so lasts until end of session.
|
||||
LLAvatarName av_name;
|
||||
buildLegacyName(full_name, &av_name);
|
||||
|
||||
// Don't add to cache, the data already exists in the legacy name system
|
||||
// cache and we don't want or need duplicate storage, because keeping the
|
||||
// two copies in sync is complex.
|
||||
processName(agent_id, av_name, false);
|
||||
}
|
||||
|
||||
void LLAvatarNameCache::requestNamesViaLegacy()
|
||||
{
|
||||
F64 now = LLFrameTimer::getTotalSeconds();
|
||||
std::string full_name;
|
||||
ask_queue_t::const_iterator it = sAskQueue.begin();
|
||||
for (; it != sAskQueue.end(); ++it)
|
||||
{
|
||||
const LLUUID& agent_id = *it;
|
||||
|
||||
// Mark as pending first, just in case the callback is immediately
|
||||
// invoked below. This should never happen in practice.
|
||||
sPendingQueue[agent_id] = now;
|
||||
|
||||
gCacheName->get(agent_id, false, // legacy compatibility
|
||||
boost::bind(&LLAvatarNameCache::legacyNameCallback,
|
||||
_1, _2, _3));
|
||||
}
|
||||
|
||||
// We've either answered immediately or moved all asks to the
|
||||
// pending queue
|
||||
sAskQueue.clear();
|
||||
}
|
||||
|
||||
void LLAvatarNameCache::initClass(bool running)
|
||||
{
|
||||
sRunning = running;
|
||||
}
|
||||
|
||||
void LLAvatarNameCache::cleanupClass()
|
||||
{
|
||||
}
|
||||
|
||||
void LLAvatarNameCache::importFile(std::istream& istr)
|
||||
{
|
||||
LLSD data;
|
||||
S32 parse_count = LLSDSerialize::fromXMLDocument(data, istr);
|
||||
if (parse_count < 1) return;
|
||||
|
||||
// by convention LLSD storage is a map
|
||||
// we only store one entry in the map
|
||||
LLSD agents = data["agents"];
|
||||
|
||||
LLUUID agent_id;
|
||||
LLAvatarName av_name;
|
||||
LLSD::map_const_iterator it = agents.beginMap();
|
||||
for ( ; it != agents.endMap(); ++it)
|
||||
{
|
||||
agent_id.set(it->first);
|
||||
av_name.fromLLSD( it->second );
|
||||
sCache[agent_id] = av_name;
|
||||
}
|
||||
// entries may have expired since we last ran the viewer, just
|
||||
// clean them out now
|
||||
eraseExpired();
|
||||
llinfos << "loaded " << sCache.size() << llendl;
|
||||
}
|
||||
|
||||
void LLAvatarNameCache::exportFile(std::ostream& ostr)
|
||||
{
|
||||
LLSD agents;
|
||||
cache_t::const_iterator it = sCache.begin();
|
||||
for ( ; it != sCache.end(); ++it)
|
||||
{
|
||||
const LLUUID& agent_id = it->first;
|
||||
const LLAvatarName& av_name = it->second;
|
||||
if (!av_name.mIsDummy)
|
||||
{
|
||||
// key must be a string
|
||||
agents[agent_id.asString()] = av_name.asLLSD();
|
||||
}
|
||||
}
|
||||
LLSD data;
|
||||
data["agents"] = agents;
|
||||
LLSDSerialize::toPrettyXML(data, ostr);
|
||||
}
|
||||
|
||||
void LLAvatarNameCache::setNameLookupURL(const std::string& name_lookup_url)
|
||||
{
|
||||
sNameLookupURL = name_lookup_url;
|
||||
}
|
||||
|
||||
bool LLAvatarNameCache::hasNameLookupURL()
|
||||
{
|
||||
return !sNameLookupURL.empty();
|
||||
}
|
||||
|
||||
void LLAvatarNameCache::idle()
|
||||
{
|
||||
// By convention, start running at first idle() call
|
||||
sRunning = true;
|
||||
|
||||
// *TODO: Possibly re-enabled this based on People API load measurements
|
||||
// 100 ms is the threshold for "user speed" operations, so we can
|
||||
// stall for about that long to batch up requests.
|
||||
//const F32 SECS_BETWEEN_REQUESTS = 0.1f;
|
||||
//if (!sRequestTimer.checkExpirationAndReset(SECS_BETWEEN_REQUESTS))
|
||||
//{
|
||||
// return;
|
||||
//}
|
||||
|
||||
// Must be large relative to above
|
||||
|
||||
// No longer deleting expired entries, just re-requesting in the get
|
||||
// this way first synchronous get call on an expired entry won't return
|
||||
// legacy name. LF
|
||||
|
||||
//const F32 ERASE_EXPIRED_TIMEOUT = 60.f; // seconds
|
||||
//if (sEraseExpiredTimer.checkExpirationAndReset(ERASE_EXPIRED_TIMEOUT))
|
||||
//{
|
||||
// eraseExpired();
|
||||
//}
|
||||
|
||||
if (sAskQueue.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (useDisplayNames())
|
||||
{
|
||||
requestNamesViaCapability();
|
||||
}
|
||||
else
|
||||
{
|
||||
// ...fall back to legacy name cache system
|
||||
requestNamesViaLegacy();
|
||||
}
|
||||
}
|
||||
|
||||
bool LLAvatarNameCache::isRequestPending(const LLUUID& agent_id)
|
||||
{
|
||||
const F64 PENDING_TIMEOUT_SECS = 5.0 * 60.0;
|
||||
F64 now = LLFrameTimer::getTotalSeconds();
|
||||
F64 expire_time = now - PENDING_TIMEOUT_SECS;
|
||||
|
||||
pending_queue_t::const_iterator it = sPendingQueue.find(agent_id);
|
||||
if (it != sPendingQueue.end())
|
||||
{
|
||||
bool request_expired = (it->second < expire_time);
|
||||
return !request_expired;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void LLAvatarNameCache::eraseExpired()
|
||||
{
|
||||
F64 now = LLFrameTimer::getTotalSeconds();
|
||||
cache_t::iterator it = sCache.begin();
|
||||
while (it != sCache.end())
|
||||
{
|
||||
cache_t::iterator cur = it;
|
||||
++it;
|
||||
const LLAvatarName& av_name = cur->second;
|
||||
if (av_name.mExpires < now)
|
||||
{
|
||||
sCache.erase(cur);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLAvatarNameCache::buildLegacyName(const std::string& full_name,
|
||||
LLAvatarName* av_name)
|
||||
{
|
||||
llassert(av_name);
|
||||
av_name->mUsername = "";
|
||||
av_name->mDisplayName = full_name;
|
||||
av_name->mIsDisplayNameDefault = true;
|
||||
av_name->mIsDummy = true;
|
||||
av_name->mExpires = F64_MAX;
|
||||
}
|
||||
|
||||
// fills in av_name if it has it in the cache, even if expired (can check expiry time)
|
||||
// returns bool specifying if av_name was filled, false otherwise
|
||||
bool LLAvatarNameCache::get(const LLUUID& agent_id, LLAvatarName *av_name)
|
||||
{
|
||||
if (sRunning)
|
||||
{
|
||||
// ...only do immediate lookups when cache is running
|
||||
if (useDisplayNames())
|
||||
{
|
||||
// ...use display names cache
|
||||
std::map<LLUUID,LLAvatarName>::iterator it = sCache.find(agent_id);
|
||||
if (it != sCache.end())
|
||||
{
|
||||
*av_name = it->second;
|
||||
|
||||
// re-request name if entry is expired
|
||||
if (av_name->mExpires < LLFrameTimer::getTotalSeconds())
|
||||
{
|
||||
if (!isRequestPending(agent_id))
|
||||
{
|
||||
sAskQueue.insert(agent_id);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// ...use legacy names cache
|
||||
std::string full_name;
|
||||
if (gCacheName->getFullName(agent_id, full_name))
|
||||
{
|
||||
buildLegacyName(full_name, av_name);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isRequestPending(agent_id))
|
||||
{
|
||||
sAskQueue.insert(agent_id);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void LLAvatarNameCache::fireSignal(const LLUUID& agent_id,
|
||||
const callback_slot_t& slot,
|
||||
const LLAvatarName& av_name)
|
||||
{
|
||||
callback_signal_t signal;
|
||||
signal.connect(slot);
|
||||
signal(agent_id, av_name);
|
||||
}
|
||||
|
||||
void LLAvatarNameCache::get(const LLUUID& agent_id, callback_slot_t slot)
|
||||
{
|
||||
if (sRunning)
|
||||
{
|
||||
// ...only do immediate lookups when cache is running
|
||||
if (useDisplayNames())
|
||||
{
|
||||
// ...use new cache
|
||||
std::map<LLUUID,LLAvatarName>::iterator it = sCache.find(agent_id);
|
||||
if (it != sCache.end())
|
||||
{
|
||||
const LLAvatarName& av_name = it->second;
|
||||
|
||||
if (av_name.mExpires > LLFrameTimer::getTotalSeconds())
|
||||
{
|
||||
// ...name already exists in cache, fire callback now
|
||||
fireSignal(agent_id, slot, av_name);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// ...use old name system
|
||||
std::string full_name;
|
||||
if (gCacheName->getFullName(agent_id, full_name))
|
||||
{
|
||||
LLAvatarName av_name;
|
||||
buildLegacyName(full_name, &av_name);
|
||||
fireSignal(agent_id, slot, av_name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// schedule a request
|
||||
if (!isRequestPending(agent_id))
|
||||
{
|
||||
sAskQueue.insert(agent_id);
|
||||
}
|
||||
|
||||
// always store additional callback, even if request is pending
|
||||
signal_map_t::iterator sig_it = sSignalMap.find(agent_id);
|
||||
if (sig_it == sSignalMap.end())
|
||||
{
|
||||
// ...new callback for this id
|
||||
callback_signal_t* signal = new callback_signal_t();
|
||||
signal->connect(slot);
|
||||
sSignalMap[agent_id] = signal;
|
||||
}
|
||||
else
|
||||
{
|
||||
// ...existing callback, bind additional slot
|
||||
callback_signal_t* signal = sig_it->second;
|
||||
signal->connect(slot);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LLAvatarNameCache::setUseDisplayNames(bool use)
|
||||
{
|
||||
if (use != sUseDisplayNames)
|
||||
{
|
||||
sUseDisplayNames = use;
|
||||
// flush our cache
|
||||
sCache.clear();
|
||||
|
||||
mUseDisplayNamesSignal();
|
||||
}
|
||||
}
|
||||
|
||||
bool LLAvatarNameCache::useDisplayNames()
|
||||
{
|
||||
// Must be both manually set on and able to look up names.
|
||||
return sUseDisplayNames && !sNameLookupURL.empty();
|
||||
}
|
||||
|
||||
void LLAvatarNameCache::erase(const LLUUID& agent_id)
|
||||
{
|
||||
sCache.erase(agent_id);
|
||||
}
|
||||
|
||||
void LLAvatarNameCache::fetch(const LLUUID& agent_id)
|
||||
{
|
||||
// re-request, even if request is already pending
|
||||
sAskQueue.insert(agent_id);
|
||||
}
|
||||
|
||||
void LLAvatarNameCache::insert(const LLUUID& agent_id, const LLAvatarName& av_name)
|
||||
{
|
||||
// *TODO: update timestamp if zero?
|
||||
sCache[agent_id] = av_name;
|
||||
}
|
||||
|
||||
F64 LLAvatarNameCache::nameExpirationFromHeaders(LLSD headers)
|
||||
{
|
||||
F64 expires = 0.0;
|
||||
if (expirationFromCacheControl(headers, &expires))
|
||||
{
|
||||
return expires;
|
||||
}
|
||||
else
|
||||
{
|
||||
// With no expiration info, default to an hour
|
||||
const F64 DEFAULT_EXPIRES = 60.0 * 60.0;
|
||||
F64 now = LLFrameTimer::getTotalSeconds();
|
||||
return now + DEFAULT_EXPIRES;
|
||||
}
|
||||
}
|
||||
|
||||
bool LLAvatarNameCache::expirationFromCacheControl(LLSD headers, F64 *expires)
|
||||
{
|
||||
// Allow the header to override the default
|
||||
LLSD cache_control_header = headers["cache-control"];
|
||||
if (cache_control_header.isDefined())
|
||||
{
|
||||
S32 max_age = 0;
|
||||
std::string cache_control = cache_control_header.asString();
|
||||
if (max_age_from_cache_control(cache_control, &max_age))
|
||||
{
|
||||
F64 now = LLFrameTimer::getTotalSeconds();
|
||||
*expires = now + (F64)max_age;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void LLAvatarNameCache::addUseDisplayNamesCallback(const use_display_name_signal_t::slot_type& cb)
|
||||
{
|
||||
mUseDisplayNamesSignal.connect(cb);
|
||||
}
|
||||
|
||||
|
||||
static const std::string MAX_AGE("max-age");
|
||||
static const boost::char_separator<char> EQUALS_SEPARATOR("=");
|
||||
static const boost::char_separator<char> COMMA_SEPARATOR(",");
|
||||
|
||||
bool max_age_from_cache_control(const std::string& cache_control, S32 *max_age)
|
||||
{
|
||||
// Split the string on "," to get a list of directives
|
||||
typedef boost::tokenizer<boost::char_separator<char> > 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;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
/**
|
||||
* @file llavatarnamecache.h
|
||||
* @brief Provides lookup of avatar SLIDs ("bobsmith123") and display names
|
||||
* ("James Cook") from avatar UUIDs.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2010&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 LLAVATARNAMECACHE_H
|
||||
#define LLAVATARNAMECACHE_H
|
||||
|
||||
#include "llavatarname.h" // for convenience
|
||||
|
||||
#include <boost/signals2.hpp>
|
||||
|
||||
class LLSD;
|
||||
class LLUUID;
|
||||
|
||||
namespace LLAvatarNameCache
|
||||
{
|
||||
|
||||
typedef boost::signals2::signal<void (void)> use_display_name_signal_t;
|
||||
|
||||
// Until the cache is set running, immediate lookups will fail and
|
||||
// async lookups will be queued. This allows us to block requests
|
||||
// until we know if the first region supports display names.
|
||||
void initClass(bool running);
|
||||
void cleanupClass();
|
||||
|
||||
void importFile(std::istream& istr);
|
||||
void exportFile(std::ostream& ostr);
|
||||
|
||||
// On the viewer, usually a simulator capabilitity
|
||||
// If empty, name cache will fall back to using legacy name
|
||||
// lookup system
|
||||
void setNameLookupURL(const std::string& name_lookup_url);
|
||||
|
||||
// Do we have a valid lookup URL, hence are we trying to use the
|
||||
// new display name lookup system?
|
||||
bool hasNameLookupURL();
|
||||
|
||||
// Periodically makes a batch request for display names not already in
|
||||
// cache. Call once per frame.
|
||||
void idle();
|
||||
|
||||
// If name is in cache, returns true and fills in provided LLAvatarName
|
||||
// otherwise returns false
|
||||
bool get(const LLUUID& agent_id, LLAvatarName *av_name);
|
||||
|
||||
// Callback types for get() below
|
||||
typedef boost::signals2::signal<
|
||||
void (const LLUUID& agent_id, const LLAvatarName& av_name)>
|
||||
callback_signal_t;
|
||||
typedef callback_signal_t::slot_type callback_slot_t;
|
||||
|
||||
// Fetches name information and calls callback.
|
||||
// If name information is in cache, callback will be called immediately.
|
||||
void get(const LLUUID& agent_id, callback_slot_t slot);
|
||||
|
||||
// Allow display names to be explicitly disabled for testing.
|
||||
void setUseDisplayNames(bool use);
|
||||
bool useDisplayNames();
|
||||
|
||||
void erase(const LLUUID& agent_id);
|
||||
|
||||
// Force a re-fetch of the most recent data, but keep the current
|
||||
// data in cache
|
||||
void fetch(const LLUUID& agent_id);
|
||||
|
||||
void insert(const LLUUID& agent_id, const LLAvatarName& av_name);
|
||||
|
||||
// Compute name expiration time from HTTP Cache-Control header,
|
||||
// or return default value, in seconds from epoch.
|
||||
F64 nameExpirationFromHeaders(LLSD headers);
|
||||
|
||||
void addUseDisplayNamesCallback(const use_display_name_signal_t::slot_type& cb);
|
||||
}
|
||||
|
||||
// Parse a cache-control header to get the max-age delta-seconds.
|
||||
// Returns true if header has max-age param and it parses correctly.
|
||||
// Exported here to ease unit testing.
|
||||
bool max_age_from_cache_control(const std::string& cache_control, S32 *max_age);
|
||||
|
||||
#endif
|
||||
|
|
@ -38,6 +38,8 @@
|
|||
#include "message.h"
|
||||
#include "llmemtype.h"
|
||||
|
||||
#include <boost/regex.hpp>
|
||||
|
||||
// llsd serialization constants
|
||||
static const std::string AGENTS("agents");
|
||||
static const std::string GROUPS("groups");
|
||||
|
|
@ -69,6 +71,8 @@ public:
|
|||
public:
|
||||
bool mIsGroup;
|
||||
U32 mCreateTime; // unix time_t
|
||||
// IDEVO TODO collapse names to one field, which will eliminate
|
||||
// many string compares on "Resident"
|
||||
std::string mFirstName;
|
||||
std::string mLastName;
|
||||
std::string mGroupName;
|
||||
|
|
@ -214,7 +218,9 @@ public:
|
|||
|
||||
Impl(LLMessageSystem* msg);
|
||||
~Impl();
|
||||
|
||||
|
||||
BOOL getName(const LLUUID& id, std::string& first, std::string& last);
|
||||
|
||||
boost::signals2::connection addPending(const LLUUID& id, const LLCacheNameCallback& callback);
|
||||
void addPending(const LLUUID& id, const LLHost& host);
|
||||
|
||||
|
|
@ -300,89 +306,10 @@ boost::signals2::connection LLCacheName::addObserver(const LLCacheNameCallback&
|
|||
return impl.mSignal.connect(callback);
|
||||
}
|
||||
|
||||
void LLCacheName::importFile(LLFILE* fp)
|
||||
{
|
||||
S32 count = 0;
|
||||
|
||||
const S32 BUFFER_SIZE = 1024;
|
||||
char buffer[BUFFER_SIZE]; /*Flawfinder: ignore*/
|
||||
|
||||
// *NOTE: These buffer sizes are hardcoded into sscanf() below
|
||||
char id_string[MAX_STRING]; /*Flawfinder: ignore*/
|
||||
char firstname[MAX_STRING]; /*Flawfinder: ignore*/
|
||||
char lastname[MAX_STRING]; /*Flawfinder: ignore*/
|
||||
U32 create_time;
|
||||
|
||||
// This is OK if the first line is actually a name. We just don't load it.
|
||||
char* valid = fgets(buffer, BUFFER_SIZE, fp);
|
||||
if (!valid) return;
|
||||
|
||||
// *NOTE: This buffer size is hardcoded into sscanf() below
|
||||
char version_string[BUFFER_SIZE]; /*Flawfinder: ignore*/
|
||||
S32 version = 0;
|
||||
S32 match = sscanf( /* Flawfinder: ignore */
|
||||
buffer,
|
||||
"%1023s %d",
|
||||
version_string, &version);
|
||||
if ( match != 2
|
||||
|| strcmp(version_string, "version")
|
||||
|| version != CN_FILE_VERSION)
|
||||
{
|
||||
llwarns << "Ignoring old cache name file format" << llendl;
|
||||
return;
|
||||
}
|
||||
|
||||
// We'll expire entries more than a week old
|
||||
U32 now = (U32)time(NULL);
|
||||
const U32 SECS_PER_DAY = 60 * 60 * 24;
|
||||
U32 delete_before_time = now - (7 * SECS_PER_DAY);
|
||||
|
||||
while(!feof(fp))
|
||||
{
|
||||
valid = fgets(buffer, BUFFER_SIZE, fp);
|
||||
if (!valid) break;
|
||||
|
||||
match = sscanf( /* Flawfinder: ignore */
|
||||
buffer,
|
||||
"%254s %u %254s %254s",
|
||||
id_string,
|
||||
&create_time,
|
||||
firstname,
|
||||
lastname);
|
||||
if (4 != match) continue;
|
||||
|
||||
LLUUID id(id_string);
|
||||
if (id.isNull()) continue;
|
||||
|
||||
// undo trivial XOR
|
||||
S32 i;
|
||||
for (i = 0; i < UUID_BYTES; i++)
|
||||
{
|
||||
id.mData[i] ^= 0x33;
|
||||
}
|
||||
|
||||
// Don't load entries that are more than a week old
|
||||
if (create_time < delete_before_time) continue;
|
||||
|
||||
LLCacheNameEntry* entry = new LLCacheNameEntry();
|
||||
entry->mIsGroup = false;
|
||||
entry->mCreateTime = create_time;
|
||||
entry->mFirstName = firstname;
|
||||
entry->mLastName = lastname;
|
||||
impl.mCache[id] = entry;
|
||||
std::string fullname = entry->mFirstName + " " + entry->mLastName;
|
||||
impl.mReverseCache[fullname] = id;
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
llinfos << "LLCacheName loaded " << count << " names" << llendl;
|
||||
}
|
||||
|
||||
bool LLCacheName::importFile(std::istream& istr)
|
||||
{
|
||||
LLSD data;
|
||||
if(LLSDSerialize::fromXML(data, istr) < 1)
|
||||
if(LLSDSerialize::fromXMLDocument(data, istr) < 1)
|
||||
return false;
|
||||
|
||||
// We'll expire entries more than a week old
|
||||
|
|
@ -408,7 +335,7 @@ bool LLCacheName::importFile(std::istream& istr)
|
|||
entry->mFirstName = agent[FIRST].asString();
|
||||
entry->mLastName = agent[LAST].asString();
|
||||
impl.mCache[id] = entry;
|
||||
std::string fullname = entry->mFirstName + " " + entry->mLastName;
|
||||
std::string fullname = buildFullName(entry->mFirstName, entry->mLastName);
|
||||
impl.mReverseCache[fullname] = id;
|
||||
|
||||
++count;
|
||||
|
|
@ -457,6 +384,7 @@ void LLCacheName::exportFile(std::ostream& ostr)
|
|||
// store it
|
||||
LLUUID id = iter->first;
|
||||
std::string id_str = id.asString();
|
||||
// IDEVO TODO: Should we store SLIDs with last name "Resident" or not?
|
||||
if(!entry->mFirstName.empty() && !entry->mLastName.empty())
|
||||
{
|
||||
data[AGENTS][id_str][FIRST] = entry->mFirstName;
|
||||
|
|
@ -474,7 +402,7 @@ void LLCacheName::exportFile(std::ostream& ostr)
|
|||
}
|
||||
|
||||
|
||||
BOOL LLCacheName::getName(const LLUUID& id, std::string& first, std::string& last)
|
||||
BOOL LLCacheName::Impl::getName(const LLUUID& id, std::string& first, std::string& last)
|
||||
{
|
||||
if(id.isNull())
|
||||
{
|
||||
|
|
@ -483,7 +411,7 @@ BOOL LLCacheName::getName(const LLUUID& id, std::string& first, std::string& las
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
LLCacheNameEntry* entry = get_ptr_in_map(impl.mCache, id );
|
||||
LLCacheNameEntry* entry = get_ptr_in_map(mCache, id );
|
||||
if (entry)
|
||||
{
|
||||
first = entry->mFirstName;
|
||||
|
|
@ -494,16 +422,17 @@ BOOL LLCacheName::getName(const LLUUID& id, std::string& first, std::string& las
|
|||
{
|
||||
first = sCacheName["waiting"];
|
||||
last.clear();
|
||||
if (!impl.isRequestPending(id))
|
||||
if (!isRequestPending(id))
|
||||
{
|
||||
impl.mAskNameQueue.insert(id);
|
||||
mAskNameQueue.insert(id);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// static
|
||||
void LLCacheName::LocalizeCacheName(std::string key, std::string value)
|
||||
void LLCacheName::localizeCacheName(std::string key, std::string value)
|
||||
{
|
||||
if (key!="" && value!= "" )
|
||||
sCacheName[key]=value;
|
||||
|
|
@ -514,11 +443,13 @@ void LLCacheName::LocalizeCacheName(std::string key, std::string value)
|
|||
BOOL LLCacheName::getFullName(const LLUUID& id, std::string& fullname)
|
||||
{
|
||||
std::string first_name, last_name;
|
||||
BOOL res = getName(id, first_name, last_name);
|
||||
fullname = first_name + " " + last_name;
|
||||
BOOL res = impl.getName(id, first_name, last_name);
|
||||
fullname = buildFullName(first_name, last_name);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
BOOL LLCacheName::getGroupName(const LLUUID& id, std::string& group)
|
||||
{
|
||||
if(id.isNull())
|
||||
|
|
@ -555,13 +486,13 @@ BOOL LLCacheName::getGroupName(const LLUUID& id, std::string& group)
|
|||
|
||||
BOOL LLCacheName::getUUID(const std::string& first, const std::string& last, LLUUID& id)
|
||||
{
|
||||
std::string fullname = first + " " + last;
|
||||
return getUUID(fullname, id);
|
||||
std::string full_name = buildFullName(first, last);
|
||||
return getUUID(full_name, id);
|
||||
}
|
||||
|
||||
BOOL LLCacheName::getUUID(const std::string& fullname, LLUUID& id)
|
||||
BOOL LLCacheName::getUUID(const std::string& full_name, LLUUID& id)
|
||||
{
|
||||
ReverseCache::iterator iter = impl.mReverseCache.find(fullname);
|
||||
ReverseCache::iterator iter = impl.mReverseCache.find(full_name);
|
||||
if (iter != impl.mReverseCache.end())
|
||||
{
|
||||
id = iter->second;
|
||||
|
|
@ -573,6 +504,89 @@ BOOL LLCacheName::getUUID(const std::string& fullname, LLUUID& id)
|
|||
}
|
||||
}
|
||||
|
||||
//static
|
||||
std::string LLCacheName::buildFullName(const std::string& first, const std::string& last)
|
||||
{
|
||||
std::string fullname = first;
|
||||
if (!last.empty()
|
||||
&& last != "Resident")
|
||||
{
|
||||
fullname += ' ';
|
||||
fullname += last;
|
||||
}
|
||||
return fullname;
|
||||
}
|
||||
|
||||
//static
|
||||
std::string LLCacheName::cleanFullName(const std::string& full_name)
|
||||
{
|
||||
return full_name.substr(0, full_name.find(" Resident"));
|
||||
}
|
||||
|
||||
//static
|
||||
std::string LLCacheName::buildUsername(const std::string& full_name)
|
||||
{
|
||||
// rare, but handle hard-coded error names returned from server
|
||||
if (full_name == "(\?\?\?) (\?\?\?)")
|
||||
{
|
||||
return "(\?\?\?)";
|
||||
}
|
||||
|
||||
std::string::size_type index = full_name.find(' ');
|
||||
|
||||
if (index != std::string::npos)
|
||||
{
|
||||
std::string username;
|
||||
username = full_name.substr(0, index);
|
||||
std::string lastname = full_name.substr(index+1);
|
||||
|
||||
if (lastname != "Resident")
|
||||
{
|
||||
username = username + "." + lastname;
|
||||
}
|
||||
|
||||
LLStringUtil::toLower(username);
|
||||
return username;
|
||||
}
|
||||
|
||||
// if the input wasn't a correctly formatted legacy name just return it unchanged
|
||||
return full_name;
|
||||
}
|
||||
|
||||
//static
|
||||
std::string LLCacheName::buildLegacyName(const std::string& complete_name)
|
||||
{
|
||||
// regexp doesn't play nice with unicode, chop off the display name
|
||||
S32 open_paren = complete_name.rfind(" (");
|
||||
|
||||
if (open_paren == std::string::npos)
|
||||
{
|
||||
return complete_name;
|
||||
}
|
||||
|
||||
std::string username = complete_name.substr(open_paren);
|
||||
boost::regex complete_name_regex("( \\()([a-z0-9]+)(.[a-z]+)*(\\))");
|
||||
boost::match_results<std::string::const_iterator> name_results;
|
||||
if (!boost::regex_match(username, name_results, complete_name_regex)) return complete_name;
|
||||
|
||||
std::string legacy_name = name_results[2];
|
||||
// capitalize the first letter
|
||||
std::string cap_letter = legacy_name.substr(0, 1);
|
||||
LLStringUtil::toUpper(cap_letter);
|
||||
legacy_name = cap_letter + legacy_name.substr(1);
|
||||
|
||||
if (name_results[3].matched)
|
||||
{
|
||||
std::string last_name = name_results[3];
|
||||
std::string cap_letter = last_name.substr(1, 1);
|
||||
LLStringUtil::toUpper(cap_letter);
|
||||
last_name = cap_letter + last_name.substr(2);
|
||||
legacy_name = legacy_name + " " + last_name;
|
||||
}
|
||||
|
||||
return legacy_name;
|
||||
}
|
||||
|
||||
// This is a little bit kludgy. LLCacheNameCallback is a slot instead of a function pointer.
|
||||
// The reason it is a slot is so that the legacy get() function below can bind an old callback
|
||||
// and pass it as a slot. The reason it isn't a boost::function is so that trackable behavior
|
||||
|
|
@ -580,7 +594,7 @@ BOOL LLCacheName::getUUID(const std::string& fullname, LLUUID& id)
|
|||
// we call it immediately. -Steve
|
||||
// NOTE: Even though passing first and last name is a bit of extra overhead, it eliminates the
|
||||
// potential need for any parsing should any code need to handle first and last name independently.
|
||||
boost::signals2::connection LLCacheName::get(const LLUUID& id, BOOL is_group, const LLCacheNameCallback& callback)
|
||||
boost::signals2::connection LLCacheName::get(const LLUUID& id, bool is_group, const LLCacheNameCallback& callback)
|
||||
{
|
||||
boost::signals2::connection res;
|
||||
|
||||
|
|
@ -588,7 +602,7 @@ boost::signals2::connection LLCacheName::get(const LLUUID& id, BOOL is_group, co
|
|||
{
|
||||
LLCacheNameSignal signal;
|
||||
signal.connect(callback);
|
||||
signal(id, sCacheName["nobody"], "", is_group);
|
||||
signal(id, sCacheName["nobody"], is_group);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
@ -600,11 +614,13 @@ boost::signals2::connection LLCacheName::get(const LLUUID& id, BOOL is_group, co
|
|||
// id found in map therefore we can call the callback immediately.
|
||||
if (entry->mIsGroup)
|
||||
{
|
||||
signal(id, entry->mGroupName, "", entry->mIsGroup);
|
||||
signal(id, entry->mGroupName, entry->mIsGroup);
|
||||
}
|
||||
else
|
||||
{
|
||||
signal(id, entry->mFirstName, entry->mLastName, entry->mIsGroup);
|
||||
std::string fullname =
|
||||
buildFullName(entry->mFirstName, entry->mLastName);
|
||||
signal(id, fullname, entry->mIsGroup);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -626,9 +642,15 @@ boost::signals2::connection LLCacheName::get(const LLUUID& id, BOOL is_group, co
|
|||
return res;
|
||||
}
|
||||
|
||||
boost::signals2::connection LLCacheName::get(const LLUUID& id, BOOL is_group, old_callback_t callback, void* user_data)
|
||||
boost::signals2::connection LLCacheName::getGroup(const LLUUID& group_id,
|
||||
const LLCacheNameCallback& callback)
|
||||
{
|
||||
return get(id, is_group, boost::bind(callback, _1, _2, _3, _4, user_data));
|
||||
return get(group_id, true, callback);
|
||||
}
|
||||
|
||||
boost::signals2::connection LLCacheName::get(const LLUUID& id, bool is_group, old_callback_t callback, void* user_data)
|
||||
{
|
||||
return get(id, is_group, boost::bind(callback, _1, _2, _3, user_data));
|
||||
}
|
||||
|
||||
void LLCacheName::processPending()
|
||||
|
|
@ -700,7 +722,7 @@ void LLCacheName::dump()
|
|||
{
|
||||
llinfos
|
||||
<< iter->first << " = "
|
||||
<< entry->mFirstName << " " << entry->mLastName
|
||||
<< buildFullName(entry->mFirstName, entry->mLastName)
|
||||
<< " @ " << entry->mCreateTime
|
||||
<< llendl;
|
||||
}
|
||||
|
|
@ -719,12 +741,24 @@ void LLCacheName::dumpStats()
|
|||
<< llendl;
|
||||
}
|
||||
|
||||
void LLCacheName::clear()
|
||||
{
|
||||
for_each(impl.mCache.begin(), impl.mCache.end(), DeletePairedPointer());
|
||||
impl.mCache.clear();
|
||||
}
|
||||
|
||||
//static
|
||||
std::string LLCacheName::getDefaultName()
|
||||
{
|
||||
return sCacheName["waiting"];
|
||||
}
|
||||
|
||||
//static
|
||||
std::string LLCacheName::getDefaultLastName()
|
||||
{
|
||||
return "Resident";
|
||||
}
|
||||
|
||||
void LLCacheName::Impl::processPendingAsks()
|
||||
{
|
||||
LLMemType mt_ppa(LLMemType::MTYPE_CACHE_PROCESS_PENDING_ASKS);
|
||||
|
|
@ -746,11 +780,13 @@ void LLCacheName::Impl::processPendingReplies()
|
|||
|
||||
if (!entry->mIsGroup)
|
||||
{
|
||||
(reply->mSignal)(reply->mID, entry->mFirstName, entry->mLastName, FALSE);
|
||||
std::string fullname =
|
||||
LLCacheName::buildFullName(entry->mFirstName, entry->mLastName);
|
||||
(reply->mSignal)(reply->mID, fullname, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
(reply->mSignal)(reply->mID, entry->mGroupName, "", TRUE);
|
||||
(reply->mSignal)(reply->mID, entry->mGroupName, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -921,13 +957,27 @@ void LLCacheName::Impl::processUUIDReply(LLMessageSystem* msg, bool isGroup)
|
|||
|
||||
if (!isGroup)
|
||||
{
|
||||
mSignal(id, entry->mFirstName, entry->mLastName, FALSE);
|
||||
std::string fullname = entry->mFirstName + " " + entry->mLastName;
|
||||
mReverseCache[fullname] = id;
|
||||
// NOTE: Very occasionally the server sends down a full name
|
||||
// in the first name field with an empty last name, for example,
|
||||
// first = "Ladanie1 Resident", last = "".
|
||||
// I cannot reproduce this, nor can I find a bug in the server code.
|
||||
// Ensure "Resident" does not appear via cleanFullName, because
|
||||
// buildFullName only checks last name. JC
|
||||
std::string full_name;
|
||||
if (entry->mLastName.empty())
|
||||
{
|
||||
full_name = cleanFullName(entry->mFirstName);
|
||||
}
|
||||
else
|
||||
{
|
||||
full_name = LLCacheName::buildFullName(entry->mFirstName, entry->mLastName);
|
||||
}
|
||||
mSignal(id, full_name, false);
|
||||
mReverseCache[full_name] = id;
|
||||
}
|
||||
else
|
||||
{
|
||||
mSignal(id, entry->mGroupName, "", TRUE);
|
||||
mSignal(id, entry->mGroupName, true);
|
||||
mReverseCache[entry->mGroupName] = id;
|
||||
}
|
||||
}
|
||||
|
|
@ -956,4 +1006,3 @@ void LLCacheName::Impl::handleUUIDGroupNameReply(LLMessageSystem* msg, void** us
|
|||
{
|
||||
((LLCacheName::Impl*)userData)->processUUIDReply(msg, true);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -36,13 +36,12 @@ class LLUUID;
|
|||
|
||||
|
||||
typedef boost::signals2::signal<void (const LLUUID& id,
|
||||
const std::string& first_name,
|
||||
const std::string& last_name,
|
||||
BOOL is_group)> LLCacheNameSignal;
|
||||
const std::string& name,
|
||||
bool is_group)> LLCacheNameSignal;
|
||||
typedef LLCacheNameSignal::slot_type LLCacheNameCallback;
|
||||
|
||||
// Old callback with user data for compatability
|
||||
typedef void (*old_callback_t)(const LLUUID&, const std::string&, const std::string&, BOOL, void*);
|
||||
typedef void (*old_callback_t)(const LLUUID&, const std::string&, bool, void*);
|
||||
|
||||
// Here's the theory:
|
||||
// If you request a name that isn't in the cache, it returns "waiting"
|
||||
|
|
@ -65,24 +64,37 @@ public:
|
|||
|
||||
boost::signals2::connection addObserver(const LLCacheNameCallback& callback);
|
||||
|
||||
// janky old format. Remove after a while. Phoenix. 2008-01-30
|
||||
void importFile(LLFILE* fp);
|
||||
|
||||
// storing cache on disk; for viewer, in name.cache
|
||||
bool importFile(std::istream& istr);
|
||||
void exportFile(std::ostream& ostr);
|
||||
|
||||
// If available, copies the first and last name into the strings provided.
|
||||
// first must be at least DB_FIRST_NAME_BUF_SIZE characters.
|
||||
// last must be at least DB_LAST_NAME_BUF_SIZE characters.
|
||||
// If available, copies name ("bobsmith123" or "James Linden") into string
|
||||
// If not available, copies the string "waiting".
|
||||
// Returns TRUE iff available.
|
||||
BOOL getName(const LLUUID& id, std::string& first, std::string& last);
|
||||
BOOL getFullName(const LLUUID& id, std::string& fullname);
|
||||
|
||||
BOOL getFullName(const LLUUID& id, std::string& full_name);
|
||||
|
||||
// Reverse lookup of UUID from name
|
||||
BOOL getUUID(const std::string& first, const std::string& last, LLUUID& id);
|
||||
BOOL getUUID(const std::string& fullname, LLUUID& id);
|
||||
|
||||
// IDEVO Temporary code
|
||||
// Clean up new-style "bobsmith123 Resident" names to "bobsmith123" for display
|
||||
static std::string buildFullName(const std::string& first, const std::string& last);
|
||||
|
||||
// Clean up legacy "bobsmith123 Resident" to "bobsmith123"
|
||||
// If name does not contain "Resident" returns it unchanged.
|
||||
static std::string cleanFullName(const std::string& full_name);
|
||||
|
||||
// Converts a standard legacy name to a username
|
||||
// "bobsmith123 Resident" -> "bobsmith"
|
||||
// "Random Linden" -> "random.linden"
|
||||
static std::string buildUsername(const std::string& name);
|
||||
|
||||
// Converts a complete display name to a legacy name
|
||||
// if possible, otherwise returns the input
|
||||
// "Alias (random.linden)" -> "Random Linden"
|
||||
// "Something random" -> "Something random"
|
||||
static std::string buildLegacyName(const std::string& name);
|
||||
|
||||
// If available, this method copies the group name into the string
|
||||
// provided. The caller must allocate at least
|
||||
|
|
@ -94,10 +106,15 @@ public:
|
|||
// If the data is currently available, may call the callback immediatly
|
||||
// otherwise, will request the data, and will call the callback when
|
||||
// available. There is no garuntee the callback will ever be called.
|
||||
boost::signals2::connection get(const LLUUID& id, BOOL is_group, const LLCacheNameCallback& callback);
|
||||
|
||||
boost::signals2::connection get(const LLUUID& id, bool is_group, const LLCacheNameCallback& callback);
|
||||
|
||||
// Convenience method for looking up a group name, so you can
|
||||
// tell the difference between avatar lookup and group lookup
|
||||
// in global searches
|
||||
boost::signals2::connection getGroup(const LLUUID& group_id, const LLCacheNameCallback& callback);
|
||||
|
||||
// LEGACY
|
||||
boost::signals2::connection get(const LLUUID& id, BOOL is_group, old_callback_t callback, void* user_data);
|
||||
boost::signals2::connection get(const LLUUID& id, bool is_group, old_callback_t callback, void* user_data);
|
||||
// This method needs to be called from time to time to send out
|
||||
// requests.
|
||||
void processPending();
|
||||
|
|
@ -108,9 +125,15 @@ public:
|
|||
// Debugging
|
||||
void dump(); // Dumps the contents of the cache
|
||||
void dumpStats(); // Dumps the sizes of the cache and associated queues.
|
||||
void clear(); // Deletes all entries from the cache
|
||||
|
||||
static std::string getDefaultName();
|
||||
static void LocalizeCacheName(std::string key, std::string value);
|
||||
|
||||
// Returns "Resident", the default last name for SLID-based accounts
|
||||
// that have no last name.
|
||||
static std::string getDefaultLastName();
|
||||
|
||||
static void localizeCacheName(std::string key, std::string value);
|
||||
static std::map<std::string, std::string> sCacheName;
|
||||
private:
|
||||
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ public:
|
|||
|
||||
LLMeanCollisionData(LLMeanCollisionData *mcd)
|
||||
: mVictim(mcd->mVictim), mPerp(mcd->mPerp), mTime(mcd->mTime), mType(mcd->mType), mMag(mcd->mMag),
|
||||
mFirstName(mcd->mFirstName), mLastName(mcd->mLastName)
|
||||
mFullName(mcd->mFullName)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -89,8 +89,7 @@ public:
|
|||
time_t mTime;
|
||||
EMeanCollisionType mType;
|
||||
F32 mMag;
|
||||
std::string mFirstName;
|
||||
std::string mLastName;
|
||||
std::string mFullName;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,102 @@
|
|||
/**
|
||||
* @file llavatarnamecache_test.cpp
|
||||
* @author James Cook
|
||||
* @brief LLAvatarNameCache test cases.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2010&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 "../llavatarnamecache.h"
|
||||
|
||||
#include "../test/lltut.h"
|
||||
|
||||
namespace tut
|
||||
{
|
||||
struct avatarnamecache_data
|
||||
{
|
||||
};
|
||||
typedef test_group<avatarnamecache_data> avatarnamecache_test;
|
||||
typedef avatarnamecache_test::object avatarnamecache_object;
|
||||
tut::avatarnamecache_test avatarnamecache_testcase("LLAvatarNameCache");
|
||||
|
||||
template<> template<>
|
||||
void avatarnamecache_object::test<1>()
|
||||
{
|
||||
bool valid = false;
|
||||
S32 max_age = 0;
|
||||
|
||||
valid = max_age_from_cache_control("max-age=3600", &max_age);
|
||||
ensure("typical input valid", valid);
|
||||
ensure_equals("typical input parsed", max_age, 3600);
|
||||
|
||||
valid = max_age_from_cache_control(
|
||||
" max-age=600 , no-cache,private=\"stuff\" ", &max_age);
|
||||
ensure("complex input valid", valid);
|
||||
ensure_equals("complex input parsed", max_age, 600);
|
||||
|
||||
valid = max_age_from_cache_control(
|
||||
"no-cache, max-age = 123 ", &max_age);
|
||||
ensure("complex input 2 valid", valid);
|
||||
ensure_equals("complex input 2 parsed", max_age, 123);
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void avatarnamecache_object::test<2>()
|
||||
{
|
||||
bool valid = false;
|
||||
S32 max_age = -1;
|
||||
|
||||
valid = max_age_from_cache_control("", &max_age);
|
||||
ensure("empty input returns invalid", !valid);
|
||||
ensure_equals("empty input doesn't change val", max_age, -1);
|
||||
|
||||
valid = max_age_from_cache_control("no-cache", &max_age);
|
||||
ensure("no max-age field returns invalid", !valid);
|
||||
|
||||
valid = max_age_from_cache_control("max", &max_age);
|
||||
ensure("just 'max' returns invalid", !valid);
|
||||
|
||||
valid = max_age_from_cache_control("max-age", &max_age);
|
||||
ensure("partial max-age is invalid", !valid);
|
||||
|
||||
valid = max_age_from_cache_control("max-age=", &max_age);
|
||||
ensure("longer partial max-age is invalid", !valid);
|
||||
|
||||
valid = max_age_from_cache_control("max-age=FOO", &max_age);
|
||||
ensure("invalid integer max-age is invalid", !valid);
|
||||
|
||||
valid = max_age_from_cache_control("max-age 234", &max_age);
|
||||
ensure("space separated max-age is invalid", !valid);
|
||||
|
||||
valid = max_age_from_cache_control("max-age=0", &max_age);
|
||||
ensure("zero max-age is valid", valid);
|
||||
|
||||
// *TODO: Handle "0000" as zero
|
||||
//valid = max_age_from_cache_control("max-age=0000", &max_age);
|
||||
//ensure("multi-zero max-age is valid", valid);
|
||||
|
||||
valid = max_age_from_cache_control("max-age=-123", &max_age);
|
||||
ensure("less than zero max-age is invalid", !valid);
|
||||
}
|
||||
}
|
||||
|
|
@ -51,6 +51,14 @@ 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})
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ bool LLPluginClassMedia::init(const std::string &launcher_filename, const std::s
|
|||
|
||||
// Queue up the media init message -- it will be sent after all the currently queued messages.
|
||||
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "init");
|
||||
message.setValue("target", mTarget);
|
||||
sendMessage(message);
|
||||
|
||||
mPlugin->init(launcher_filename, plugin_filename, debug);
|
||||
|
|
@ -143,7 +144,7 @@ void LLPluginClassMedia::reset()
|
|||
mProgressPercent = 0;
|
||||
mClickURL.clear();
|
||||
mClickTarget.clear();
|
||||
mClickTargetType = TARGET_NONE;
|
||||
mClickUUID.clear();
|
||||
|
||||
// media_time class
|
||||
mCurrentTime = 0.0f;
|
||||
|
|
@ -669,6 +670,18 @@ F64 LLPluginClassMedia::getCPUUsage()
|
|||
return result;
|
||||
}
|
||||
|
||||
void LLPluginClassMedia::sendPickFileResponse(const std::string &file)
|
||||
{
|
||||
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "pick_file_response");
|
||||
message.setValue("file", file);
|
||||
if(mPlugin->isBlocked())
|
||||
{
|
||||
// If the plugin sent a blocking pick-file request, the response should unblock it.
|
||||
message.setValueBoolean("blocking_response", true);
|
||||
}
|
||||
sendMessage(message);
|
||||
}
|
||||
|
||||
void LLPluginClassMedia::cut()
|
||||
{
|
||||
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_cut");
|
||||
|
|
@ -715,24 +728,9 @@ void LLPluginClassMedia::setJavascriptEnabled(const bool enabled)
|
|||
sendMessage(message);
|
||||
}
|
||||
|
||||
LLPluginClassMedia::ETargetType getTargetTypeFromLLQtWebkit(int target_type)
|
||||
void LLPluginClassMedia::setTarget(const std::string &target)
|
||||
{
|
||||
// convert a LinkTargetType value from llqtwebkit to an ETargetType
|
||||
// so that we don't expose the llqtwebkit header in viewer code
|
||||
switch (target_type)
|
||||
{
|
||||
case LLQtWebKit::LTT_TARGET_NONE:
|
||||
return LLPluginClassMedia::TARGET_NONE;
|
||||
|
||||
case LLQtWebKit::LTT_TARGET_BLANK:
|
||||
return LLPluginClassMedia::TARGET_BLANK;
|
||||
|
||||
case LLQtWebKit::LTT_TARGET_EXTERNAL:
|
||||
return LLPluginClassMedia::TARGET_EXTERNAL;
|
||||
|
||||
default:
|
||||
return LLPluginClassMedia::TARGET_OTHER;
|
||||
}
|
||||
mTarget = target;
|
||||
}
|
||||
|
||||
/* virtual */
|
||||
|
|
@ -945,6 +943,10 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
|
|||
mMediaName = message.getValue("name");
|
||||
mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAME_CHANGED);
|
||||
}
|
||||
else if(message_name == "pick_file")
|
||||
{
|
||||
mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PICK_FILE_REQUEST);
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL;
|
||||
|
|
@ -987,15 +989,13 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
|
|||
{
|
||||
mClickURL = message.getValue("uri");
|
||||
mClickTarget = message.getValue("target");
|
||||
U32 target_type = message.getValueU32("target_type");
|
||||
mClickTargetType = ::getTargetTypeFromLLQtWebkit(target_type);
|
||||
mClickUUID = message.getValue("uuid");
|
||||
mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLICK_LINK_HREF);
|
||||
}
|
||||
else if(message_name == "click_nofollow")
|
||||
{
|
||||
mClickURL = message.getValue("uri");
|
||||
mClickTarget.clear();
|
||||
mClickTargetType = TARGET_NONE;
|
||||
mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLICK_LINK_NOFOLLOW);
|
||||
}
|
||||
else if(message_name == "cookie_set")
|
||||
|
|
@ -1005,6 +1005,20 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
|
|||
mOwner->handleCookieSet(this, message.getValue("cookie"));
|
||||
}
|
||||
}
|
||||
else if(message_name == "close_request")
|
||||
{
|
||||
mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLOSE_REQUEST);
|
||||
}
|
||||
else if(message_name == "geometry_change")
|
||||
{
|
||||
mClickUUID = message.getValue("uuid");
|
||||
mGeometryX = message.getValueS32("x");
|
||||
mGeometryY = message.getValueS32("y");
|
||||
mGeometryWidth = message.getValueS32("width");
|
||||
mGeometryHeight = message.getValueS32("height");
|
||||
|
||||
mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_GEOMETRY_CHANGE);
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL;
|
||||
|
|
@ -1159,6 +1173,25 @@ void LLPluginClassMedia::setBrowserUserAgent(const std::string& user_agent)
|
|||
sendMessage(message);
|
||||
}
|
||||
|
||||
void LLPluginClassMedia::proxyWindowOpened(const std::string &target, const std::string &uuid)
|
||||
{
|
||||
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "proxy_window_opened");
|
||||
|
||||
message.setValue("target", target);
|
||||
message.setValue("uuid", uuid);
|
||||
|
||||
sendMessage(message);
|
||||
}
|
||||
|
||||
void LLPluginClassMedia::proxyWindowClosed(const std::string &uuid)
|
||||
{
|
||||
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "proxy_window_closed");
|
||||
|
||||
message.setValue("uuid", uuid);
|
||||
|
||||
sendMessage(message);
|
||||
}
|
||||
|
||||
void LLPluginClassMedia::crashPlugin()
|
||||
{
|
||||
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "crash");
|
||||
|
|
|
|||
|
|
@ -156,6 +156,8 @@ public:
|
|||
void setLowPrioritySizeLimit(int size);
|
||||
|
||||
F64 getCPUUsage();
|
||||
|
||||
void sendPickFileResponse(const std::string &file);
|
||||
|
||||
// Valid after a MEDIA_EVENT_CURSOR_CHANGED event
|
||||
std::string getCursorName() const { return mCursorName; };
|
||||
|
|
@ -176,7 +178,8 @@ public:
|
|||
void setLanguageCode(const std::string &language_code);
|
||||
void setPluginsEnabled(const bool enabled);
|
||||
void setJavascriptEnabled(const bool enabled);
|
||||
|
||||
void setTarget(const std::string &target);
|
||||
|
||||
///////////////////////////////////
|
||||
// media browser class functions
|
||||
bool pluginSupportsMediaBrowser(void);
|
||||
|
|
@ -193,6 +196,8 @@ public:
|
|||
void browse_back();
|
||||
void set_status_redirect(int code, const std::string &url);
|
||||
void setBrowserUserAgent(const std::string& user_agent);
|
||||
void proxyWindowOpened(const std::string &target, const std::string &uuid);
|
||||
void proxyWindowClosed(const std::string &uuid);
|
||||
|
||||
// This is valid after MEDIA_EVENT_NAVIGATE_BEGIN or MEDIA_EVENT_NAVIGATE_COMPLETE
|
||||
std::string getNavigateURI() const { return mNavigateURI; };
|
||||
|
|
@ -218,16 +223,14 @@ public:
|
|||
// This is valid after MEDIA_EVENT_CLICK_LINK_HREF
|
||||
std::string getClickTarget() const { return mClickTarget; };
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TARGET_NONE, // empty href target string
|
||||
TARGET_BLANK, // target to open link in user's preferred browser
|
||||
TARGET_EXTERNAL, // target to open link in external browser
|
||||
TARGET_OTHER // nonempty and unsupported target type
|
||||
}ETargetType;
|
||||
|
||||
// This is valid after MEDIA_EVENT_CLICK_LINK_HREF
|
||||
ETargetType getClickTargetType() const { return mClickTargetType; };
|
||||
// This is valid during MEDIA_EVENT_CLICK_LINK_HREF and MEDIA_EVENT_GEOMETRY_CHANGE
|
||||
std::string getClickUUID() const { return mClickUUID; };
|
||||
|
||||
// These are valid during MEDIA_EVENT_GEOMETRY_CHANGE
|
||||
S32 getGeometryX() const { return mGeometryX; };
|
||||
S32 getGeometryY() const { return mGeometryY; };
|
||||
S32 getGeometryWidth() const { return mGeometryWidth; };
|
||||
S32 getGeometryHeight() const { return mGeometryHeight; };
|
||||
|
||||
std::string getMediaName() const { return mMediaName; };
|
||||
std::string getMediaDescription() const { return mMediaDescription; };
|
||||
|
|
@ -347,6 +350,8 @@ protected:
|
|||
|
||||
LLColor4 mBackgroundColor;
|
||||
|
||||
std::string mTarget;
|
||||
|
||||
/////////////////////////////////////////
|
||||
// media_browser class
|
||||
std::string mNavigateURI;
|
||||
|
|
@ -359,7 +364,11 @@ protected:
|
|||
std::string mLocation;
|
||||
std::string mClickURL;
|
||||
std::string mClickTarget;
|
||||
ETargetType mClickTargetType;
|
||||
std::string mClickUUID;
|
||||
S32 mGeometryX;
|
||||
S32 mGeometryY;
|
||||
S32 mGeometryWidth;
|
||||
S32 mGeometryHeight;
|
||||
|
||||
/////////////////////////////////////////
|
||||
// media_time class
|
||||
|
|
|
|||
|
|
@ -54,6 +54,9 @@ public:
|
|||
MEDIA_EVENT_LOCATION_CHANGED, // browser location (URL) has changed (maybe due to internal navagation/frames/etc)
|
||||
MEDIA_EVENT_CLICK_LINK_HREF, // I'm not entirely sure what the semantics of these two are
|
||||
MEDIA_EVENT_CLICK_LINK_NOFOLLOW,
|
||||
MEDIA_EVENT_CLOSE_REQUEST, // The plugin requested its window be closed (currently hooked up to javascript window.close in webkit)
|
||||
MEDIA_EVENT_PICK_FILE_REQUEST, // The plugin wants the user to pick a file
|
||||
MEDIA_EVENT_GEOMETRY_CHANGE, // The plugin requested its window geometry be changed (per the javascript window interface)
|
||||
|
||||
MEDIA_EVENT_PLUGIN_FAILED_LAUNCH, // The plugin failed to launch
|
||||
MEDIA_EVENT_PLUGIN_FAILED // The plugin died unexpectedly
|
||||
|
|
|
|||
|
|
@ -79,4 +79,6 @@ if (DARWIN)
|
|||
)
|
||||
endif (DARWIN)
|
||||
|
||||
ll_deploy_sharedlibs_command(SLPlugin)
|
||||
if (LL_TESTS)
|
||||
ll_deploy_sharedlibs_command(SLPlugin)
|
||||
endif (LL_TESTS)
|
||||
|
|
|
|||
|
|
@ -281,7 +281,7 @@ int main(int argc, char **argv)
|
|||
}
|
||||
|
||||
// Check for a change in this process's frontmost window.
|
||||
if(FrontWindow() != front_window)
|
||||
if(GetFrontWindowOfClass(kAllWindowClasses, true) != front_window)
|
||||
{
|
||||
ProcessSerialNumber self = { 0, kCurrentProcess };
|
||||
ProcessSerialNumber parent = { 0, kNoProcess };
|
||||
|
|
@ -307,7 +307,7 @@ int main(int argc, char **argv)
|
|||
}
|
||||
}
|
||||
|
||||
if((FrontWindow() != NULL) && (front_window == NULL))
|
||||
if((GetFrontWindowOfClass(kAllWindowClasses, true) != NULL) && (front_window == NULL))
|
||||
{
|
||||
// Opening the first window
|
||||
|
||||
|
|
@ -319,7 +319,7 @@ int main(int argc, char **argv)
|
|||
|
||||
if(layer_group)
|
||||
{
|
||||
SetWindowGroup(FrontWindow(), layer_group);
|
||||
SetWindowGroup(GetFrontWindowOfClass(kAllWindowClasses, true), layer_group);
|
||||
}
|
||||
|
||||
if(parent_is_front_process)
|
||||
|
|
@ -328,9 +328,9 @@ int main(int argc, char **argv)
|
|||
(void) SetFrontProcess( &self );
|
||||
}
|
||||
|
||||
ActivateWindow(FrontWindow(), true);
|
||||
ActivateWindow(GetFrontWindowOfClass(kAllWindowClasses, true), true);
|
||||
}
|
||||
else if((FrontWindow() == NULL) && (front_window != NULL))
|
||||
else if((GetFrontWindowOfClass(kAllWindowClasses, true) == NULL) && (front_window != NULL))
|
||||
{
|
||||
// Closing the last window
|
||||
|
||||
|
|
@ -350,7 +350,7 @@ int main(int argc, char **argv)
|
|||
window_hack_state = 2;
|
||||
}
|
||||
|
||||
front_window = FrontWindow();
|
||||
front_window = GetFrontWindowOfClass(kAllWindowClasses, true);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -977,37 +977,43 @@ LLFontGL::VAlign LLFontGL::vAlignFromName(const std::string& name)
|
|||
//static
|
||||
LLFontGL* LLFontGL::getFontMonospace()
|
||||
{
|
||||
return getFont(LLFontDescriptor("Monospace","Monospace",0));
|
||||
static LLFontGL* fontp = getFont(LLFontDescriptor("Monospace","Monospace",0));
|
||||
return fontp;
|
||||
}
|
||||
|
||||
//static
|
||||
LLFontGL* LLFontGL::getFontSansSerifSmall()
|
||||
{
|
||||
return getFont(LLFontDescriptor("SansSerif","Small",0));
|
||||
static LLFontGL* fontp = getFont(LLFontDescriptor("SansSerif","Small",0));
|
||||
return fontp;
|
||||
}
|
||||
|
||||
//static
|
||||
LLFontGL* LLFontGL::getFontSansSerif()
|
||||
{
|
||||
return getFont(LLFontDescriptor("SansSerif","Medium",0));
|
||||
static LLFontGL* fontp = getFont(LLFontDescriptor("SansSerif","Medium",0));
|
||||
return fontp;
|
||||
}
|
||||
|
||||
//static
|
||||
LLFontGL* LLFontGL::getFontSansSerifBig()
|
||||
{
|
||||
return getFont(LLFontDescriptor("SansSerif","Large",0));
|
||||
static LLFontGL* fontp = getFont(LLFontDescriptor("SansSerif","Large",0));
|
||||
return fontp;
|
||||
}
|
||||
|
||||
//static
|
||||
LLFontGL* LLFontGL::getFontSansSerifHuge()
|
||||
{
|
||||
return getFont(LLFontDescriptor("SansSerif","Huge",0));
|
||||
static LLFontGL* fontp = getFont(LLFontDescriptor("SansSerif","Large",0));
|
||||
return fontp;
|
||||
}
|
||||
|
||||
//static
|
||||
LLFontGL* LLFontGL::getFontSansSerifBold()
|
||||
{
|
||||
return getFont(LLFontDescriptor("SansSerif","Medium",BOLD));
|
||||
static LLFontGL* fontp = getFont(LLFontDescriptor("SansSerif","Medium",BOLD));
|
||||
return fontp;
|
||||
}
|
||||
|
||||
//static
|
||||
|
|
|
|||
|
|
@ -368,6 +368,18 @@ void LLImageGL::restoreGL()
|
|||
}
|
||||
}
|
||||
|
||||
//static
|
||||
void LLImageGL::dirtyTexOptions()
|
||||
{
|
||||
for (std::set<LLImageGL*>::iterator iter = sImageList.begin();
|
||||
iter != sImageList.end(); iter++)
|
||||
{
|
||||
LLImageGL* glimage = *iter;
|
||||
glimage->mTexOptionsDirty = true;
|
||||
stop_glerror();
|
||||
}
|
||||
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
//for server side use only.
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ public:
|
|||
// Save off / restore GL textures
|
||||
static void destroyGL(BOOL save_state = TRUE);
|
||||
static void restoreGL();
|
||||
static void dirtyTexOptions();
|
||||
|
||||
// Sometimes called externally for textures not using LLImageGL (should go away...)
|
||||
static S32 updateBoundTexMem(const S32 mem, const S32 ncomponents, S32 category) ;
|
||||
|
|
|
|||
|
|
@ -384,8 +384,6 @@ void LLRenderTarget::flush(BOOL fetch_depth)
|
|||
}
|
||||
else
|
||||
{
|
||||
#if !LL_DARWIN
|
||||
|
||||
stop_glerror();
|
||||
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
||||
|
|
@ -429,7 +427,6 @@ void LLRenderTarget::flush(BOOL fetch_depth)
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
||||
}
|
||||
|
|
@ -438,7 +435,6 @@ void LLRenderTarget::flush(BOOL fetch_depth)
|
|||
void LLRenderTarget::copyContents(LLRenderTarget& source, S32 srcX0, S32 srcY0, S32 srcX1, S32 srcY1,
|
||||
S32 dstX0, S32 dstY0, S32 dstX1, S32 dstY1, U32 mask, U32 filter)
|
||||
{
|
||||
#if !LL_DARWIN
|
||||
gGL.flush();
|
||||
if (!source.mFBO || !mFBO)
|
||||
{
|
||||
|
|
@ -477,14 +473,12 @@ void LLRenderTarget::copyContents(LLRenderTarget& source, S32 srcX0, S32 srcY0,
|
|||
stop_glerror();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//static
|
||||
void LLRenderTarget::copyContentsToFramebuffer(LLRenderTarget& source, S32 srcX0, S32 srcY0, S32 srcX1, S32 srcY1,
|
||||
S32 dstX0, S32 dstY0, S32 dstX1, S32 dstY1, U32 mask, U32 filter)
|
||||
{
|
||||
#if !LL_DARWIN
|
||||
if (!source.mFBO)
|
||||
{
|
||||
llerrs << "Cannot copy framebuffer contents for non FBO render targets." << llendl;
|
||||
|
|
@ -501,7 +495,6 @@ void LLRenderTarget::copyContentsToFramebuffer(LLRenderTarget& source, S32 srcX0
|
|||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
||||
stop_glerror();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
BOOL LLRenderTarget::isComplete() const
|
||||
|
|
@ -646,7 +639,6 @@ void LLMultisampleBuffer::allocate(U32 resx, U32 resy, U32 color_fmt, BOOL depth
|
|||
|
||||
void LLMultisampleBuffer::addColorAttachment(U32 color_fmt)
|
||||
{
|
||||
#if !LL_DARWIN
|
||||
if (color_fmt == 0)
|
||||
{
|
||||
return;
|
||||
|
|
@ -687,12 +679,10 @@ void LLMultisampleBuffer::addColorAttachment(U32 color_fmt)
|
|||
}
|
||||
|
||||
mTex.push_back(tex);
|
||||
#endif
|
||||
}
|
||||
|
||||
void LLMultisampleBuffer::allocateDepth()
|
||||
{
|
||||
#if !LL_DARWIN
|
||||
glGenRenderbuffersEXT(1, (GLuint* ) &mDepth);
|
||||
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, mDepth);
|
||||
if (mStencil)
|
||||
|
|
@ -703,6 +693,5 @@ void LLMultisampleBuffer::allocateDepth()
|
|||
{
|
||||
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, mSamples, GL_DEPTH_COMPONENT16_ARB, mResX, mResY);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -158,6 +158,7 @@ set(llui_HEADER_FILES
|
|||
llnotifications.h
|
||||
llnotificationslistener.h
|
||||
llnotificationsutil.h
|
||||
llnotificationtemplate.h
|
||||
llpanel.h
|
||||
llprogressbar.h
|
||||
llradiogroup.h
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ LLAccordionCtrl::LLAccordionCtrl() : LLPanel()
|
|||
|
||||
mSingleExpansion = false;
|
||||
mFitParent = false;
|
||||
LLUICtrlFactory::getInstance()->buildPanel(this, "accordion_parent.xml");
|
||||
buildFromFile( "accordion_parent.xml");
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -141,6 +141,7 @@ LLAccordionCtrlTab::LLAccordionCtrlTabHeader::LLAccordionCtrlTabHeader(
|
|||
textboxParams.use_ellipses = true;
|
||||
textboxParams.bg_visible = false;
|
||||
textboxParams.mouse_opaque = false;
|
||||
textboxParams.parse_urls = false;
|
||||
mHeaderTextbox = LLUICtrlFactory::create<LLTextBox>(textboxParams);
|
||||
addChild(mHeaderTextbox);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,10 +85,10 @@ public:
|
|||
|
||||
Optional<bool> selection_enabled;
|
||||
|
||||
Optional<S32> padding_left;
|
||||
Optional<S32> padding_right;
|
||||
Optional<S32> padding_top;
|
||||
Optional<S32> padding_bottom;
|
||||
Optional<S32> padding_left,
|
||||
padding_right,
|
||||
padding_top,
|
||||
padding_bottom;
|
||||
|
||||
Params();
|
||||
};
|
||||
|
|
@ -170,7 +170,7 @@ public:
|
|||
virtual BOOL handleScrollWheel( S32 x, S32 y, S32 clicks );
|
||||
|
||||
|
||||
virtual bool addChild(LLView* child, S32 tab_group);
|
||||
virtual bool addChild(LLView* child, S32 tab_group = 0 );
|
||||
|
||||
bool isExpanded() const { return mDisplayChildren; }
|
||||
|
||||
|
|
|
|||
|
|
@ -50,9 +50,7 @@ template class LLCheckBoxCtrl* LLView::getChild<class LLCheckBoxCtrl>(
|
|||
const std::string& name, BOOL recurse) const;
|
||||
|
||||
LLCheckBoxCtrl::Params::Params()
|
||||
: text_enabled_color("text_enabled_color"),
|
||||
text_disabled_color("text_disabled_color"),
|
||||
initial_value("initial_value", false),
|
||||
: initial_value("initial_value", false),
|
||||
label_text("label_text"),
|
||||
check_button("check_button"),
|
||||
radio_style("radio_style")
|
||||
|
|
@ -61,8 +59,8 @@ LLCheckBoxCtrl::Params::Params()
|
|||
|
||||
LLCheckBoxCtrl::LLCheckBoxCtrl(const LLCheckBoxCtrl::Params& p)
|
||||
: LLUICtrl(p),
|
||||
mTextEnabledColor(p.text_enabled_color()),
|
||||
mTextDisabledColor(p.text_disabled_color()),
|
||||
mTextEnabledColor(p.label_text.text_color()),
|
||||
mTextDisabledColor(p.label_text.text_readonly_color()),
|
||||
mFont(p.font())
|
||||
{
|
||||
mViewModel->setValue(LLSD(p.initial_value));
|
||||
|
|
@ -89,7 +87,6 @@ LLCheckBoxCtrl::LLCheckBoxCtrl(const LLCheckBoxCtrl::Params& p)
|
|||
{
|
||||
tbparams.font(p.font);
|
||||
}
|
||||
tbparams.text_color( p.enabled() ? p.text_enabled_color() : p.text_disabled_color() );
|
||||
mLabel = LLUICtrlFactory::create<LLTextBox> (tbparams);
|
||||
addChild(mLabel);
|
||||
|
||||
|
|
|
|||
|
|
@ -52,8 +52,6 @@ public:
|
|||
struct Params
|
||||
: public LLInitParam::Block<Params, LLUICtrl::Params>
|
||||
{
|
||||
Optional<LLUIColor> text_enabled_color;
|
||||
Optional<LLUIColor> text_disabled_color;
|
||||
Optional<bool> initial_value; // override LLUICtrl initial_value
|
||||
|
||||
Optional<LLTextBox::Params> label_text;
|
||||
|
|
|
|||
|
|
@ -52,8 +52,6 @@
|
|||
#include "lltooltip.h"
|
||||
|
||||
// Globals
|
||||
S32 LLCOMBOBOX_HEIGHT = 0;
|
||||
S32 LLCOMBOBOX_WIDTH = 0;
|
||||
S32 MAX_COMBO_WIDTH = 500;
|
||||
|
||||
static LLDefaultChildRegistry::Register<LLComboBox> register_combo_box("combo_box");
|
||||
|
|
@ -139,8 +137,8 @@ LLComboBox::LLComboBox(const LLComboBox::Params& p)
|
|||
// Grab the mouse-up event and make sure the button state is correct
|
||||
mList->setMouseUpCallback(boost::bind(&LLComboBox::onListMouseUp, this));
|
||||
|
||||
for (LLInitParam::ParamIterator<ItemParams>::const_iterator it = p.items().begin();
|
||||
it != p.items().end();
|
||||
for (LLInitParam::ParamIterator<ItemParams>::const_iterator it = p.items.begin();
|
||||
it != p.items.end();
|
||||
++it)
|
||||
{
|
||||
LLScrollListItem::Params item_params = *it;
|
||||
|
|
@ -486,7 +484,7 @@ void LLComboBox::createLineEditor(const LLComboBox::Params& p)
|
|||
LLLineEditor::Params params = p.combo_editor;
|
||||
params.rect(text_entry_rect);
|
||||
params.default_text(LLStringUtil::null);
|
||||
params.max_length_bytes(mMaxChars);
|
||||
params.max_length.bytes(mMaxChars);
|
||||
params.commit_callback.function(boost::bind(&LLComboBox::onTextCommit, this, _2));
|
||||
params.keystroke_callback(boost::bind(&LLComboBox::onTextEntry, this, _1));
|
||||
params.commit_on_focus_lost(false);
|
||||
|
|
@ -705,10 +703,10 @@ void LLComboBox::onItemSelected(const LLSD& data)
|
|||
setLabel(getSelectedItemLabel());
|
||||
|
||||
if (mAllowTextEntry)
|
||||
{
|
||||
gFocusMgr.setKeyboardFocus(mTextEntry);
|
||||
mTextEntry->selectAll();
|
||||
}
|
||||
{
|
||||
gFocusMgr.setKeyboardFocus(mTextEntry);
|
||||
mTextEntry->selectAll();
|
||||
}
|
||||
}
|
||||
// hiding the list reasserts the old value stored in the text editor/dropdown button
|
||||
hideList();
|
||||
|
|
|
|||
|
|
@ -43,9 +43,6 @@
|
|||
class LLFontGL;
|
||||
class LLViewBorder;
|
||||
|
||||
extern S32 LLCOMBOBOX_HEIGHT;
|
||||
extern S32 LLCOMBOBOX_WIDTH;
|
||||
|
||||
class LLComboBox
|
||||
: public LLUICtrl, public LLCtrlListInterface
|
||||
{
|
||||
|
|
@ -224,8 +221,8 @@ private:
|
|||
commit_callback_t mPrearrangeCallback;
|
||||
commit_callback_t mTextEntryCallback;
|
||||
commit_callback_t mSelectionCallback;
|
||||
boost::signals2::connection mTopLostSignalConnection;
|
||||
S32 mLastSelectedIndex;
|
||||
boost::signals2::connection mTopLostSignalConnection;
|
||||
S32 mLastSelectedIndex;
|
||||
};
|
||||
|
||||
// A combo box with icons for the list of items.
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
#include "lluictrlfactory.h"
|
||||
#include "llbutton.h"
|
||||
#include "llcheckboxctrl.h"
|
||||
#include "lldir.h"
|
||||
#include "lldraghandle.h"
|
||||
#include "llfloaterreg.h"
|
||||
#include "llfocusmgr.h"
|
||||
|
|
@ -2829,7 +2830,8 @@ LLFastTimer::DeclareTimer POST_BUILD("Floater Post Build");
|
|||
bool LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, const std::string& filename, LLXMLNodePtr output_node)
|
||||
{
|
||||
Params params(LLUICtrlFactory::getDefaultParams<LLFloater>());
|
||||
LLXUIParser::instance().readXUI(node, params, filename); // *TODO: Error checking
|
||||
LLXUIParser parser;
|
||||
parser.readXUI(node, params, filename); // *TODO: Error checking
|
||||
|
||||
if (output_node)
|
||||
{
|
||||
|
|
@ -2837,8 +2839,7 @@ bool LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, const std::str
|
|||
setupParamsForExport(output_params, parent);
|
||||
Params default_params(LLUICtrlFactory::getDefaultParams<LLFloater>());
|
||||
output_node->setName(node->getName()->mString);
|
||||
LLXUIParser::instance().writeXUI(
|
||||
output_node, output_params, &default_params);
|
||||
parser.writeXUI(output_node, output_params, &default_params);
|
||||
}
|
||||
|
||||
// Default floater position to top-left corner of screen
|
||||
|
|
@ -2933,3 +2934,64 @@ bool LLFloater::isVisible(const LLFloater* floater)
|
|||
{
|
||||
return floater && floater->getVisible();
|
||||
}
|
||||
|
||||
static LLFastTimer::DeclareTimer FTM_BUILD_FLOATERS("Build Floaters");
|
||||
|
||||
bool LLFloater::buildFromFile(const std::string& filename, LLXMLNodePtr output_node)
|
||||
{
|
||||
LLFastTimer timer(FTM_BUILD_FLOATERS);
|
||||
LLXMLNodePtr root;
|
||||
|
||||
//if exporting, only load the language being exported,
|
||||
//instead of layering localized version on top of english
|
||||
if (output_node)
|
||||
{
|
||||
if (!LLUICtrlFactory::getLocalizedXMLNode(filename, root))
|
||||
{
|
||||
llwarns << "Couldn't parse floater from: " << LLUI::getLocalizedSkinPath() + gDirUtilp->getDirDelimiter() + filename << llendl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (!LLUICtrlFactory::getLayeredXMLNode(filename, root))
|
||||
{
|
||||
llwarns << "Couldn't parse floater from: " << LLUI::getSkinPath() + gDirUtilp->getDirDelimiter() + filename << llendl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// root must be called floater
|
||||
if( !(root->hasName("floater") || root->hasName("multi_floater")) )
|
||||
{
|
||||
llwarns << "Root node should be named floater in: " << filename << llendl;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool res = true;
|
||||
|
||||
lldebugs << "Building floater " << filename << llendl;
|
||||
LLUICtrlFactory::instance().pushFileName(filename);
|
||||
{
|
||||
if (!getFactoryMap().empty())
|
||||
{
|
||||
LLPanel::sFactoryStack.push_front(&getFactoryMap());
|
||||
}
|
||||
|
||||
// for local registry callbacks; define in constructor, referenced in XUI or postBuild
|
||||
getCommitCallbackRegistrar().pushScope();
|
||||
getEnableCallbackRegistrar().pushScope();
|
||||
|
||||
res = initFloaterXML(root, getParent(), filename, output_node);
|
||||
|
||||
setXMLFilename(filename);
|
||||
|
||||
getCommitCallbackRegistrar().popScope();
|
||||
getEnableCallbackRegistrar().popScope();
|
||||
|
||||
if (!getFactoryMap().empty())
|
||||
{
|
||||
LLPanel::sFactoryStack.pop_front();
|
||||
}
|
||||
}
|
||||
LLUICtrlFactory::instance().popFileName();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -141,6 +141,7 @@ public:
|
|||
|
||||
// Don't export top/left for rect, only height/width
|
||||
static void setupParamsForExport(Params& p, LLView* parent);
|
||||
bool buildFromFile(const std::string &filename, LLXMLNodePtr output_node = NULL);
|
||||
|
||||
boost::signals2::connection setMinimizeCallback( const commit_signal_t::slot_type& cb );
|
||||
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ LLFloater* LLFloaterReg::getInstance(const std::string& name, const LLSD& key)
|
|||
|
||||
res = build_func(key);
|
||||
|
||||
bool success = LLUICtrlFactory::getInstance()->buildFloater(res, xui_file, NULL);
|
||||
bool success = res->buildFromFile(xui_file, NULL);
|
||||
if (!success)
|
||||
{
|
||||
llwarns << "Failed to build floater type: '" << name << "'." << llendl;
|
||||
|
|
|
|||
|
|
@ -35,95 +35,66 @@
|
|||
#include "llresizebar.h"
|
||||
#include "llcriticaldamp.h"
|
||||
|
||||
static LLDefaultChildRegistry::Register<LLLayoutStack> register_layout_stack("layout_stack", &LLLayoutStack::fromXML);
|
||||
|
||||
static LLDefaultChildRegistry::Register<LLLayoutStack> register_layout_stack("layout_stack");
|
||||
static LLLayoutStack::LayoutStackRegistry::Register<LLLayoutPanel> register_layout_panel("layout_panel");
|
||||
|
||||
//
|
||||
// LLLayoutStack
|
||||
// LLLayoutPanel
|
||||
//
|
||||
struct LLLayoutStack::LayoutPanel
|
||||
{
|
||||
LayoutPanel(LLPanel* panelp, ELayoutOrientation orientation, S32 min_width, S32 min_height, S32 max_width, S32 max_height, BOOL auto_resize, BOOL user_resize) : mPanel(panelp),
|
||||
mMinWidth(min_width),
|
||||
mMinHeight(min_height),
|
||||
mMaxWidth(max_width),
|
||||
mMaxHeight(max_height),
|
||||
mAutoResize(auto_resize),
|
||||
mUserResize(user_resize),
|
||||
mOrientation(orientation),
|
||||
LLLayoutPanel::LLLayoutPanel(const Params& p)
|
||||
: LLPanel(p),
|
||||
mMinDim(p.min_dim),
|
||||
mMaxDim(p.max_dim),
|
||||
mAutoResize(p.auto_resize),
|
||||
mUserResize(p.user_resize),
|
||||
mCollapsed(FALSE),
|
||||
mCollapseAmt(0.f),
|
||||
mVisibleAmt(1.f), // default to fully visible
|
||||
mResizeBar(NULL)
|
||||
{
|
||||
LLResizeBar::Side side = (orientation == HORIZONTAL) ? LLResizeBar::RIGHT : LLResizeBar::BOTTOM;
|
||||
LLRect resize_bar_rect = panelp->getRect();
|
||||
// panels initialized as hidden should not start out partially visible
|
||||
if (!getVisible())
|
||||
{
|
||||
mVisibleAmt = 0.f;
|
||||
}
|
||||
}
|
||||
|
||||
S32 min_dim;
|
||||
if (orientation == HORIZONTAL)
|
||||
void LLLayoutPanel::initFromParams(const Params& p)
|
||||
{
|
||||
min_dim = mMinHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
min_dim = mMinWidth;
|
||||
}
|
||||
LLResizeBar::Params p;
|
||||
p.name("resize");
|
||||
p.resizing_view(mPanel);
|
||||
p.min_size(min_dim);
|
||||
p.side(side);
|
||||
p.snapping_enabled(false);
|
||||
mResizeBar = LLUICtrlFactory::create<LLResizeBar>(p);
|
||||
// panels initialized as hidden should not start out partially visible
|
||||
if (!mPanel->getVisible())
|
||||
{
|
||||
mVisibleAmt = 0.f;
|
||||
}
|
||||
LLPanel::initFromParams(p);
|
||||
setFollowsNone();
|
||||
}
|
||||
|
||||
~LayoutPanel()
|
||||
|
||||
LLLayoutPanel::~LLLayoutPanel()
|
||||
{
|
||||
// probably not necessary, but...
|
||||
delete mResizeBar;
|
||||
mResizeBar = NULL;
|
||||
}
|
||||
|
||||
F32 getCollapseFactor()
|
||||
F32 LLLayoutPanel::getCollapseFactor(LLLayoutStack::ELayoutOrientation orientation)
|
||||
{
|
||||
if (mOrientation == HORIZONTAL)
|
||||
if (orientation == LLLayoutStack::HORIZONTAL)
|
||||
{
|
||||
F32 collapse_amt =
|
||||
clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, (F32)mMinWidth / (F32)llmax(1, mPanel->getRect().getWidth()));
|
||||
clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, (F32)mMinDim / (F32)llmax(1, getRect().getWidth()));
|
||||
return mVisibleAmt * collapse_amt;
|
||||
}
|
||||
else
|
||||
{
|
||||
F32 collapse_amt =
|
||||
clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, llmin(1.f, (F32)mMinHeight / (F32)llmax(1, mPanel->getRect().getHeight())));
|
||||
clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, llmin(1.f, (F32)mMinDim / (F32)llmax(1, getRect().getHeight())));
|
||||
return mVisibleAmt * collapse_amt;
|
||||
}
|
||||
}
|
||||
|
||||
LLPanel* mPanel;
|
||||
S32 mMinWidth;
|
||||
S32 mMinHeight;
|
||||
|
||||
// mMaxWidth & mMaxHeight are added to make configurable max width of the nearby chat bar. EXT-5589
|
||||
// they are not processed by LLLayoutStack but they can be if necessary
|
||||
S32 mMaxWidth;
|
||||
S32 mMaxHeight;
|
||||
BOOL mAutoResize;
|
||||
BOOL mUserResize;
|
||||
BOOL mCollapsed;
|
||||
LLResizeBar* mResizeBar;
|
||||
ELayoutOrientation mOrientation;
|
||||
F32 mVisibleAmt;
|
||||
F32 mCollapseAmt;
|
||||
};
|
||||
//
|
||||
// LLLayoutStack
|
||||
//
|
||||
|
||||
LLLayoutStack::Params::Params()
|
||||
: orientation("orientation", std::string("vertical")),
|
||||
: orientation("orientation"),
|
||||
animate("animate", true),
|
||||
clip("clip", true),
|
||||
border_size("border_size", LLCachedControl<S32>(*LLUI::sSettingGroups["config"], "UIResizeBarHeight", 0))
|
||||
|
|
@ -157,18 +128,18 @@ void LLLayoutStack::draw()
|
|||
for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
|
||||
{
|
||||
// clip to layout rectangle, not bounding rectangle
|
||||
LLRect clip_rect = (*panel_it)->mPanel->getRect();
|
||||
LLRect clip_rect = (*panel_it)->getRect();
|
||||
// scale clipping rectangle by visible amount
|
||||
if (mOrientation == HORIZONTAL)
|
||||
{
|
||||
clip_rect.mRight = clip_rect.mLeft + llround((F32)clip_rect.getWidth() * (*panel_it)->getCollapseFactor());
|
||||
clip_rect.mRight = clip_rect.mLeft + llround((F32)clip_rect.getWidth() * (*panel_it)->getCollapseFactor(mOrientation));
|
||||
}
|
||||
else
|
||||
{
|
||||
clip_rect.mBottom = clip_rect.mTop - llround((F32)clip_rect.getHeight() * (*panel_it)->getCollapseFactor());
|
||||
clip_rect.mBottom = clip_rect.mTop - llround((F32)clip_rect.getHeight() * (*panel_it)->getCollapseFactor(mOrientation));
|
||||
}
|
||||
|
||||
LLPanel* panelp = (*panel_it)->mPanel;
|
||||
LLPanel* panelp = (*panel_it);
|
||||
|
||||
LLLocalClipRect clip(clip_rect, mClip);
|
||||
// only force drawing invisible children if visible amount is non-zero
|
||||
|
|
@ -179,7 +150,7 @@ void LLLayoutStack::draw()
|
|||
|
||||
void LLLayoutStack::removeChild(LLView* view)
|
||||
{
|
||||
LayoutPanel* embedded_panelp = findEmbeddedPanel(dynamic_cast<LLPanel*>(view));
|
||||
LLLayoutPanel* embedded_panelp = findEmbeddedPanel(dynamic_cast<LLPanel*>(view));
|
||||
|
||||
if (embedded_panelp)
|
||||
{
|
||||
|
|
@ -200,149 +171,16 @@ BOOL LLLayoutStack::postBuild()
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static void get_attribute_s32_and_write(LLXMLNodePtr node,
|
||||
const char* name,
|
||||
S32 *value,
|
||||
S32 default_value,
|
||||
LLXMLNodePtr output_child)
|
||||
{
|
||||
BOOL has_attr = node->getAttributeS32(name, *value);
|
||||
if (has_attr && *value != default_value && output_child)
|
||||
{
|
||||
// create an attribute child node
|
||||
LLXMLNodePtr child_attr = output_child->createChild(name, TRUE);
|
||||
child_attr->setIntValue(*value);
|
||||
}
|
||||
}
|
||||
|
||||
static void get_attribute_bool_and_write(LLXMLNodePtr node,
|
||||
const char* name,
|
||||
BOOL *value,
|
||||
BOOL default_value,
|
||||
LLXMLNodePtr output_child)
|
||||
{
|
||||
BOOL has_attr = node->getAttributeBOOL(name, *value);
|
||||
if (has_attr && *value != default_value && output_child)
|
||||
{
|
||||
LLXMLNodePtr child_attr = output_child->createChild(name, TRUE);
|
||||
child_attr->setBoolValue(*value);
|
||||
}
|
||||
}
|
||||
//static
|
||||
LLView* LLLayoutStack::fromXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node)
|
||||
{
|
||||
LLLayoutStack::Params p(LLUICtrlFactory::getDefaultParams<LLLayoutStack>());
|
||||
LLXUIParser::instance().readXUI(node, p, LLUICtrlFactory::getInstance()->getCurFileName());
|
||||
|
||||
// Export must happen before setupParams() mungles rectangles and before
|
||||
// this item gets added to parent (otherwise screws up last_child_rect
|
||||
// logic). JC
|
||||
if (output_node)
|
||||
{
|
||||
Params output_params(p);
|
||||
setupParamsForExport(output_params, parent);
|
||||
LLLayoutStack::Params default_params(LLUICtrlFactory::getDefaultParams<LLLayoutStack>());
|
||||
output_node->setName(node->getName()->mString);
|
||||
LLXUIParser::instance().writeXUI(
|
||||
output_node, output_params, &default_params);
|
||||
}
|
||||
|
||||
p.from_xui = true;
|
||||
applyXUILayout(p, parent);
|
||||
LLLayoutStack* layout_stackp = LLUICtrlFactory::create<LLLayoutStack>(p);
|
||||
|
||||
if (parent && layout_stackp)
|
||||
{
|
||||
S32 tab_group = p.tab_group.isProvided() ? p.tab_group() : parent->getLastTabGroup();
|
||||
|
||||
parent->addChild(layout_stackp, tab_group);
|
||||
}
|
||||
|
||||
for (LLXMLNodePtr child_node = node->getFirstChild(); child_node.notNull(); child_node = child_node->getNextSibling())
|
||||
{
|
||||
const S32 DEFAULT_MIN_WIDTH = 0;
|
||||
const S32 DEFAULT_MIN_HEIGHT = 0;
|
||||
const S32 DEFAULT_MAX_WIDTH = S32_MAX;
|
||||
const S32 DEFAULT_MAX_HEIGHT = S32_MAX;
|
||||
const BOOL DEFAULT_AUTO_RESIZE = TRUE;
|
||||
|
||||
S32 min_width = DEFAULT_MIN_WIDTH;
|
||||
S32 min_height = DEFAULT_MIN_HEIGHT;
|
||||
S32 max_width = DEFAULT_MAX_WIDTH;
|
||||
S32 max_height = DEFAULT_MAX_HEIGHT;
|
||||
BOOL auto_resize = DEFAULT_AUTO_RESIZE;
|
||||
|
||||
LLXMLNodePtr output_child;
|
||||
if (output_node)
|
||||
bool LLLayoutStack::addChild(LLView* child, S32 tab_group)
|
||||
{
|
||||
output_child = output_node->createChild("", FALSE);
|
||||
}
|
||||
|
||||
// Layout stack allows child nodes to acquire additional attributes,
|
||||
// such as "min_width" in: <button label="Foo" min_width="100"/>
|
||||
// If these attributes exist and have non-default values, write them
|
||||
// to the output node.
|
||||
get_attribute_s32_and_write(child_node, "min_width", &min_width,
|
||||
DEFAULT_MIN_WIDTH, output_child);
|
||||
get_attribute_s32_and_write(child_node, "min_height", &min_height,
|
||||
DEFAULT_MIN_HEIGHT, output_child);
|
||||
get_attribute_s32_and_write(child_node, "max_width", &max_width,
|
||||
DEFAULT_MAX_WIDTH, output_child);
|
||||
get_attribute_s32_and_write(child_node, "max_height", &max_height,
|
||||
DEFAULT_MAX_HEIGHT, output_child);
|
||||
get_attribute_bool_and_write(child_node, "auto_resize", &auto_resize,
|
||||
DEFAULT_AUTO_RESIZE, output_child);
|
||||
|
||||
if (child_node->hasName("layout_panel"))
|
||||
{
|
||||
BOOL user_resize = TRUE;
|
||||
get_attribute_bool_and_write(child_node, "user_resize", &user_resize,
|
||||
TRUE, output_child);
|
||||
LLPanel* panelp = (LLPanel*)LLPanel::fromXML(child_node, layout_stackp, output_child);
|
||||
LLLayoutPanel* panelp = dynamic_cast<LLLayoutPanel*>(child);
|
||||
if (panelp)
|
||||
{
|
||||
panelp->setFollowsNone();
|
||||
layout_stackp->addPanel(panelp, min_width, min_height, max_width, max_height, auto_resize, user_resize);
|
||||
mPanels.push_back(panelp);
|
||||
}
|
||||
return LLView::addChild(child, tab_group);
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOL user_resize = FALSE;
|
||||
get_attribute_bool_and_write(child_node, "user_resize", &user_resize,
|
||||
FALSE, output_child);
|
||||
|
||||
LLPanel::Params p;
|
||||
p.mouse_opaque(false);
|
||||
LLPanel* panelp = LLUICtrlFactory::create<LLPanel>(p);
|
||||
LLView* new_child = LLUICtrlFactory::getInstance()->createFromXML(child_node, panelp, LLStringUtil::null, LLPanel::child_registry_t::instance(), output_child);
|
||||
if (new_child)
|
||||
{
|
||||
// put child in new embedded panel
|
||||
layout_stackp->addPanel(panelp, min_width, min_height, max_width, max_height, auto_resize, user_resize);
|
||||
// resize panel to contain widget and move widget to be contained in panel
|
||||
panelp->setRect(new_child->getRect());
|
||||
new_child->setOrigin(0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
panelp->die();
|
||||
}
|
||||
}
|
||||
|
||||
if (output_child && !output_child->mChildren && output_child->mAttributes.empty() && output_child->getValue().empty())
|
||||
{
|
||||
output_node->deleteChild(output_child);
|
||||
}
|
||||
}
|
||||
|
||||
if (!layout_stackp->postBuild())
|
||||
{
|
||||
delete layout_stackp;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return layout_stackp;
|
||||
}
|
||||
|
||||
S32 LLLayoutStack::getDefaultHeight(S32 cur_height)
|
||||
{
|
||||
|
|
@ -370,8 +208,8 @@ S32 LLLayoutStack::getDefaultWidth(S32 cur_width)
|
|||
|
||||
void LLLayoutStack::movePanel(LLPanel* panel_to_move, LLPanel* target_panel, bool move_to_front)
|
||||
{
|
||||
LayoutPanel* embedded_panel_to_move = findEmbeddedPanel(panel_to_move);
|
||||
LayoutPanel* embedded_target_panel = move_to_front ? *mPanels.begin() : findEmbeddedPanel(target_panel);
|
||||
LLLayoutPanel* embedded_panel_to_move = findEmbeddedPanel(panel_to_move);
|
||||
LLLayoutPanel* embedded_target_panel = move_to_front ? *mPanels.begin() : findEmbeddedPanel(target_panel);
|
||||
|
||||
if (!embedded_panel_to_move || !embedded_target_panel || embedded_panel_to_move == embedded_target_panel)
|
||||
{
|
||||
|
|
@ -384,34 +222,14 @@ void LLLayoutStack::movePanel(LLPanel* panel_to_move, LLPanel* target_panel, boo
|
|||
mPanels.insert(it, embedded_panel_to_move);
|
||||
}
|
||||
|
||||
void LLLayoutStack::addPanel(LLPanel* panel, S32 min_width, S32 min_height, S32 max_width, S32 max_height, BOOL auto_resize, BOOL user_resize, EAnimate animate, S32 index)
|
||||
void LLLayoutStack::addPanel(LLLayoutPanel* panel, EAnimate animate)
|
||||
{
|
||||
addChild(panel);
|
||||
|
||||
// panel starts off invisible (collapsed)
|
||||
if (animate == ANIMATE)
|
||||
{
|
||||
panel->setVisible(FALSE);
|
||||
}
|
||||
LayoutPanel* embedded_panel = new LayoutPanel(panel, mOrientation, min_width, min_height, max_width, max_height, auto_resize, user_resize);
|
||||
|
||||
mPanels.insert(mPanels.begin() + llclamp(index, 0, (S32)mPanels.size()), embedded_panel);
|
||||
|
||||
if (panel->getParent() != this)
|
||||
{
|
||||
addChild(panel);
|
||||
}
|
||||
addChild(embedded_panel->mResizeBar);
|
||||
|
||||
// bring all resize bars to the front so that they are clickable even over the panels
|
||||
// with a bit of overlap
|
||||
for (e_panel_list_t::iterator panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
|
||||
{
|
||||
LLResizeBar* resize_barp = (*panel_it)->mResizeBar;
|
||||
sendChildToFront(resize_barp);
|
||||
}
|
||||
|
||||
// start expanding panel animation
|
||||
if (animate == ANIMATE)
|
||||
{
|
||||
panel->mVisibleAmt = 0.f;
|
||||
panel->setVisible(TRUE);
|
||||
}
|
||||
}
|
||||
|
|
@ -423,7 +241,7 @@ void LLLayoutStack::removePanel(LLPanel* panel)
|
|||
|
||||
void LLLayoutStack::collapsePanel(LLPanel* panel, BOOL collapsed)
|
||||
{
|
||||
LayoutPanel* panel_container = findEmbeddedPanel(panel);
|
||||
LLLayoutPanel* panel_container = findEmbeddedPanel(panel);
|
||||
if (!panel_container) return;
|
||||
|
||||
panel_container->mCollapsed = collapsed;
|
||||
|
|
@ -431,7 +249,7 @@ void LLLayoutStack::collapsePanel(LLPanel* panel, BOOL collapsed)
|
|||
|
||||
void LLLayoutStack::updatePanelAutoResize(const std::string& panel_name, BOOL auto_resize)
|
||||
{
|
||||
LayoutPanel* panel = findEmbeddedPanelByName(panel_name);
|
||||
LLLayoutPanel* panel = findEmbeddedPanelByName(panel_name);
|
||||
|
||||
if (panel)
|
||||
{
|
||||
|
|
@ -441,7 +259,7 @@ void LLLayoutStack::updatePanelAutoResize(const std::string& panel_name, BOOL au
|
|||
|
||||
void LLLayoutStack::setPanelUserResize(const std::string& panel_name, BOOL user_resize)
|
||||
{
|
||||
LayoutPanel* panel = findEmbeddedPanelByName(panel_name);
|
||||
LLLayoutPanel* panel = findEmbeddedPanelByName(panel_name);
|
||||
|
||||
if (panel)
|
||||
{
|
||||
|
|
@ -449,27 +267,25 @@ void LLLayoutStack::setPanelUserResize(const std::string& panel_name, BOOL user_
|
|||
}
|
||||
}
|
||||
|
||||
bool LLLayoutStack::getPanelMinSize(const std::string& panel_name, S32* min_widthp, S32* min_heightp)
|
||||
bool LLLayoutStack::getPanelMinSize(const std::string& panel_name, S32* min_dimp)
|
||||
{
|
||||
LayoutPanel* panel = findEmbeddedPanelByName(panel_name);
|
||||
LLLayoutPanel* panel = findEmbeddedPanelByName(panel_name);
|
||||
|
||||
if (panel)
|
||||
{
|
||||
if (min_widthp) *min_widthp = panel->mMinWidth;
|
||||
if (min_heightp) *min_heightp = panel->mMinHeight;
|
||||
if (min_dimp) *min_dimp = panel->mMinDim;
|
||||
}
|
||||
|
||||
return NULL != panel;
|
||||
}
|
||||
|
||||
bool LLLayoutStack::getPanelMaxSize(const std::string& panel_name, S32* max_widthp, S32* max_heightp)
|
||||
bool LLLayoutStack::getPanelMaxSize(const std::string& panel_name, S32* max_dimp)
|
||||
{
|
||||
LayoutPanel* panel = findEmbeddedPanelByName(panel_name);
|
||||
LLLayoutPanel* panel = findEmbeddedPanelByName(panel_name);
|
||||
|
||||
if (panel)
|
||||
{
|
||||
if (max_widthp) *max_widthp = panel->mMaxWidth;
|
||||
if (max_heightp) *max_heightp = panel->mMaxHeight;
|
||||
if (max_dimp) *max_dimp = panel->mMaxDim;
|
||||
}
|
||||
|
||||
return NULL != panel;
|
||||
|
|
@ -481,6 +297,7 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
|
|||
LLFastTimer ft(FTM_UPDATE_LAYOUT);
|
||||
static LLUICachedControl<S32> resize_bar_overlap ("UIResizeBarOverlap", 0);
|
||||
calcMinExtents();
|
||||
createResizeBars();
|
||||
|
||||
// calculate current extents
|
||||
S32 total_width = 0;
|
||||
|
|
@ -492,7 +309,7 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
|
|||
e_panel_list_t::iterator panel_it;
|
||||
for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
|
||||
{
|
||||
LLPanel* panelp = (*panel_it)->mPanel;
|
||||
LLPanel* panelp = (*panel_it);
|
||||
if (panelp->getVisible())
|
||||
{
|
||||
if (mAnimate)
|
||||
|
|
@ -542,11 +359,11 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
|
|||
if (mOrientation == HORIZONTAL)
|
||||
{
|
||||
// enforce minimize size constraint by default
|
||||
if (panelp->getRect().getWidth() < (*panel_it)->mMinWidth)
|
||||
if (panelp->getRect().getWidth() < (*panel_it)->mMinDim)
|
||||
{
|
||||
panelp->reshape((*panel_it)->mMinWidth, panelp->getRect().getHeight());
|
||||
panelp->reshape((*panel_it)->mMinDim, panelp->getRect().getHeight());
|
||||
}
|
||||
total_width += llround(panelp->getRect().getWidth() * (*panel_it)->getCollapseFactor());
|
||||
total_width += llround(panelp->getRect().getWidth() * (*panel_it)->getCollapseFactor(mOrientation));
|
||||
// want n-1 panel gaps for n panels
|
||||
if (panel_it != mPanels.begin())
|
||||
{
|
||||
|
|
@ -556,11 +373,11 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
|
|||
else //VERTICAL
|
||||
{
|
||||
// enforce minimize size constraint by default
|
||||
if (panelp->getRect().getHeight() < (*panel_it)->mMinHeight)
|
||||
if (panelp->getRect().getHeight() < (*panel_it)->mMinDim)
|
||||
{
|
||||
panelp->reshape(panelp->getRect().getWidth(), (*panel_it)->mMinHeight);
|
||||
panelp->reshape(panelp->getRect().getWidth(), (*panel_it)->mMinDim);
|
||||
}
|
||||
total_height += llround(panelp->getRect().getHeight() * (*panel_it)->getCollapseFactor());
|
||||
total_height += llround(panelp->getRect().getHeight() * (*panel_it)->getCollapseFactor(mOrientation));
|
||||
if (panel_it != mPanels.begin())
|
||||
{
|
||||
total_height += mPanelSpacing;
|
||||
|
|
@ -574,7 +391,7 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
|
|||
for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
|
||||
{
|
||||
// panels that are not fully visible do not count towards shrink headroom
|
||||
if ((*panel_it)->getCollapseFactor() < 1.f)
|
||||
if ((*panel_it)->getCollapseFactor(mOrientation) < 1.f)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
|
@ -587,11 +404,11 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
|
|||
{
|
||||
if (mOrientation == HORIZONTAL)
|
||||
{
|
||||
shrink_headroom_total += (*panel_it)->mPanel->getRect().getWidth() - (*panel_it)->mMinWidth;
|
||||
shrink_headroom_total += (*panel_it)->getRect().getWidth() - (*panel_it)->mMinDim;
|
||||
}
|
||||
else //VERTICAL
|
||||
{
|
||||
shrink_headroom_total += (*panel_it)->mPanel->getRect().getHeight() - (*panel_it)->mMinHeight;
|
||||
shrink_headroom_total += (*panel_it)->getRect().getHeight() - (*panel_it)->mMinDim;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -599,13 +416,13 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
|
|||
num_resizable_panels++;
|
||||
if (mOrientation == HORIZONTAL)
|
||||
{
|
||||
shrink_headroom_available += (*panel_it)->mPanel->getRect().getWidth() - (*panel_it)->mMinWidth;
|
||||
shrink_headroom_total += (*panel_it)->mPanel->getRect().getWidth() - (*panel_it)->mMinWidth;
|
||||
shrink_headroom_available += (*panel_it)->getRect().getWidth() - (*panel_it)->mMinDim;
|
||||
shrink_headroom_total += (*panel_it)->getRect().getWidth() - (*panel_it)->mMinDim;
|
||||
}
|
||||
else //VERTICAL
|
||||
{
|
||||
shrink_headroom_available += (*panel_it)->mPanel->getRect().getHeight() - (*panel_it)->mMinHeight;
|
||||
shrink_headroom_total += (*panel_it)->mPanel->getRect().getHeight() - (*panel_it)->mMinHeight;
|
||||
shrink_headroom_available += (*panel_it)->getRect().getHeight() - (*panel_it)->mMinDim;
|
||||
shrink_headroom_total += (*panel_it)->getRect().getHeight() - (*panel_it)->mMinDim;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -628,17 +445,25 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
|
|||
|
||||
for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
|
||||
{
|
||||
LLPanel* panelp = (*panel_it)->mPanel;
|
||||
LLPanel* panelp = (*panel_it);
|
||||
|
||||
S32 cur_width = panelp->getRect().getWidth();
|
||||
S32 cur_height = panelp->getRect().getHeight();
|
||||
S32 new_width = llmax((*panel_it)->mMinWidth, cur_width);
|
||||
S32 new_height = llmax((*panel_it)->mMinHeight, cur_height);
|
||||
S32 new_width = cur_width;
|
||||
S32 new_height = cur_height;
|
||||
|
||||
if (mOrientation == HORIZONTAL)
|
||||
{
|
||||
new_width = llmax((*panel_it)->mMinDim, new_width);
|
||||
}
|
||||
else
|
||||
{
|
||||
new_height = llmax((*panel_it)->mMinDim, new_height);
|
||||
}
|
||||
S32 delta_size = 0;
|
||||
|
||||
// if panel can automatically resize (not animating, and resize flag set)...
|
||||
if ((*panel_it)->getCollapseFactor() == 1.f
|
||||
if ((*panel_it)->getCollapseFactor(mOrientation) == 1.f
|
||||
&& (force_resize || (*panel_it)->mAutoResize)
|
||||
&& !(*panel_it)->mResizeBar->hasMouseCapture())
|
||||
{
|
||||
|
|
@ -649,8 +474,8 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
|
|||
{
|
||||
// shrink proportionally to amount over minimum
|
||||
// so we can do this in one pass
|
||||
delta_size = (shrink_headroom_available > 0) ? llround((F32)pixels_to_distribute * ((F32)(cur_width - (*panel_it)->mMinWidth) / (F32)shrink_headroom_available)) : 0;
|
||||
shrink_headroom_available -= (cur_width - (*panel_it)->mMinWidth);
|
||||
delta_size = (shrink_headroom_available > 0) ? llround((F32)pixels_to_distribute * ((F32)(cur_width - (*panel_it)->mMinDim) / (F32)shrink_headroom_available)) : 0;
|
||||
shrink_headroom_available -= (cur_width - (*panel_it)->mMinDim);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -659,7 +484,7 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
|
|||
num_resizable_panels--;
|
||||
}
|
||||
pixels_to_distribute -= delta_size;
|
||||
new_width = llmax((*panel_it)->mMinWidth, cur_width + delta_size);
|
||||
new_width = llmax((*panel_it)->mMinDim, cur_width + delta_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -672,8 +497,8 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
|
|||
{
|
||||
// shrink proportionally to amount over minimum
|
||||
// so we can do this in one pass
|
||||
delta_size = (shrink_headroom_available > 0) ? llround((F32)pixels_to_distribute * ((F32)(cur_height - (*panel_it)->mMinHeight) / (F32)shrink_headroom_available)) : 0;
|
||||
shrink_headroom_available -= (cur_height - (*panel_it)->mMinHeight);
|
||||
delta_size = (shrink_headroom_available > 0) ? llround((F32)pixels_to_distribute * ((F32)(cur_height - (*panel_it)->mMinDim) / (F32)shrink_headroom_available)) : 0;
|
||||
shrink_headroom_available -= (cur_height - (*panel_it)->mMinDim);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -681,7 +506,7 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
|
|||
num_resizable_panels--;
|
||||
}
|
||||
pixels_to_distribute -= delta_size;
|
||||
new_height = llmax((*panel_it)->mMinHeight, cur_height + delta_size);
|
||||
new_height = llmax((*panel_it)->mMinDim, cur_height + delta_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -722,11 +547,11 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
|
|||
|
||||
if (mOrientation == HORIZONTAL)
|
||||
{
|
||||
cur_x += llround(new_width * (*panel_it)->getCollapseFactor()) + mPanelSpacing;
|
||||
cur_x += llround(new_width * (*panel_it)->getCollapseFactor(mOrientation)) + mPanelSpacing;
|
||||
}
|
||||
else //VERTICAL
|
||||
{
|
||||
cur_y -= llround(new_height * (*panel_it)->getCollapseFactor()) + mPanelSpacing;
|
||||
cur_y -= llround(new_height * (*panel_it)->getCollapseFactor(mOrientation)) + mPanelSpacing;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -734,19 +559,19 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
|
|||
LLResizeBar* last_resize_bar = NULL;
|
||||
for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
|
||||
{
|
||||
LLPanel* panelp = (*panel_it)->mPanel;
|
||||
LLPanel* panelp = (*panel_it);
|
||||
|
||||
if (mOrientation == HORIZONTAL)
|
||||
{
|
||||
(*panel_it)->mResizeBar->setResizeLimits(
|
||||
(*panel_it)->mMinWidth,
|
||||
(*panel_it)->mMinWidth + shrink_headroom_total);
|
||||
(*panel_it)->mMinDim,
|
||||
(*panel_it)->mMinDim + shrink_headroom_total);
|
||||
}
|
||||
else //VERTICAL
|
||||
{
|
||||
(*panel_it)->mResizeBar->setResizeLimits(
|
||||
(*panel_it)->mMinHeight,
|
||||
(*panel_it)->mMinHeight + shrink_headroom_total);
|
||||
(*panel_it)->mMinDim,
|
||||
(*panel_it)->mMinDim + shrink_headroom_total);
|
||||
}
|
||||
|
||||
// toggle resize bars based on panel visibility, resizability, etc
|
||||
|
|
@ -782,14 +607,14 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
|
|||
} // end LLLayoutStack::updateLayout
|
||||
|
||||
|
||||
LLLayoutStack::LayoutPanel* LLLayoutStack::findEmbeddedPanel(LLPanel* panelp) const
|
||||
LLLayoutPanel* LLLayoutStack::findEmbeddedPanel(LLPanel* panelp) const
|
||||
{
|
||||
if (!panelp) return NULL;
|
||||
|
||||
e_panel_list_t::const_iterator panel_it;
|
||||
for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
|
||||
{
|
||||
if ((*panel_it)->mPanel == panelp)
|
||||
if ((*panel_it) == panelp)
|
||||
{
|
||||
return *panel_it;
|
||||
}
|
||||
|
|
@ -797,15 +622,15 @@ LLLayoutStack::LayoutPanel* LLLayoutStack::findEmbeddedPanel(LLPanel* panelp) co
|
|||
return NULL;
|
||||
}
|
||||
|
||||
LLLayoutStack::LayoutPanel* LLLayoutStack::findEmbeddedPanelByName(const std::string& name) const
|
||||
LLLayoutPanel* LLLayoutStack::findEmbeddedPanelByName(const std::string& name) const
|
||||
{
|
||||
LayoutPanel* result = NULL;
|
||||
LLLayoutPanel* result = NULL;
|
||||
|
||||
for (e_panel_list_t::const_iterator panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
|
||||
{
|
||||
LayoutPanel* p = *panel_it;
|
||||
LLLayoutPanel* p = *panel_it;
|
||||
|
||||
if (p->mPanel->getName() == name)
|
||||
if (p->getName() == name)
|
||||
{
|
||||
result = p;
|
||||
break;
|
||||
|
|
@ -826,9 +651,7 @@ void LLLayoutStack::calcMinExtents()
|
|||
{
|
||||
if (mOrientation == HORIZONTAL)
|
||||
{
|
||||
mMinHeight = llmax( mMinHeight,
|
||||
(*panel_it)->mMinHeight);
|
||||
mMinWidth += (*panel_it)->mMinWidth;
|
||||
mMinWidth += (*panel_it)->mMinDim;
|
||||
if (panel_it != mPanels.begin())
|
||||
{
|
||||
mMinWidth += mPanelSpacing;
|
||||
|
|
@ -836,9 +659,7 @@ void LLLayoutStack::calcMinExtents()
|
|||
}
|
||||
else //VERTICAL
|
||||
{
|
||||
mMinWidth = llmax( mMinWidth,
|
||||
(*panel_it)->mMinWidth);
|
||||
mMinHeight += (*panel_it)->mMinHeight;
|
||||
mMinHeight += (*panel_it)->mMinDim;
|
||||
if (panel_it != mPanels.begin())
|
||||
{
|
||||
mMinHeight += mPanelSpacing;
|
||||
|
|
@ -847,6 +668,37 @@ void LLLayoutStack::calcMinExtents()
|
|||
}
|
||||
}
|
||||
|
||||
void LLLayoutStack::createResizeBars()
|
||||
{
|
||||
for (e_panel_list_t::iterator panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
|
||||
{
|
||||
LLLayoutPanel* lp = (*panel_it);
|
||||
if (lp->mResizeBar == NULL)
|
||||
{
|
||||
LLResizeBar::Side side = (mOrientation == HORIZONTAL) ? LLResizeBar::RIGHT : LLResizeBar::BOTTOM;
|
||||
LLRect resize_bar_rect = getRect();
|
||||
|
||||
LLResizeBar::Params resize_params;
|
||||
resize_params.name("resize");
|
||||
resize_params.resizing_view(lp);
|
||||
resize_params.min_size(lp->mMinDim);
|
||||
resize_params.side(side);
|
||||
resize_params.snapping_enabled(false);
|
||||
LLResizeBar* resize_bar = LLUICtrlFactory::create<LLResizeBar>(resize_params);
|
||||
lp->mResizeBar = resize_bar;
|
||||
LLView::addChild(resize_bar, 0);
|
||||
|
||||
// bring all resize bars to the front so that they are clickable even over the panels
|
||||
// with a bit of overlap
|
||||
for (e_panel_list_t::iterator panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
|
||||
{
|
||||
LLResizeBar* resize_barp = (*panel_it)->mResizeBar;
|
||||
sendChildToFront(resize_barp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// update layout stack animations, etc. once per frame
|
||||
// NOTE: we use this to size world view based on animating UI, *before* we draw the UI
|
||||
// we might still need to call updateLayout during UI draw phase, in case UI elements
|
||||
|
|
|
|||
|
|
@ -28,16 +28,21 @@
|
|||
#ifndef LL_LLLAYOUTSTACK_H
|
||||
#define LL_LLLAYOUTSTACK_H
|
||||
|
||||
#include "llview.h"
|
||||
#include "llpanel.h"
|
||||
|
||||
class LLPanel;
|
||||
|
||||
class LLLayoutPanel;
|
||||
|
||||
class LLLayoutStack : public LLView, public LLInstanceTracker<LLLayoutStack>
|
||||
{
|
||||
public:
|
||||
struct LayoutStackRegistry : public LLChildRegistry<LayoutStackRegistry>
|
||||
{};
|
||||
|
||||
struct Params : public LLInitParam::Block<Params, LLView::Params>
|
||||
{
|
||||
Optional<std::string> orientation;
|
||||
Mandatory<std::string> orientation;
|
||||
Optional<S32> border_size;
|
||||
Optional<bool> animate,
|
||||
clip;
|
||||
|
|
@ -45,6 +50,8 @@ public:
|
|||
Params();
|
||||
};
|
||||
|
||||
typedef LayoutStackRegistry child_registry_t;
|
||||
|
||||
typedef enum e_layout_orientation
|
||||
{
|
||||
HORIZONTAL,
|
||||
|
|
@ -56,6 +63,7 @@ public:
|
|||
/*virtual*/ void draw();
|
||||
/*virtual*/ void removeChild(LLView*);
|
||||
/*virtual*/ BOOL postBuild();
|
||||
/*virtual*/ bool addChild(LLView* child, S32 tab_group = 0);
|
||||
|
||||
static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node = NULL);
|
||||
|
||||
|
|
@ -68,7 +76,7 @@ public:
|
|||
ANIMATE
|
||||
} EAnimate;
|
||||
|
||||
void addPanel(LLPanel* panel, S32 min_width, S32 min_height, S32 max_width, S32 max_height, BOOL auto_resize, BOOL user_resize, EAnimate animate = NO_ANIMATE, S32 index = S32_MAX);
|
||||
void addPanel(LLLayoutPanel* panel, EAnimate animate = NO_ANIMATE);
|
||||
void removePanel(LLPanel* panel);
|
||||
void collapsePanel(LLPanel* panel, BOOL collapsed = TRUE);
|
||||
S32 getNumPanels() { return mPanels.size(); }
|
||||
|
|
@ -82,20 +90,18 @@ public:
|
|||
void setPanelUserResize(const std::string& panel_name, BOOL user_resize);
|
||||
|
||||
/**
|
||||
* Gets minimal width and/or height of the specified by name panel.
|
||||
* Gets minimal dimension along layout_stack axis of the specified by name panel.
|
||||
*
|
||||
* If it is necessary to get only the one dimension pass NULL for another one.
|
||||
* @returns true if specified by panel_name internal panel exists, false otherwise.
|
||||
*/
|
||||
bool getPanelMinSize(const std::string& panel_name, S32* min_widthp, S32* min_heightp);
|
||||
bool getPanelMinSize(const std::string& panel_name, S32* min_dimp);
|
||||
|
||||
/**
|
||||
* Gets maximal width and/or height of the specified by name panel.
|
||||
* Gets maximal dimension along layout_stack axis of the specified by name panel.
|
||||
*
|
||||
* If it is necessary to get only the one dimension pass NULL for another one.
|
||||
* @returns true if specified by panel_name internal panel exists, false otherwise.
|
||||
*/
|
||||
bool getPanelMaxSize(const std::string& panel_name, S32* max_width, S32* max_height);
|
||||
bool getPanelMaxSize(const std::string& panel_name, S32* max_dim);
|
||||
|
||||
void updateLayout(BOOL force_resize = FALSE);
|
||||
|
||||
|
|
@ -110,19 +116,18 @@ protected:
|
|||
friend class LLUICtrlFactory;
|
||||
|
||||
private:
|
||||
struct LayoutPanel;
|
||||
|
||||
void createResizeBars();
|
||||
void calcMinExtents();
|
||||
S32 getDefaultHeight(S32 cur_height);
|
||||
S32 getDefaultWidth(S32 cur_width);
|
||||
|
||||
const ELayoutOrientation mOrientation;
|
||||
|
||||
typedef std::vector<LayoutPanel*> e_panel_list_t;
|
||||
typedef std::vector<LLLayoutPanel*> e_panel_list_t;
|
||||
e_panel_list_t mPanels;
|
||||
|
||||
LayoutPanel* findEmbeddedPanel(LLPanel* panelp) const;
|
||||
LayoutPanel* findEmbeddedPanelByName(const std::string& name) const;
|
||||
LLLayoutPanel* findEmbeddedPanel(LLPanel* panelp) const;
|
||||
LLLayoutPanel* findEmbeddedPanelByName(const std::string& name) const;
|
||||
|
||||
S32 mMinWidth; // calculated by calcMinExtents
|
||||
S32 mMinHeight; // calculated by calcMinExtents
|
||||
|
|
@ -134,4 +139,49 @@ private:
|
|||
bool mClip;
|
||||
}; // end class LLLayoutStack
|
||||
|
||||
class LLLayoutPanel : public LLPanel
|
||||
{
|
||||
friend class LLLayoutStack;
|
||||
friend class LLUICtrlFactory;
|
||||
public:
|
||||
struct Params : public LLInitParam::Block<Params, LLPanel::Params>
|
||||
{
|
||||
Optional<S32> min_dim,
|
||||
max_dim;
|
||||
Optional<bool> user_resize,
|
||||
auto_resize;
|
||||
|
||||
Params()
|
||||
: min_dim("min_dim", 0),
|
||||
max_dim("max_dim", 0),
|
||||
user_resize("user_resize", true),
|
||||
auto_resize("auto_resize", true)
|
||||
{
|
||||
addSynonym(min_dim, "min_width");
|
||||
addSynonym(min_dim, "min_height");
|
||||
addSynonym(max_dim, "max_width");
|
||||
addSynonym(max_dim, "max_height");
|
||||
}
|
||||
};
|
||||
|
||||
~LLLayoutPanel();
|
||||
|
||||
void initFromParams(const Params& p);
|
||||
protected:
|
||||
LLLayoutPanel(const Params& p) ;
|
||||
|
||||
|
||||
F32 getCollapseFactor(LLLayoutStack::ELayoutOrientation orientation);
|
||||
|
||||
S32 mMinDim;
|
||||
S32 mMaxDim;
|
||||
BOOL mAutoResize;
|
||||
BOOL mUserResize;
|
||||
BOOL mCollapsed;
|
||||
class LLResizeBar* mResizeBar;
|
||||
F32 mVisibleAmt;
|
||||
F32 mCollapseAmt;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ template class LLLineEditor* LLView::getChild<class LLLineEditor>(
|
|||
//
|
||||
|
||||
LLLineEditor::Params::Params()
|
||||
: max_length_bytes("max_length", 254),
|
||||
: max_length(""),
|
||||
keystroke_callback("keystroke_callback"),
|
||||
prevalidate_callback("prevalidate_callback"),
|
||||
background_image("background_image"),
|
||||
|
|
@ -108,7 +108,8 @@ LLLineEditor::Params::Params()
|
|||
|
||||
LLLineEditor::LLLineEditor(const LLLineEditor::Params& p)
|
||||
: LLUICtrl(p),
|
||||
mMaxLengthBytes(p.max_length_bytes),
|
||||
mMaxLengthBytes(p.max_length.bytes),
|
||||
mMaxLengthChars(p.max_length.chars),
|
||||
mCursorPos( 0 ),
|
||||
mScrollHPos( 0 ),
|
||||
mTextPadLeft(p.text_pad_left),
|
||||
|
|
@ -313,6 +314,12 @@ void LLLineEditor::setMaxTextLength(S32 max_text_length)
|
|||
mMaxLengthBytes = max_len;
|
||||
}
|
||||
|
||||
void LLLineEditor::setMaxTextChars(S32 max_text_chars)
|
||||
{
|
||||
S32 max_chars = llmax(0, max_text_chars);
|
||||
mMaxLengthChars = max_chars;
|
||||
}
|
||||
|
||||
void LLLineEditor::getTextPadding(S32 *left, S32 *right)
|
||||
{
|
||||
*left = mTextPadLeft;
|
||||
|
|
@ -358,6 +365,16 @@ void LLLineEditor::setText(const LLStringExplicit &new_text)
|
|||
}
|
||||
mText.assign(truncated_utf8);
|
||||
|
||||
if (mMaxLengthChars)
|
||||
{
|
||||
LLWString truncated_wstring = utf8str_to_wstring(truncated_utf8);
|
||||
if (truncated_wstring.size() > (U32)mMaxLengthChars)
|
||||
{
|
||||
truncated_wstring = truncated_wstring.substr(0, mMaxLengthChars);
|
||||
}
|
||||
mText.assign(wstring_to_utf8str(truncated_wstring));
|
||||
}
|
||||
|
||||
if (all_selected)
|
||||
{
|
||||
// ...keep whole thing selected
|
||||
|
|
@ -798,6 +815,7 @@ void LLLineEditor::addChar(const llwchar uni_char)
|
|||
}
|
||||
|
||||
S32 cur_bytes = mText.getString().size();
|
||||
|
||||
S32 new_bytes = wchar_utf8_length(new_c);
|
||||
|
||||
BOOL allow_char = TRUE;
|
||||
|
|
@ -807,6 +825,14 @@ void LLLineEditor::addChar(const llwchar uni_char)
|
|||
{
|
||||
allow_char = FALSE;
|
||||
}
|
||||
else if (mMaxLengthChars)
|
||||
{
|
||||
S32 wide_chars = mText.getWString().size();
|
||||
if ((wide_chars + 1) > mMaxLengthChars)
|
||||
{
|
||||
allow_char = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (allow_char)
|
||||
{
|
||||
|
|
@ -1107,7 +1133,19 @@ void LLLineEditor::pasteHelper(bool is_primary)
|
|||
clean_string = clean_string.substr(0, wchars_that_fit);
|
||||
LLUI::reportBadKeystroke();
|
||||
}
|
||||
|
||||
|
||||
if (mMaxLengthChars)
|
||||
{
|
||||
U32 available_chars = mMaxLengthChars - mText.getWString().size();
|
||||
|
||||
if (available_chars < clean_string.size())
|
||||
{
|
||||
clean_string = clean_string.substr(0, available_chars);
|
||||
}
|
||||
|
||||
LLUI::reportBadKeystroke();
|
||||
}
|
||||
|
||||
mText.insert(getCursor(), clean_string);
|
||||
setCursor( getCursor() + (S32)clean_string.length() );
|
||||
deselect();
|
||||
|
|
@ -1271,7 +1309,7 @@ BOOL LLLineEditor::handleSpecialKey(KEY key, MASK mask)
|
|||
if( mCurrentHistoryLine > mLineHistory.begin() )
|
||||
{
|
||||
mText.assign( *(--mCurrentHistoryLine) );
|
||||
setCursor(llmin((S32)mText.length(), getCursor()));
|
||||
setCursorToEnd();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1288,7 +1326,7 @@ BOOL LLLineEditor::handleSpecialKey(KEY key, MASK mask)
|
|||
if( !mLineHistory.empty() && mCurrentHistoryLine < mLineHistory.end() - 1 )
|
||||
{
|
||||
mText.assign( *(++mCurrentHistoryLine) );
|
||||
setCursor(llmin((S32)mText.length(), getCursor()));
|
||||
setCursorToEnd();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -59,11 +59,19 @@ public:
|
|||
|
||||
typedef boost::function<void (LLLineEditor* caller)> keystroke_callback_t;
|
||||
|
||||
struct MaxLength : public LLInitParam::Choice<MaxLength>
|
||||
{
|
||||
Alternative<S32> bytes, chars;
|
||||
|
||||
MaxLength() : bytes("max_length_bytes", 254),
|
||||
chars("max_length_chars", 0)
|
||||
{}
|
||||
};
|
||||
|
||||
struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
|
||||
{
|
||||
Optional<std::string> default_text;
|
||||
Optional<S32> max_length_bytes;
|
||||
|
||||
Optional<MaxLength> max_length;
|
||||
Optional<keystroke_callback_t> keystroke_callback;
|
||||
|
||||
Optional<LLTextValidate::validate_func_t, LLTextValidate::ValidateTextNamedFuncs> prevalidate_callback;
|
||||
|
|
@ -214,6 +222,7 @@ public:
|
|||
void setKeystrokeCallback(callback_t callback, void* user_data);
|
||||
|
||||
void setMaxTextLength(S32 max_text_length);
|
||||
void setMaxTextChars(S32 max_text_chars);
|
||||
// Manipulate left and right padding for text
|
||||
void getTextPadding(S32 *left, S32 *right);
|
||||
void setTextPadding(S32 left, S32 right);
|
||||
|
|
@ -277,6 +286,7 @@ protected:
|
|||
LLViewBorder* mBorder;
|
||||
const LLFontGL* mGLFont;
|
||||
S32 mMaxLengthBytes; // Max length of the UTF8 string in bytes
|
||||
S32 mMaxLengthChars; // Maximum number of characters in the string
|
||||
S32 mCursorPos; // I-beam is just after the mCursorPos-th character.
|
||||
S32 mScrollHPos; // Horizontal offset from the start of mText. Used for scrolling.
|
||||
LLFrameTimer mScrollTimer;
|
||||
|
|
|
|||
|
|
@ -101,8 +101,8 @@ LLMultiSlider::LLMultiSlider(const LLMultiSlider::Params& p)
|
|||
setMouseUpCallback(initCommitCallback(p.mouse_up_callback));
|
||||
}
|
||||
|
||||
for (LLInitParam::ParamIterator<SliderParams>::const_iterator it = p.sliders().begin();
|
||||
it != p.sliders().end();
|
||||
for (LLInitParam::ParamIterator<SliderParams>::const_iterator it = p.sliders.begin();
|
||||
it != p.sliders.end();
|
||||
++it)
|
||||
{
|
||||
if (it->name.isProvided())
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@ LLMultiSliderCtrl::LLMultiSliderCtrl(const LLMultiSliderCtrl::Params& p)
|
|||
params.name("MultiSliderCtrl Editor");
|
||||
params.rect(text_rect);
|
||||
params.font(p.font);
|
||||
params.max_length_bytes(MAX_STRING_LENGTH);
|
||||
params.max_length.bytes(MAX_STRING_LENGTH);
|
||||
params.commit_callback.function(LLMultiSliderCtrl::onEditorCommit);
|
||||
params.prevalidate_callback(&LLTextValidate::validateFloat);
|
||||
params.follows.flags(FOLLOWS_LEFT | FOLLOWS_BOTTOM);
|
||||
|
|
|
|||
|
|
@ -27,8 +27,11 @@
|
|||
#include "linden_common.h"
|
||||
|
||||
#include "llnotifications.h"
|
||||
#include "llnotificationtemplate.h"
|
||||
|
||||
#include "llavatarnamecache.h"
|
||||
#include "llinstantmessage.h"
|
||||
#include "llcachename.h"
|
||||
#include "llxmlnode.h"
|
||||
#include "lluictrl.h"
|
||||
#include "lluictrlfactory.h"
|
||||
|
|
@ -37,6 +40,8 @@
|
|||
#include "lltrans.h"
|
||||
#include "llnotificationslistener.h"
|
||||
#include "llstring.h"
|
||||
#include "llsdparam.h"
|
||||
#include "llsdutil.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <boost/regex.hpp>
|
||||
|
|
@ -44,6 +49,58 @@
|
|||
|
||||
const std::string NOTIFICATION_PERSIST_VERSION = "0.93";
|
||||
|
||||
void NotificationPriorityValues::declareValues()
|
||||
{
|
||||
declare("low", NOTIFICATION_PRIORITY_LOW);
|
||||
declare("normal", NOTIFICATION_PRIORITY_NORMAL);
|
||||
declare("high", NOTIFICATION_PRIORITY_HIGH);
|
||||
declare("critical", NOTIFICATION_PRIORITY_CRITICAL);
|
||||
}
|
||||
|
||||
LLNotificationForm::FormElementBase::FormElementBase()
|
||||
: name("name")
|
||||
{}
|
||||
|
||||
LLNotificationForm::FormIgnore::FormIgnore()
|
||||
: text("text"),
|
||||
control("control"),
|
||||
invert_control("invert_control", true),
|
||||
save_option("save_option", false)
|
||||
{}
|
||||
|
||||
LLNotificationForm::FormButton::FormButton()
|
||||
: index("index"),
|
||||
text("text"),
|
||||
ignore("ignore"),
|
||||
is_default("default"),
|
||||
type("type")
|
||||
{
|
||||
// set type here so it gets serialized
|
||||
type = "button";
|
||||
}
|
||||
|
||||
LLNotificationForm::FormInput::FormInput()
|
||||
: type("type"),
|
||||
max_length_chars("max_length_chars"),
|
||||
width("width", 0),
|
||||
value("value")
|
||||
{}
|
||||
|
||||
LLNotificationForm::FormElement::FormElement()
|
||||
: button("button"),
|
||||
input("input")
|
||||
{}
|
||||
|
||||
LLNotificationForm::FormElements::FormElements()
|
||||
: elements("")
|
||||
{}
|
||||
|
||||
LLNotificationForm::Params::Params()
|
||||
: name("name"),
|
||||
ignore("ignore"),
|
||||
form_elements("")
|
||||
{}
|
||||
|
||||
// Local channel for persistent notifications
|
||||
// Stores only persistent notifications.
|
||||
// Class users can use connectChanged() to process persistent notifications
|
||||
|
|
@ -88,12 +145,7 @@ bool filterIgnoredNotifications(LLNotificationPtr notification)
|
|||
|
||||
LLNotificationFormPtr form = notification->getForm();
|
||||
// Check to see if the user wants to ignore this alert
|
||||
if (form->getIgnoreType() != LLNotificationForm::IGNORE_NO)
|
||||
{
|
||||
return LLUI::sSettingGroups["ignores"]->getBOOL(notification->getName());
|
||||
}
|
||||
|
||||
return true;
|
||||
return !notification->getForm()->getIgnored();
|
||||
}
|
||||
|
||||
bool handleIgnoredNotification(const LLSD& payload)
|
||||
|
|
@ -135,63 +187,68 @@ namespace LLNotificationFilters
|
|||
};
|
||||
|
||||
LLNotificationForm::LLNotificationForm()
|
||||
: mFormData(LLSD::emptyArray()),
|
||||
mIgnore(IGNORE_NO)
|
||||
: mIgnore(IGNORE_NO)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
LLNotificationForm::LLNotificationForm(const std::string& name, const LLXMLNodePtr xml_node)
|
||||
: mFormData(LLSD::emptyArray()),
|
||||
mIgnore(IGNORE_NO)
|
||||
LLNotificationForm::LLNotificationForm(const std::string& name, const LLNotificationForm::Params& p)
|
||||
: mIgnore(IGNORE_NO),
|
||||
mInvertSetting(true) // ignore settings by default mean true=show, false=ignore
|
||||
{
|
||||
if (!xml_node->hasName("form"))
|
||||
if (p.ignore.isProvided())
|
||||
{
|
||||
llwarns << "Bad xml node for form: " << xml_node->getName() << llendl;
|
||||
}
|
||||
LLXMLNodePtr child = xml_node->getFirstChild();
|
||||
while(child)
|
||||
{
|
||||
child = LLNotifications::instance().checkForXMLTemplate(child);
|
||||
mIgnoreMsg = p.ignore.text;
|
||||
|
||||
LLSD item_entry;
|
||||
std::string element_name = child->getName()->mString;
|
||||
|
||||
if (element_name == "ignore" )
|
||||
if (!p.ignore.save_option)
|
||||
{
|
||||
bool save_option = false;
|
||||
child->getAttribute_bool("save_option", save_option);
|
||||
if (!save_option)
|
||||
{
|
||||
mIgnore = IGNORE_WITH_DEFAULT_RESPONSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
// remember last option chosen by user and automatically respond with that in the future
|
||||
mIgnore = IGNORE_WITH_LAST_RESPONSE;
|
||||
LLUI::sSettingGroups["ignores"]->declareLLSD(std::string("Default") + name, "", std::string("Default response for notification " + name));
|
||||
}
|
||||
child->getAttributeString("text", mIgnoreMsg);
|
||||
BOOL show_notification = TRUE;
|
||||
LLUI::sSettingGroups["ignores"]->declareBOOL(name, show_notification, "Ignore notification with this name", TRUE);
|
||||
mIgnore = IGNORE_WITH_DEFAULT_RESPONSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
// flatten xml form entry into single LLSD map with type==name
|
||||
item_entry["type"] = element_name;
|
||||
const LLXMLAttribList::iterator attrib_end = child->mAttributes.end();
|
||||
for(LLXMLAttribList::iterator attrib_it = child->mAttributes.begin();
|
||||
attrib_it != attrib_end;
|
||||
++attrib_it)
|
||||
{
|
||||
item_entry[std::string(attrib_it->second->getName()->mString)] = attrib_it->second->getValue();
|
||||
}
|
||||
item_entry["value"] = child->getTextContents();
|
||||
mFormData.append(item_entry);
|
||||
// remember last option chosen by user and automatically respond with that in the future
|
||||
mIgnore = IGNORE_WITH_LAST_RESPONSE;
|
||||
LLUI::sSettingGroups["ignores"]->declareLLSD(std::string("Default") + name, "", std::string("Default response for notification " + name));
|
||||
}
|
||||
|
||||
child = child->getNextSibling();
|
||||
BOOL show_notification = TRUE;
|
||||
if (p.ignore.control.isProvided())
|
||||
{
|
||||
mIgnoreSetting = LLUI::sSettingGroups["config"]->getControl(p.ignore.control);
|
||||
mInvertSetting = p.ignore.invert_control;
|
||||
}
|
||||
else
|
||||
{
|
||||
LLUI::sSettingGroups["ignores"]->declareBOOL(name, show_notification, "Ignore notification with this name", TRUE);
|
||||
mIgnoreSetting = LLUI::sSettingGroups["ignores"]->getControl(name);
|
||||
}
|
||||
}
|
||||
|
||||
LLParamSDParser parser;
|
||||
parser.writeSD(mFormData, p.form_elements);
|
||||
|
||||
mFormData = mFormData[""];
|
||||
if (!mFormData.isArray())
|
||||
{
|
||||
// change existing contents to a one element array
|
||||
LLSD new_llsd_array = LLSD::emptyArray();
|
||||
new_llsd_array.append(mFormData);
|
||||
mFormData = new_llsd_array;
|
||||
}
|
||||
|
||||
for (LLSD::array_iterator it = mFormData.beginArray(), end_it = mFormData.endArray();
|
||||
it != end_it;
|
||||
++it)
|
||||
{
|
||||
// lift contents of form element up a level, since element type is already encoded in "type" param
|
||||
if (it->isMap() && it->beginMap() != it->endMap())
|
||||
{
|
||||
*it = it->beginMap()->second;
|
||||
}
|
||||
}
|
||||
|
||||
LL_DEBUGS("Notifications") << name << LL_ENDL;
|
||||
LL_DEBUGS("Notifications") << ll_pretty_print_sd(mFormData) << LL_ENDL;
|
||||
}
|
||||
|
||||
LLNotificationForm::LLNotificationForm(const LLSD& sd)
|
||||
|
|
@ -293,16 +350,64 @@ std::string LLNotificationForm::getDefaultOption()
|
|||
return "";
|
||||
}
|
||||
|
||||
LLNotificationTemplate::LLNotificationTemplate() :
|
||||
mExpireSeconds(0),
|
||||
mExpireOption(-1),
|
||||
mURLOption(-1),
|
||||
mURLOpenExternally(-1),
|
||||
mPersist(false),
|
||||
mUnique(false),
|
||||
mPriority(NOTIFICATION_PRIORITY_NORMAL)
|
||||
LLControlVariablePtr LLNotificationForm::getIgnoreSetting()
|
||||
{
|
||||
return mIgnoreSetting;
|
||||
}
|
||||
|
||||
bool LLNotificationForm::getIgnored()
|
||||
{
|
||||
mForm = LLNotificationFormPtr(new LLNotificationForm());
|
||||
bool ignored = false;
|
||||
if (mIgnore != LLNotificationForm::IGNORE_NO
|
||||
&& mIgnoreSetting)
|
||||
{
|
||||
ignored = mIgnoreSetting->getValue().asBoolean();
|
||||
if (mInvertSetting) ignored = !ignored;
|
||||
}
|
||||
|
||||
return ignored;
|
||||
}
|
||||
|
||||
void LLNotificationForm::setIgnored(bool ignored)
|
||||
{
|
||||
if (mIgnoreSetting)
|
||||
{
|
||||
if (mInvertSetting) ignored = !ignored;
|
||||
mIgnoreSetting->setValue(ignored);
|
||||
}
|
||||
}
|
||||
|
||||
LLNotificationTemplate::LLNotificationTemplate(const LLNotificationTemplate::Params& p)
|
||||
: mName(p.name),
|
||||
mType(p.type),
|
||||
mMessage(p.value),
|
||||
mLabel(p.label),
|
||||
mIcon(p.icon),
|
||||
mURL(p.url.value),
|
||||
mExpireSeconds(p.duration),
|
||||
mExpireOption(p.expire_option),
|
||||
mURLOption(p.url.option),
|
||||
mURLTarget(p.url.target),
|
||||
mUnique(p.unique.isProvided()),
|
||||
mPriority(p.priority),
|
||||
mPersist(p.persist),
|
||||
mDefaultFunctor(p.functor.isProvided() ? p.functor() : p.name())
|
||||
{
|
||||
if (p.sound.isProvided()
|
||||
&& LLUI::sSettingGroups["config"]->controlExists(p.sound))
|
||||
{
|
||||
mSoundEffect = LLUUID(LLUI::sSettingGroups["config"]->getString(p.sound));
|
||||
}
|
||||
|
||||
for(LLInitParam::ParamIterator<LLNotificationTemplate::UniquenessContext>::const_iterator it = p.unique.contexts.begin(),
|
||||
end_it = p.unique.contexts.end();
|
||||
it != end_it;
|
||||
++it)
|
||||
{
|
||||
mUniqueContext.push_back(it->key);
|
||||
}
|
||||
|
||||
mForm = LLNotificationFormPtr(new LLNotificationForm(p.name, p.form_ref.form));
|
||||
}
|
||||
|
||||
LLNotification::LLNotification(const LLNotification::Params& p) :
|
||||
|
|
@ -499,7 +604,7 @@ void LLNotification::respond(const LLSD& response)
|
|||
{
|
||||
mResponder->handleRespond(asLLSD(), response);
|
||||
}
|
||||
else
|
||||
else if (!mResponseFunctorName.empty())
|
||||
{
|
||||
// look up the functor
|
||||
LLNotificationFunctorRegistry::ResponseFunctor functor =
|
||||
|
|
@ -507,6 +612,11 @@ void LLNotification::respond(const LLSD& response)
|
|||
// and then call it
|
||||
functor(asLLSD(), response);
|
||||
}
|
||||
else
|
||||
{
|
||||
// no registered responder
|
||||
return;
|
||||
}
|
||||
|
||||
if (mTemporaryResponder && !isReusable())
|
||||
{
|
||||
|
|
@ -517,8 +627,7 @@ void LLNotification::respond(const LLSD& response)
|
|||
|
||||
if (mForm->getIgnoreType() != LLNotificationForm::IGNORE_NO)
|
||||
{
|
||||
BOOL show_notification = mIgnored ? FALSE : TRUE;
|
||||
LLUI::sSettingGroups["ignores"]->setBOOL(getName(), show_notification);
|
||||
mForm->setIgnored(mIgnored);
|
||||
if (mIgnored && mForm->getIgnoreType() == LLNotificationForm::IGNORE_WITH_LAST_RESPONSE)
|
||||
{
|
||||
LLUI::sSettingGroups["ignores"]->setLLSD("Default" + getName(), response);
|
||||
|
|
@ -528,6 +637,49 @@ void LLNotification::respond(const LLSD& response)
|
|||
update();
|
||||
}
|
||||
|
||||
void LLNotification::respondWithDefault()
|
||||
{
|
||||
respond(getResponseTemplate(WITH_DEFAULT_BUTTON));
|
||||
}
|
||||
|
||||
|
||||
const std::string& LLNotification::getName() const
|
||||
{
|
||||
return mTemplatep->mName;
|
||||
}
|
||||
|
||||
const std::string& LLNotification::getIcon() const
|
||||
{
|
||||
return mTemplatep->mIcon;
|
||||
}
|
||||
|
||||
|
||||
bool LLNotification::isPersistent() const
|
||||
{
|
||||
return mTemplatep->mPersist;
|
||||
}
|
||||
|
||||
std::string LLNotification::getType() const
|
||||
{
|
||||
return (mTemplatep ? mTemplatep->mType : "");
|
||||
}
|
||||
|
||||
S32 LLNotification::getURLOption() const
|
||||
{
|
||||
return (mTemplatep ? mTemplatep->mURLOption : -1);
|
||||
}
|
||||
|
||||
S32 LLNotification::getURLOpenExternally() const
|
||||
{
|
||||
return(mTemplatep? mTemplatep->mURLTarget == "_external": -1);
|
||||
}
|
||||
|
||||
bool LLNotification::hasUniquenessConstraints() const
|
||||
{
|
||||
return (mTemplatep ? mTemplatep->mUnique : false);
|
||||
}
|
||||
|
||||
|
||||
void LLNotification::setIgnored(bool ignore)
|
||||
{
|
||||
mIgnored = ignore;
|
||||
|
|
@ -607,6 +759,8 @@ void LLNotification::init(const std::string& template_name, const LLSD& form_ele
|
|||
// apply substitution to form labels
|
||||
mForm->formatElements(mSubstitutions);
|
||||
|
||||
mIgnored = mForm->getIgnored();
|
||||
|
||||
LLDate rightnow = LLDate::now();
|
||||
if (mTemplatep->mExpireSeconds)
|
||||
{
|
||||
|
|
@ -910,12 +1064,12 @@ std::string LLNotificationChannel::summarize()
|
|||
// LLNotifications implementation
|
||||
// ---
|
||||
LLNotifications::LLNotifications() : LLNotificationChannelBase(LLNotificationFilters::includeEverything,
|
||||
LLNotificationComparators::orderByUUID()),
|
||||
mIgnoreAllNotifications(false)
|
||||
LLNotificationComparators::orderByUUID()),
|
||||
mIgnoreAllNotifications(false)
|
||||
{
|
||||
LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Notification.Show", boost::bind(&LLNotifications::addFromCallback, this, _2));
|
||||
|
||||
mListener.reset(new LLNotificationsListener(*this));
|
||||
|
||||
mListener.reset(new LLNotificationsListener(*this));
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1095,11 +1249,6 @@ bool LLNotifications::templateExists(const std::string& name)
|
|||
return (mTemplates.count(name) != 0);
|
||||
}
|
||||
|
||||
void LLNotifications::clearTemplates()
|
||||
{
|
||||
mTemplates.clear();
|
||||
}
|
||||
|
||||
void LLNotifications::forceResponse(const LLNotification::Params& params, S32 option)
|
||||
{
|
||||
LLNotificationPtr temp_notify(new LLNotification(params));
|
||||
|
|
@ -1162,190 +1311,88 @@ void replaceSubstitutionStrings(LLXMLNodePtr node, StringMap& replacements)
|
|||
}
|
||||
}
|
||||
|
||||
// private to this file
|
||||
// returns true if the template request was invalid and there's nothing else we
|
||||
// can do with this node, false if you should keep processing (it may have
|
||||
// replaced the contents of the node referred to)
|
||||
LLXMLNodePtr LLNotifications::checkForXMLTemplate(LLXMLNodePtr item)
|
||||
void replaceFormText(LLNotificationForm::Params& form, const std::string& pattern, const std::string& replace)
|
||||
{
|
||||
if (item->hasName("usetemplate"))
|
||||
if (form.ignore.isProvided() && form.ignore.text() == pattern)
|
||||
{
|
||||
std::string replacementName;
|
||||
if (item->getAttributeString("name", replacementName))
|
||||
form.ignore.text = replace;
|
||||
}
|
||||
for (LLInitParam::ParamIterator<LLNotificationForm::FormElement>::iterator it = form.form_elements.elements.begin(),
|
||||
end_it = form.form_elements.elements.end();
|
||||
it != end_it;
|
||||
++it)
|
||||
{
|
||||
if (it->button.isChosen() && it->button.text() == pattern)
|
||||
{
|
||||
StringMap replacements;
|
||||
for (LLXMLAttribList::const_iterator it=item->mAttributes.begin();
|
||||
it != item->mAttributes.end(); ++it)
|
||||
{
|
||||
replacements[it->second->getName()->mString] = it->second->getValue();
|
||||
}
|
||||
if (mXmlTemplates.count(replacementName))
|
||||
{
|
||||
item=LLXMLNode::replaceNode(item, mXmlTemplates[replacementName]);
|
||||
|
||||
// walk the nodes looking for $(substitution) here and replace
|
||||
replaceSubstitutionStrings(item, replacements);
|
||||
}
|
||||
else
|
||||
{
|
||||
llwarns << "XML template lookup failure on '" << replacementName << "' " << llendl;
|
||||
}
|
||||
it->button.text = replace;
|
||||
}
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
bool LLNotifications::loadTemplates()
|
||||
{
|
||||
const std::string xml_filename = "notifications.xml";
|
||||
std::string full_filename = gDirUtilp->findSkinnedFilename(LLUI::getXUIPaths().front(), xml_filename);
|
||||
|
||||
LLXMLNodePtr root;
|
||||
|
||||
BOOL success = LLUICtrlFactory::getLayeredXMLNode(xml_filename, root);
|
||||
|
||||
if (!success || root.isNull() || !root->hasName( "notifications" ))
|
||||
{
|
||||
llerrs << "Problem reading UI Notifications file: " << xml_filename << llendl;
|
||||
llerrs << "Problem reading UI Notifications file: " << full_filename << llendl;
|
||||
return false;
|
||||
}
|
||||
|
||||
clearTemplates();
|
||||
|
||||
for (LLXMLNodePtr item = root->getFirstChild();
|
||||
item.notNull(); item = item->getNextSibling())
|
||||
|
||||
LLNotificationTemplate::Notifications params;
|
||||
LLXUIParser parser;
|
||||
parser.readXUI(root, params, full_filename);
|
||||
|
||||
mTemplates.clear();
|
||||
|
||||
for(LLInitParam::ParamIterator<LLNotificationTemplate::GlobalString>::const_iterator it = params.strings.begin(), end_it = params.strings.end();
|
||||
it != end_it;
|
||||
++it)
|
||||
{
|
||||
// we do this FIRST so that item can be changed if we
|
||||
// encounter a usetemplate -- we just replace the
|
||||
// current xml node and keep processing
|
||||
item = checkForXMLTemplate(item);
|
||||
|
||||
if (item->hasName("global"))
|
||||
{
|
||||
std::string global_name;
|
||||
if (item->getAttributeString("name", global_name))
|
||||
{
|
||||
mGlobalStrings[global_name] = item->getTextContents();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (item->hasName("template"))
|
||||
{
|
||||
// store an xml template; templates must have a single node (can contain
|
||||
// other nodes)
|
||||
std::string name;
|
||||
item->getAttributeString("name", name);
|
||||
LLXMLNodePtr ptr = item->getFirstChild();
|
||||
mXmlTemplates[name] = ptr;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!item->hasName("notification"))
|
||||
{
|
||||
llwarns << "Unexpected entity " << item->getName()->mString <<
|
||||
" found in " << xml_filename << llendl;
|
||||
continue;
|
||||
}
|
||||
|
||||
// now we know we have a notification entry, so let's build it
|
||||
LLNotificationTemplatePtr pTemplate(new LLNotificationTemplate());
|
||||
|
||||
if (!item->getAttributeString("name", pTemplate->mName))
|
||||
{
|
||||
llwarns << "Unable to parse notification with no name" << llendl;
|
||||
continue;
|
||||
}
|
||||
|
||||
//llinfos << "Parsing " << pTemplate->mName << llendl;
|
||||
|
||||
pTemplate->mMessage = item->getTextContents();
|
||||
pTemplate->mDefaultFunctor = pTemplate->mName;
|
||||
item->getAttributeString("type", pTemplate->mType);
|
||||
item->getAttributeString("icon", pTemplate->mIcon);
|
||||
item->getAttributeString("label", pTemplate->mLabel);
|
||||
item->getAttributeU32("duration", pTemplate->mExpireSeconds);
|
||||
item->getAttributeU32("expireOption", pTemplate->mExpireOption);
|
||||
|
||||
std::string priority;
|
||||
item->getAttributeString("priority", priority);
|
||||
pTemplate->mPriority = NOTIFICATION_PRIORITY_NORMAL;
|
||||
if (!priority.empty())
|
||||
{
|
||||
if (priority == "low") pTemplate->mPriority = NOTIFICATION_PRIORITY_LOW;
|
||||
if (priority == "normal") pTemplate->mPriority = NOTIFICATION_PRIORITY_NORMAL;
|
||||
if (priority == "high") pTemplate->mPriority = NOTIFICATION_PRIORITY_HIGH;
|
||||
if (priority == "critical") pTemplate->mPriority = NOTIFICATION_PRIORITY_CRITICAL;
|
||||
}
|
||||
|
||||
item->getAttributeString("functor", pTemplate->mDefaultFunctor);
|
||||
|
||||
BOOL persist = false;
|
||||
item->getAttributeBOOL("persist", persist);
|
||||
pTemplate->mPersist = persist;
|
||||
|
||||
std::string sound;
|
||||
item->getAttributeString("sound", sound);
|
||||
if (!sound.empty())
|
||||
{
|
||||
// test for bad sound effect name / missing effect
|
||||
if (LLUI::sSettingGroups["config"]->controlExists(sound))
|
||||
{
|
||||
pTemplate->mSoundEffect =
|
||||
LLUUID(LLUI::sSettingGroups["config"]->getString(sound));
|
||||
}
|
||||
else
|
||||
{
|
||||
llwarns << "Unknown sound effect control name " << sound
|
||||
<< llendl;
|
||||
}
|
||||
}
|
||||
|
||||
for (LLXMLNodePtr child = item->getFirstChild();
|
||||
!child.isNull(); child = child->getNextSibling())
|
||||
{
|
||||
child = checkForXMLTemplate(child);
|
||||
|
||||
// <url>
|
||||
if (child->hasName("url"))
|
||||
{
|
||||
pTemplate->mURL = child->getTextContents();
|
||||
child->getAttributeU32("option", pTemplate->mURLOption);
|
||||
child->getAttributeU32("openexternally", pTemplate->mURLOpenExternally);
|
||||
}
|
||||
|
||||
if (child->hasName("unique"))
|
||||
{
|
||||
pTemplate->mUnique = true;
|
||||
for (LLXMLNodePtr formitem = child->getFirstChild();
|
||||
!formitem.isNull(); formitem = formitem->getNextSibling())
|
||||
{
|
||||
if (formitem->hasName("context"))
|
||||
{
|
||||
std::string key;
|
||||
formitem->getAttributeString("key", key);
|
||||
pTemplate->mUniqueContext.push_back(key);
|
||||
//llwarns << "adding " << key << " to unique context" << llendl;
|
||||
}
|
||||
else
|
||||
{
|
||||
llwarns << "'unique' has unrecognized subelement "
|
||||
<< formitem->getName()->mString << llendl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// <form>
|
||||
if (child->hasName("form"))
|
||||
{
|
||||
pTemplate->mForm = LLNotificationFormPtr(new LLNotificationForm(pTemplate->mName, child));
|
||||
}
|
||||
}
|
||||
addTemplate(pTemplate->mName, pTemplate);
|
||||
mGlobalStrings[it->name] = it->value;
|
||||
}
|
||||
|
||||
//std::ostringstream ostream;
|
||||
//root->writeToOstream(ostream, "\n ");
|
||||
//llwarns << ostream.str() << llendl;
|
||||
|
||||
|
||||
std::map<std::string, LLNotificationForm::Params> form_templates;
|
||||
|
||||
for(LLInitParam::ParamIterator<LLNotificationTemplate::Template>::const_iterator it = params.templates.begin(), end_it = params.templates.end();
|
||||
it != end_it;
|
||||
++it)
|
||||
{
|
||||
form_templates[it->name] = it->form;
|
||||
}
|
||||
|
||||
for(LLInitParam::ParamIterator<LLNotificationTemplate::Params>::iterator it = params.notifications.begin(), end_it = params.notifications.end();
|
||||
it != end_it;
|
||||
++it)
|
||||
{
|
||||
if (it->form_ref.form_template.isChosen())
|
||||
{
|
||||
// replace form contents from template
|
||||
it->form_ref.form = form_templates[it->form_ref.form_template.name];
|
||||
if(it->form_ref.form_template.yes_text.isProvided())
|
||||
{
|
||||
replaceFormText(it->form_ref.form, "$yestext", it->form_ref.form_template.yes_text);
|
||||
}
|
||||
if(it->form_ref.form_template.no_text.isProvided())
|
||||
{
|
||||
replaceFormText(it->form_ref.form, "$notext", it->form_ref.form_template.no_text);
|
||||
}
|
||||
if(it->form_ref.form_template.cancel_text.isProvided())
|
||||
{
|
||||
replaceFormText(it->form_ref.form, "$canceltext", it->form_ref.form_template.cancel_text);
|
||||
}
|
||||
if(it->form_ref.form_template.ignore_text.isProvided())
|
||||
{
|
||||
replaceFormText(it->form_ref.form, "$ignoretext", it->form_ref.form_template.ignore_text);
|
||||
}
|
||||
}
|
||||
addTemplate(it->name, LLNotificationTemplatePtr(new LLNotificationTemplate(*it)));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -1396,6 +1443,8 @@ LLNotificationPtr LLNotifications::add(const LLNotification::Params& p)
|
|||
|
||||
void LLNotifications::add(const LLNotificationPtr pNotif)
|
||||
{
|
||||
if (pNotif == NULL) return;
|
||||
|
||||
// first see if we already have it -- if so, that's a problem
|
||||
LLNotificationSet::iterator it=mItems.find(pNotif);
|
||||
if (it != mItems.end())
|
||||
|
|
@ -1408,6 +1457,8 @@ void LLNotifications::add(const LLNotificationPtr pNotif)
|
|||
|
||||
void LLNotifications::cancel(LLNotificationPtr pNotif)
|
||||
{
|
||||
if (pNotif == NULL) return;
|
||||
|
||||
LLNotificationSet::iterator it=mItems.find(pNotif);
|
||||
if (it == mItems.end())
|
||||
{
|
||||
|
|
@ -1417,6 +1468,30 @@ void LLNotifications::cancel(LLNotificationPtr pNotif)
|
|||
updateItem(LLSD().with("sigtype", "delete").with("id", pNotif->id()), pNotif);
|
||||
}
|
||||
|
||||
void LLNotifications::cancelByName(const std::string& name)
|
||||
{
|
||||
std::vector<LLNotificationPtr> notifs_to_cancel;
|
||||
for (LLNotificationSet::iterator it=mItems.begin(), end_it = mItems.end();
|
||||
it != end_it;
|
||||
++it)
|
||||
{
|
||||
LLNotificationPtr pNotif = *it;
|
||||
if (pNotif->getName() == name)
|
||||
{
|
||||
notifs_to_cancel.push_back(pNotif);
|
||||
}
|
||||
}
|
||||
|
||||
for (std::vector<LLNotificationPtr>::iterator it = notifs_to_cancel.begin(), end_it = notifs_to_cancel.end();
|
||||
it != end_it;
|
||||
++it)
|
||||
{
|
||||
LLNotificationPtr pNotif = *it;
|
||||
pNotif->cancel();
|
||||
updateItem(LLSD().with("sigtype", "delete").with("id", pNotif->id()), pNotif);
|
||||
}
|
||||
}
|
||||
|
||||
void LLNotifications::update(const LLNotificationPtr pNotif)
|
||||
{
|
||||
LLNotificationSet::iterator it=mItems.find(pNotif);
|
||||
|
|
@ -1481,17 +1556,50 @@ std::ostream& operator<<(std::ostream& s, const LLNotification& notification)
|
|||
return s;
|
||||
}
|
||||
|
||||
void LLPostponedNotification::onCachedNameReceived(const LLUUID& id, const std::string& first,
|
||||
const std::string& last, bool is_group)
|
||||
//static
|
||||
void LLPostponedNotification::lookupName(LLPostponedNotification* thiz,
|
||||
const LLUUID& id,
|
||||
bool is_group)
|
||||
{
|
||||
mName = first + " " + last;
|
||||
|
||||
LLStringUtil::trim(mName);
|
||||
if (mName.empty())
|
||||
if (is_group)
|
||||
{
|
||||
llwarns << "Empty name received for Id: " << id << llendl;
|
||||
mName = SYSTEM_FROM;
|
||||
gCacheName->getGroup(id,
|
||||
boost::bind(&LLPostponedNotification::onGroupNameCache,
|
||||
thiz, _1, _2, _3));
|
||||
}
|
||||
else
|
||||
{
|
||||
LLAvatarNameCache::get(id,
|
||||
boost::bind(&LLPostponedNotification::onAvatarNameCache,
|
||||
thiz, _1, _2));
|
||||
}
|
||||
}
|
||||
|
||||
void LLPostponedNotification::onGroupNameCache(const LLUUID& id,
|
||||
const std::string& full_name,
|
||||
bool is_group)
|
||||
{
|
||||
finalizeName(full_name);
|
||||
}
|
||||
|
||||
void LLPostponedNotification::onAvatarNameCache(const LLUUID& agent_id,
|
||||
const LLAvatarName& av_name)
|
||||
{
|
||||
std::string name = av_name.getCompleteName();
|
||||
|
||||
// from PE merge - we should figure out if this is the right thing to do
|
||||
if (name.empty())
|
||||
{
|
||||
llwarns << "Empty name received for Id: " << agent_id << llendl;
|
||||
name = SYSTEM_FROM;
|
||||
}
|
||||
|
||||
finalizeName(name);
|
||||
}
|
||||
|
||||
void LLPostponedNotification::finalizeName(const std::string& name)
|
||||
{
|
||||
mName = name;
|
||||
modifyNotificationParams();
|
||||
LLNotifications::instance().add(mParams);
|
||||
cleanup();
|
||||
|
|
|
|||
|
|
@ -98,9 +98,8 @@
|
|||
#include "llinitparam.h"
|
||||
#include "llnotificationslistener.h"
|
||||
#include "llnotificationptr.h"
|
||||
#include "llcachename.h"
|
||||
|
||||
|
||||
class LLAvatarName;
|
||||
typedef enum e_notification_priority
|
||||
{
|
||||
NOTIFICATION_PRIORITY_UNSPECIFIED,
|
||||
|
|
@ -110,6 +109,11 @@ typedef enum e_notification_priority
|
|||
NOTIFICATION_PRIORITY_CRITICAL
|
||||
} ENotificationPriority;
|
||||
|
||||
struct NotificationPriorityValues : public LLInitParam::TypeValuesHelper<ENotificationPriority, NotificationPriorityValues>
|
||||
{
|
||||
static void declareValues();
|
||||
};
|
||||
|
||||
class LLNotificationResponderInterface
|
||||
{
|
||||
public:
|
||||
|
|
@ -157,6 +161,68 @@ class LLNotificationForm
|
|||
LOG_CLASS(LLNotificationForm);
|
||||
|
||||
public:
|
||||
struct FormElementBase : public LLInitParam::Block<FormElementBase>
|
||||
{
|
||||
Optional<std::string> name;
|
||||
|
||||
FormElementBase();
|
||||
};
|
||||
|
||||
struct FormIgnore : public LLInitParam::Block<FormIgnore, FormElementBase>
|
||||
{
|
||||
Optional<std::string> text;
|
||||
Optional<bool> save_option;
|
||||
Optional<std::string> control;
|
||||
Optional<bool> invert_control;
|
||||
|
||||
FormIgnore();
|
||||
};
|
||||
|
||||
struct FormButton : public LLInitParam::Block<FormButton, FormElementBase>
|
||||
{
|
||||
Mandatory<S32> index;
|
||||
Mandatory<std::string> text;
|
||||
Optional<std::string> ignore;
|
||||
Optional<bool> is_default;
|
||||
|
||||
Mandatory<std::string> type;
|
||||
|
||||
FormButton();
|
||||
};
|
||||
|
||||
struct FormInput : public LLInitParam::Block<FormInput, FormElementBase>
|
||||
{
|
||||
Mandatory<std::string> type;
|
||||
Optional<S32> width;
|
||||
Optional<S32> max_length_chars;
|
||||
|
||||
Optional<std::string> value;
|
||||
FormInput();
|
||||
};
|
||||
|
||||
struct FormElement : public LLInitParam::Choice<FormElement>
|
||||
{
|
||||
Alternative<FormButton> button;
|
||||
Alternative<FormInput> input;
|
||||
|
||||
FormElement();
|
||||
};
|
||||
|
||||
struct FormElements : public LLInitParam::Block<FormElements>
|
||||
{
|
||||
Multiple<FormElement> elements;
|
||||
FormElements();
|
||||
};
|
||||
|
||||
struct Params : public LLInitParam::Block<Params>
|
||||
{
|
||||
Optional<std::string> name;
|
||||
Optional<FormIgnore> ignore;
|
||||
Optional<FormElements> form_elements;
|
||||
|
||||
Params();
|
||||
};
|
||||
|
||||
typedef enum e_ignore_type
|
||||
{
|
||||
IGNORE_NO,
|
||||
|
|
@ -167,8 +233,7 @@ public:
|
|||
|
||||
LLNotificationForm();
|
||||
LLNotificationForm(const LLSD& sd);
|
||||
LLNotificationForm(const std::string& name,
|
||||
const LLPointer<class LLXMLNode> xml_node);
|
||||
LLNotificationForm(const std::string& name, const Params& p);
|
||||
|
||||
LLSD asLLSD() const;
|
||||
|
||||
|
|
@ -181,92 +246,25 @@ public:
|
|||
// appends form elements from another form serialized as LLSD
|
||||
void append(const LLSD& sub_form);
|
||||
std::string getDefaultOption();
|
||||
LLPointer<class LLControlVariable> getIgnoreSetting();
|
||||
bool getIgnored();
|
||||
void setIgnored(bool ignored);
|
||||
|
||||
EIgnoreType getIgnoreType() { return mIgnore; }
|
||||
std::string getIgnoreMessage() { return mIgnoreMsg; }
|
||||
|
||||
private:
|
||||
LLSD mFormData;
|
||||
EIgnoreType mIgnore;
|
||||
std::string mIgnoreMsg;
|
||||
LLSD mFormData;
|
||||
EIgnoreType mIgnore;
|
||||
std::string mIgnoreMsg;
|
||||
LLPointer<class LLControlVariable> mIgnoreSetting;
|
||||
bool mInvertSetting;
|
||||
};
|
||||
|
||||
typedef boost::shared_ptr<LLNotificationForm> LLNotificationFormPtr;
|
||||
|
||||
// This is the class of object read from the XML file (notifications.xml,
|
||||
// from the appropriate local language directory).
|
||||
struct LLNotificationTemplate
|
||||
{
|
||||
LLNotificationTemplate();
|
||||
// the name of the notification -- the key used to identify it
|
||||
// Ideally, the key should follow variable naming rules
|
||||
// (no spaces or punctuation).
|
||||
std::string mName;
|
||||
// The type of the notification
|
||||
// used to control which queue it's stored in
|
||||
std::string mType;
|
||||
// The text used to display the notification. Replaceable parameters
|
||||
// are enclosed in square brackets like this [].
|
||||
std::string mMessage;
|
||||
// The label for the notification; used for
|
||||
// certain classes of notification (those with a window and a window title).
|
||||
// Also used when a notification pops up underneath the current one.
|
||||
// Replaceable parameters can be used in the label.
|
||||
std::string mLabel;
|
||||
// The name of the icon image. This should include an extension.
|
||||
std::string mIcon;
|
||||
// This is the Highlander bit -- "There Can Be Only One"
|
||||
// An outstanding notification with this bit set
|
||||
// is updated by an incoming notification with the same name,
|
||||
// rather than creating a new entry in the queue.
|
||||
// (used for things like progress indications, or repeating warnings
|
||||
// like "the grid is going down in N minutes")
|
||||
bool mUnique;
|
||||
// if we want to be unique only if a certain part of the payload is constant
|
||||
// specify the field names for the payload. The notification will only be
|
||||
// combined if all of the fields named in the context are identical in the
|
||||
// new and the old notification; otherwise, the notification will be
|
||||
// duplicated. This is to support suppressing duplicate offers from the same
|
||||
// sender but still differentiating different offers. Example: Invitation to
|
||||
// conference chat.
|
||||
std::vector<std::string> mUniqueContext;
|
||||
// If this notification expires automatically, this value will be
|
||||
// nonzero, and indicates the number of seconds for which the notification
|
||||
// will be valid (a teleport offer, for example, might be valid for
|
||||
// 300 seconds).
|
||||
U32 mExpireSeconds;
|
||||
// if the offer expires, one of the options is chosen automatically
|
||||
// based on its "value" parameter. This controls which one.
|
||||
// If expireSeconds is specified, expireOption should also be specified.
|
||||
U32 mExpireOption;
|
||||
// if the notification contains a url, it's stored here (and replaced
|
||||
// into the message where [_URL] is found)
|
||||
std::string mURL;
|
||||
// if there's a URL in the message, this controls which option visits
|
||||
// that URL. Obsolete this and eliminate the buttons for affected
|
||||
// messages when we allow clickable URLs in the UI
|
||||
U32 mURLOption;
|
||||
|
||||
U32 mURLOpenExternally;
|
||||
//This is a flag that tells if the url needs to open externally dispite
|
||||
//what the user setting is.
|
||||
|
||||
// does this notification persist across sessions? if so, it will be
|
||||
// serialized to disk on first receipt and read on startup
|
||||
bool mPersist;
|
||||
// This is the name of the default functor, if present, to be
|
||||
// used for the notification's callback. It is optional, and used only if
|
||||
// the notification is constructed without an identified functor.
|
||||
std::string mDefaultFunctor;
|
||||
// The form data associated with a given notification (buttons, text boxes, etc)
|
||||
LLNotificationFormPtr mForm;
|
||||
// default priority for notifications of this type
|
||||
ENotificationPriority mPriority;
|
||||
// UUID of the audio file to be played when this notification arrives
|
||||
// this is loaded as a name, but looked up to get the UUID upon template load.
|
||||
// If null, it wasn't specified.
|
||||
LLUUID mSoundEffect;
|
||||
};
|
||||
|
||||
struct LLNotificationTemplate;
|
||||
|
||||
// we want to keep a map of these by name, and it's best to manage them
|
||||
// with smart pointers
|
||||
|
|
@ -302,7 +300,7 @@ public:
|
|||
// optional
|
||||
Optional<LLSD> substitutions;
|
||||
Optional<LLSD> payload;
|
||||
Optional<ENotificationPriority> priority;
|
||||
Optional<ENotificationPriority, NotificationPriorityValues> priority;
|
||||
Optional<LLSD> form_elements;
|
||||
Optional<LLDate> time_stamp;
|
||||
Optional<LLNotificationContext*> context;
|
||||
|
|
@ -445,6 +443,7 @@ public:
|
|||
LLSD asLLSD();
|
||||
|
||||
void respond(const LLSD& sd);
|
||||
void respondWithDefault();
|
||||
|
||||
void* getResponder() { return mResponderObj; }
|
||||
|
||||
|
|
@ -462,6 +461,13 @@ public:
|
|||
return mRespondedTo;
|
||||
}
|
||||
|
||||
bool isActive() const
|
||||
{
|
||||
return !isRespondedTo()
|
||||
&& !isCancelled()
|
||||
&& !isExpired();
|
||||
}
|
||||
|
||||
const LLSD& getResponse() { return mResponse; }
|
||||
|
||||
bool isIgnored() const
|
||||
|
|
@ -469,15 +475,11 @@ public:
|
|||
return mIgnored;
|
||||
}
|
||||
|
||||
const std::string& getName() const
|
||||
{
|
||||
return mTemplatep->mName;
|
||||
}
|
||||
const std::string& getName() const;
|
||||
|
||||
bool isPersistent() const
|
||||
{
|
||||
return mTemplatep->mPersist;
|
||||
}
|
||||
const std::string& getIcon() const;
|
||||
|
||||
bool isPersistent() const;
|
||||
|
||||
const LLUUID& id() const
|
||||
{
|
||||
|
|
@ -499,28 +501,12 @@ public:
|
|||
return mTimestamp;
|
||||
}
|
||||
|
||||
std::string getType() const
|
||||
{
|
||||
return (mTemplatep ? mTemplatep->mType : "");
|
||||
}
|
||||
|
||||
std::string getType() const;
|
||||
std::string getMessage() const;
|
||||
std::string getLabel() const;
|
||||
|
||||
std::string getURL() const;
|
||||
// {
|
||||
// return (mTemplatep ? mTemplatep->mURL : "");
|
||||
// }
|
||||
|
||||
S32 getURLOption() const
|
||||
{
|
||||
return (mTemplatep ? mTemplatep->mURLOption : -1);
|
||||
}
|
||||
|
||||
S32 getURLOpenExternally() const
|
||||
{
|
||||
return(mTemplatep? mTemplatep->mURLOpenExternally : -1);
|
||||
}
|
||||
S32 getURLOption() const;
|
||||
S32 getURLOpenExternally() const;
|
||||
|
||||
const LLNotificationFormPtr getForm();
|
||||
|
||||
|
|
@ -590,7 +576,7 @@ public:
|
|||
|
||||
std::string summarize() const;
|
||||
|
||||
bool hasUniquenessConstraints() const { return (mTemplatep ? mTemplatep->mUnique : false);}
|
||||
bool hasUniquenessConstraints() const;
|
||||
|
||||
virtual ~LLNotification() {}
|
||||
};
|
||||
|
|
@ -872,7 +858,6 @@ public:
|
|||
// load notification descriptions from file;
|
||||
// OK to call more than once because it will reload
|
||||
bool loadTemplates();
|
||||
LLPointer<class LLXMLNode> checkForXMLTemplate(LLPointer<class LLXMLNode> item);
|
||||
|
||||
// Add a simple notification (from XUI)
|
||||
void addFromCallback(const LLSD& name);
|
||||
|
|
@ -894,6 +879,7 @@ public:
|
|||
|
||||
void add(const LLNotificationPtr pNotif);
|
||||
void cancel(LLNotificationPtr pNotif);
|
||||
void cancelByName(const std::string& name);
|
||||
void update(const LLNotificationPtr pNotif);
|
||||
|
||||
LLNotificationPtr find(LLUUID uuid);
|
||||
|
|
@ -917,8 +903,6 @@ public:
|
|||
|
||||
// test for existence
|
||||
bool templateExists(const std::string& name);
|
||||
// useful if you're reloading the file
|
||||
void clearTemplates(); // erase all templates
|
||||
|
||||
void forceResponse(const LLNotification::Params& params, S32 option);
|
||||
|
||||
|
|
@ -956,9 +940,6 @@ private:
|
|||
|
||||
std::string mFileName;
|
||||
|
||||
typedef std::map<std::string, LLPointer<class LLXMLNode> > XMLTemplateMap;
|
||||
XMLTemplateMap mXmlTemplates;
|
||||
|
||||
LLNotificationMap mUniqueNotifications;
|
||||
|
||||
typedef std::map<std::string, std::string> GlobalStringMap;
|
||||
|
|
@ -994,17 +975,20 @@ public:
|
|||
{
|
||||
// upcast T to the base type to restrict T derivation from LLPostponedNotification
|
||||
LLPostponedNotification* thiz = new T();
|
||||
|
||||
thiz->mParams = params;
|
||||
|
||||
gCacheName->get(id, is_group, boost::bind(
|
||||
&LLPostponedNotification::onCachedNameReceived, thiz, _1, _2,
|
||||
_3, _4));
|
||||
// Avoid header file dependency on llcachename.h
|
||||
lookupName(thiz, id, is_group);
|
||||
}
|
||||
|
||||
private:
|
||||
void onCachedNameReceived(const LLUUID& id, const std::string& first,
|
||||
const std::string& last, bool is_group);
|
||||
static void lookupName(LLPostponedNotification* thiz, const LLUUID& id, bool is_group);
|
||||
// only used for groups
|
||||
void onGroupNameCache(const LLUUID& id, const std::string& full_name, bool is_group);
|
||||
// only used for avatars
|
||||
void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name);
|
||||
// used for both group and avatar names
|
||||
void finalizeName(const std::string& name);
|
||||
|
||||
void cleanup()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
#include "linden_common.h"
|
||||
#include "llnotificationslistener.h"
|
||||
#include "llnotifications.h"
|
||||
#include "llnotificationtemplate.h"
|
||||
#include "llsd.h"
|
||||
#include "llui.h"
|
||||
|
||||
|
|
@ -182,7 +183,11 @@ void LLNotificationsListener::ignore(const LLSD& params) const
|
|||
if (params["name"].isDefined())
|
||||
{
|
||||
// ["name"] was passed: ignore just that notification
|
||||
LLUI::sSettingGroups["ignores"]->setBOOL(params["name"], ignore);
|
||||
LLNotificationTemplatePtr templatep = mNotifications.getTemplate(params["name"]);
|
||||
if (templatep)
|
||||
{
|
||||
templatep->mForm->setIgnored(ignore);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,282 @@
|
|||
/**
|
||||
* @file llnotificationtemplate.h
|
||||
* @brief Description of notification contents
|
||||
* @author Q (with assistance from Richard and Coco)
|
||||
*
|
||||
* $LicenseInfo:firstyear=2008&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_LLNOTIFICATION_TEMPLATE_H
|
||||
#define LL_LLNOTIFICATION_TEMPLATE_H
|
||||
|
||||
//#include <string>
|
||||
//#include <list>
|
||||
//#include <vector>
|
||||
//#include <map>
|
||||
//#include <set>
|
||||
//#include <iomanip>
|
||||
//#include <sstream>
|
||||
//
|
||||
//#include <boost/utility.hpp>
|
||||
//#include <boost/shared_ptr.hpp>
|
||||
//#include <boost/enable_shared_from_this.hpp>
|
||||
//#include <boost/type_traits.hpp>
|
||||
//
|
||||
//// we want to minimize external dependencies, but this one is important
|
||||
//#include "llsd.h"
|
||||
//
|
||||
//// and we need this to manage the notification callbacks
|
||||
//#include "llevents.h"
|
||||
//#include "llfunctorregistry.h"
|
||||
//#include "llpointer.h"
|
||||
#include "llinitparam.h"
|
||||
//#include "llnotificationslistener.h"
|
||||
//#include "llnotificationptr.h"
|
||||
//#include "llcachename.h"
|
||||
#include "llnotifications.h"
|
||||
|
||||
|
||||
typedef boost::shared_ptr<LLNotificationForm> LLNotificationFormPtr;
|
||||
|
||||
// This is the class of object read from the XML file (notifications.xml,
|
||||
// from the appropriate local language directory).
|
||||
struct LLNotificationTemplate
|
||||
{
|
||||
struct GlobalString : public LLInitParam::Block<GlobalString>
|
||||
{
|
||||
Mandatory<std::string> name,
|
||||
value;
|
||||
|
||||
GlobalString()
|
||||
: name("name"),
|
||||
value("value")
|
||||
{}
|
||||
};
|
||||
|
||||
struct UniquenessContext : public LLInitParam::Block<UniquenessContext>
|
||||
{
|
||||
Mandatory<std::string> key;
|
||||
|
||||
UniquenessContext()
|
||||
: key("key")
|
||||
{}
|
||||
|
||||
};
|
||||
|
||||
struct UniquenessConstraint : public LLInitParam::Block<UniquenessConstraint>
|
||||
{
|
||||
private:
|
||||
// this idiom allows
|
||||
// <notification unique="true">
|
||||
// as well as
|
||||
// <notification> <unique> <context key=""/> </unique>...
|
||||
Optional<bool> dummy_val;
|
||||
public:
|
||||
Multiple<UniquenessContext> contexts;
|
||||
|
||||
UniquenessConstraint()
|
||||
: contexts("context"),
|
||||
dummy_val("")
|
||||
{}
|
||||
};
|
||||
|
||||
// Templates are used to define common form types, such as OK/Cancel dialogs, etc.
|
||||
|
||||
struct Template : public LLInitParam::Block<Template>
|
||||
{
|
||||
Mandatory<std::string> name;
|
||||
Mandatory<LLNotificationForm::Params> form;
|
||||
|
||||
Template()
|
||||
: name("name"),
|
||||
form("form")
|
||||
{}
|
||||
};
|
||||
|
||||
// Reference a template to use its form elements
|
||||
struct TemplateRef : public LLInitParam::Block<TemplateRef>
|
||||
{
|
||||
Mandatory<std::string> name;
|
||||
Optional<std::string> yes_text,
|
||||
no_text,
|
||||
cancel_text,
|
||||
ignore_text;
|
||||
|
||||
TemplateRef()
|
||||
: name("name"),
|
||||
yes_text("yestext"),
|
||||
no_text("notext"),
|
||||
cancel_text("canceltext"),
|
||||
ignore_text("ignoretext")
|
||||
{}
|
||||
};
|
||||
|
||||
struct URL : public LLInitParam::Block<URL>
|
||||
{
|
||||
Mandatory<S32> option;
|
||||
Mandatory<std::string> value;
|
||||
Optional<std::string> target;
|
||||
Ignored name;
|
||||
|
||||
URL()
|
||||
: option("option", -1),
|
||||
value("value"),
|
||||
target("target", "_blank"),
|
||||
name("name")
|
||||
{}
|
||||
};
|
||||
|
||||
struct FormRef : public LLInitParam::Choice<FormRef>
|
||||
{
|
||||
Alternative<LLNotificationForm::Params> form;
|
||||
Alternative<TemplateRef> form_template;
|
||||
|
||||
FormRef()
|
||||
: form("form"),
|
||||
form_template("usetemplate")
|
||||
{}
|
||||
};
|
||||
|
||||
struct Params : public LLInitParam::Block<Params>
|
||||
{
|
||||
Mandatory<std::string> name;
|
||||
Optional<bool> persist;
|
||||
Optional<std::string> functor,
|
||||
icon,
|
||||
label,
|
||||
sound,
|
||||
type,
|
||||
value;
|
||||
Optional<U32> duration;
|
||||
Optional<S32> expire_option;
|
||||
Optional<URL> url;
|
||||
Optional<UniquenessConstraint> unique;
|
||||
Optional<FormRef> form_ref;
|
||||
Optional<ENotificationPriority,
|
||||
NotificationPriorityValues> priority;
|
||||
|
||||
|
||||
Params()
|
||||
: name("name"),
|
||||
persist("persist", false),
|
||||
functor("functor"),
|
||||
icon("icon"),
|
||||
label("label"),
|
||||
priority("priority"),
|
||||
sound("sound"),
|
||||
type("type"),
|
||||
value("value"),
|
||||
duration("duration"),
|
||||
expire_option("expireOption", -1),
|
||||
url("url"),
|
||||
unique("unique"),
|
||||
form_ref("")
|
||||
{}
|
||||
|
||||
};
|
||||
|
||||
struct Notifications : public LLInitParam::Block<Notifications>
|
||||
{
|
||||
Multiple<GlobalString> strings;
|
||||
Multiple<Template> templates;
|
||||
Multiple<Params> notifications;
|
||||
|
||||
Notifications()
|
||||
: strings("global"),
|
||||
notifications("notification"),
|
||||
templates("template")
|
||||
{}
|
||||
};
|
||||
|
||||
LLNotificationTemplate(const Params& p);
|
||||
// the name of the notification -- the key used to identify it
|
||||
// Ideally, the key should follow variable naming rules
|
||||
// (no spaces or punctuation).
|
||||
std::string mName;
|
||||
// The type of the notification
|
||||
// used to control which queue it's stored in
|
||||
std::string mType;
|
||||
// The text used to display the notification. Replaceable parameters
|
||||
// are enclosed in square brackets like this [].
|
||||
std::string mMessage;
|
||||
// The label for the notification; used for
|
||||
// certain classes of notification (those with a window and a window title).
|
||||
// Also used when a notification pops up underneath the current one.
|
||||
// Replaceable parameters can be used in the label.
|
||||
std::string mLabel;
|
||||
// The name of the icon image. This should include an extension.
|
||||
std::string mIcon;
|
||||
// This is the Highlander bit -- "There Can Be Only One"
|
||||
// An outstanding notification with this bit set
|
||||
// is updated by an incoming notification with the same name,
|
||||
// rather than creating a new entry in the queue.
|
||||
// (used for things like progress indications, or repeating warnings
|
||||
// like "the grid is going down in N minutes")
|
||||
bool mUnique;
|
||||
// if we want to be unique only if a certain part of the payload is constant
|
||||
// specify the field names for the payload. The notification will only be
|
||||
// combined if all of the fields named in the context are identical in the
|
||||
// new and the old notification; otherwise, the notification will be
|
||||
// duplicated. This is to support suppressing duplicate offers from the same
|
||||
// sender but still differentiating different offers. Example: Invitation to
|
||||
// conference chat.
|
||||
std::vector<std::string> mUniqueContext;
|
||||
// If this notification expires automatically, this value will be
|
||||
// nonzero, and indicates the number of seconds for which the notification
|
||||
// will be valid (a teleport offer, for example, might be valid for
|
||||
// 300 seconds).
|
||||
U32 mExpireSeconds;
|
||||
// if the offer expires, one of the options is chosen automatically
|
||||
// based on its "value" parameter. This controls which one.
|
||||
// If expireSeconds is specified, expireOption should also be specified.
|
||||
U32 mExpireOption;
|
||||
// if the notification contains a url, it's stored here (and replaced
|
||||
// into the message where [_URL] is found)
|
||||
std::string mURL;
|
||||
// if there's a URL in the message, this controls which option visits
|
||||
// that URL. Obsolete this and eliminate the buttons for affected
|
||||
// messages when we allow clickable URLs in the UI
|
||||
U32 mURLOption;
|
||||
|
||||
std::string mURLTarget;
|
||||
//This is a flag that tells if the url needs to open externally dispite
|
||||
//what the user setting is.
|
||||
|
||||
// does this notification persist across sessions? if so, it will be
|
||||
// serialized to disk on first receipt and read on startup
|
||||
bool mPersist;
|
||||
// This is the name of the default functor, if present, to be
|
||||
// used for the notification's callback. It is optional, and used only if
|
||||
// the notification is constructed without an identified functor.
|
||||
std::string mDefaultFunctor;
|
||||
// The form data associated with a given notification (buttons, text boxes, etc)
|
||||
LLNotificationFormPtr mForm;
|
||||
// default priority for notifications of this type
|
||||
ENotificationPriority mPriority;
|
||||
// UUID of the audio file to be played when this notification arrives
|
||||
// this is loaded as a name, but looked up to get the UUID upon template load.
|
||||
// If null, it wasn't specified.
|
||||
LLUUID mSoundEffect;
|
||||
};
|
||||
|
||||
#endif //LL_LLNOTIFICATION_TEMPLATE_H
|
||||
|
||||
|
|
@ -35,6 +35,7 @@
|
|||
#include "llfontgl.h"
|
||||
#include "llrect.h"
|
||||
#include "llerror.h"
|
||||
#include "lldir.h"
|
||||
#include "lltimer.h"
|
||||
|
||||
#include "llaccordionctrltab.h"
|
||||
|
|
@ -52,6 +53,8 @@
|
|||
#include "lltabcontainer.h"
|
||||
|
||||
static LLDefaultChildRegistry::Register<LLPanel> r1("panel", &LLPanel::fromXML);
|
||||
LLPanel::factory_stack_t LLPanel::sFactoryStack;
|
||||
|
||||
|
||||
// Compiler optimization, generate extern template
|
||||
template class LLPanel* LLView::getChild<class LLPanel>(
|
||||
|
|
@ -380,8 +383,7 @@ LLView* LLPanel::fromXML(LLXMLNodePtr node, LLView* parent, LLXMLNodePtr output_
|
|||
|
||||
LLPanel* panelp = NULL;
|
||||
|
||||
{
|
||||
LLFastTimer timer(FTM_PANEL_CONSTRUCTION);
|
||||
{ LLFastTimer _(FTM_PANEL_CONSTRUCTION);
|
||||
|
||||
if(!class_attr.empty())
|
||||
{
|
||||
|
|
@ -394,7 +396,7 @@ LLView* LLPanel::fromXML(LLXMLNodePtr node, LLView* parent, LLXMLNodePtr output_
|
|||
|
||||
if (!panelp)
|
||||
{
|
||||
panelp = LLUICtrlFactory::getInstance()->createFactoryPanel(name);
|
||||
panelp = createFactoryPanel(name);
|
||||
llassert(panelp);
|
||||
|
||||
if (!panelp)
|
||||
|
|
@ -407,20 +409,20 @@ LLView* LLPanel::fromXML(LLXMLNodePtr node, LLView* parent, LLXMLNodePtr output_
|
|||
// factory panels may have registered their own factory maps
|
||||
if (!panelp->getFactoryMap().empty())
|
||||
{
|
||||
LLUICtrlFactory::instance().pushFactoryFunctions(&panelp->getFactoryMap());
|
||||
sFactoryStack.push_back(&panelp->getFactoryMap());
|
||||
}
|
||||
// for local registry callbacks; define in constructor, referenced in XUI or postBuild
|
||||
panelp->mCommitCallbackRegistrar.pushScope();
|
||||
panelp->mEnableCallbackRegistrar.pushScope();
|
||||
|
||||
panelp->initPanelXML(node, parent, output_node);
|
||||
panelp->initPanelXML(node, parent, output_node, LLUICtrlFactory::getDefaultParams<LLPanel>());
|
||||
|
||||
panelp->mCommitCallbackRegistrar.popScope();
|
||||
panelp->mEnableCallbackRegistrar.popScope();
|
||||
|
||||
if (!panelp->getFactoryMap().empty())
|
||||
{
|
||||
LLUICtrlFactory::instance().popFactoryFunctions();
|
||||
sFactoryStack.pop_back();
|
||||
}
|
||||
|
||||
return panelp;
|
||||
|
|
@ -444,8 +446,8 @@ void LLPanel::initFromParams(const LLPanel::Params& p)
|
|||
setVisibleCallback(initCommitCallback(p.visible_callback));
|
||||
}
|
||||
|
||||
for (LLInitParam::ParamIterator<LocalizedString>::const_iterator it = p.strings().begin();
|
||||
it != p.strings().end();
|
||||
for (LLInitParam::ParamIterator<LocalizedString>::const_iterator it = p.strings.begin();
|
||||
it != p.strings.end();
|
||||
++it)
|
||||
{
|
||||
mUIStrings[it->name] = it->value;
|
||||
|
|
@ -487,11 +489,9 @@ static LLFastTimer::DeclareTimer FTM_PANEL_SETUP("Panel Setup");
|
|||
static LLFastTimer::DeclareTimer FTM_EXTERNAL_PANEL_LOAD("Load Extern Panel Reference");
|
||||
static LLFastTimer::DeclareTimer FTM_PANEL_POSTBUILD("Panel PostBuild");
|
||||
|
||||
BOOL LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node)
|
||||
BOOL LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node, const LLPanel::Params& default_params)
|
||||
{
|
||||
const LLPanel::Params& default_params(LLUICtrlFactory::getDefaultParams<LLPanel>());
|
||||
Params params(default_params);
|
||||
|
||||
{
|
||||
LLFastTimer timer(FTM_PANEL_SETUP);
|
||||
|
||||
|
|
@ -505,6 +505,8 @@ BOOL LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr outpu
|
|||
setXMLFilename(xml_filename);
|
||||
}
|
||||
|
||||
LLXUIParser parser;
|
||||
|
||||
if (!xml_filename.empty())
|
||||
{
|
||||
LLUICtrlFactory::instance().pushFileName(xml_filename);
|
||||
|
|
@ -514,12 +516,11 @@ BOOL LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr outpu
|
|||
{
|
||||
//if we are exporting, we want to export the current xml
|
||||
//not the referenced xml
|
||||
LLXUIParser::instance().readXUI(node, params, LLUICtrlFactory::getInstance()->getCurFileName());
|
||||
parser.readXUI(node, params, LLUICtrlFactory::getInstance()->getCurFileName());
|
||||
Params output_params(params);
|
||||
setupParamsForExport(output_params, parent);
|
||||
output_node->setName(node->getName()->mString);
|
||||
LLXUIParser::instance().writeXUI(
|
||||
output_node, output_params, &default_params);
|
||||
parser.writeXUI(output_node, output_params, &default_params);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -530,7 +531,7 @@ BOOL LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr outpu
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
LLXUIParser::instance().readXUI(referenced_xml, params, LLUICtrlFactory::getInstance()->getCurFileName());
|
||||
parser.readXUI(referenced_xml, params, LLUICtrlFactory::getInstance()->getCurFileName());
|
||||
|
||||
// add children using dimensions from referenced xml for consistent layout
|
||||
setShape(params.rect);
|
||||
|
|
@ -540,15 +541,14 @@ BOOL LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr outpu
|
|||
}
|
||||
|
||||
// ask LLUICtrlFactory for filename, since xml_filename might be empty
|
||||
LLXUIParser::instance().readXUI(node, params, LLUICtrlFactory::getInstance()->getCurFileName());
|
||||
parser.readXUI(node, params, LLUICtrlFactory::getInstance()->getCurFileName());
|
||||
|
||||
if (output_node)
|
||||
{
|
||||
Params output_params(params);
|
||||
setupParamsForExport(output_params, parent);
|
||||
output_node->setName(node->getName()->mString);
|
||||
LLXUIParser::instance().writeXUI(
|
||||
output_node, output_params, &default_params);
|
||||
parser.writeXUI(output_node, output_params, &default_params);
|
||||
}
|
||||
|
||||
params.from_xui = true;
|
||||
|
|
@ -959,3 +959,89 @@ boost::signals2::connection LLPanel::setVisibleCallback( const commit_signal_t::
|
|||
|
||||
return mVisibleSignal->connect(cb);
|
||||
}
|
||||
|
||||
static LLFastTimer::DeclareTimer FTM_BUILD_PANELS("Build Panels");
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// buildPanel()
|
||||
//-----------------------------------------------------------------------------
|
||||
BOOL LLPanel::buildFromFile(const std::string& filename, LLXMLNodePtr output_node, const LLPanel::Params& default_params)
|
||||
{
|
||||
LLFastTimer timer(FTM_BUILD_PANELS);
|
||||
BOOL didPost = FALSE;
|
||||
LLXMLNodePtr root;
|
||||
|
||||
//if exporting, only load the language being exported,
|
||||
//instead of layering localized version on top of english
|
||||
if (output_node)
|
||||
{
|
||||
if (!LLUICtrlFactory::getLocalizedXMLNode(filename, root))
|
||||
{
|
||||
llwarns << "Couldn't parse panel from: " << LLUI::getLocalizedSkinPath() + gDirUtilp->getDirDelimiter() + filename << llendl;
|
||||
return didPost;
|
||||
}
|
||||
}
|
||||
else if (!LLUICtrlFactory::getLayeredXMLNode(filename, root))
|
||||
{
|
||||
llwarns << "Couldn't parse panel from: " << LLUI::getSkinPath() + gDirUtilp->getDirDelimiter() + filename << llendl;
|
||||
return didPost;
|
||||
}
|
||||
|
||||
// root must be called panel
|
||||
if( !root->hasName("panel" ) )
|
||||
{
|
||||
llwarns << "Root node should be named panel in : " << filename << llendl;
|
||||
return didPost;
|
||||
}
|
||||
|
||||
lldebugs << "Building panel " << filename << llendl;
|
||||
|
||||
LLUICtrlFactory::instance().pushFileName(filename);
|
||||
{
|
||||
if (!getFactoryMap().empty())
|
||||
{
|
||||
sFactoryStack.push_back(&getFactoryMap());
|
||||
}
|
||||
|
||||
// for local registry callbacks; define in constructor, referenced in XUI or postBuild
|
||||
getCommitCallbackRegistrar().pushScope();
|
||||
getEnableCallbackRegistrar().pushScope();
|
||||
|
||||
didPost = initPanelXML(root, NULL, output_node, default_params);
|
||||
|
||||
getCommitCallbackRegistrar().popScope();
|
||||
getEnableCallbackRegistrar().popScope();
|
||||
|
||||
setXMLFilename(filename);
|
||||
|
||||
if (!getFactoryMap().empty())
|
||||
{
|
||||
sFactoryStack.pop_back();
|
||||
}
|
||||
}
|
||||
LLUICtrlFactory::instance().popFileName();
|
||||
return didPost;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// createFactoryPanel()
|
||||
//-----------------------------------------------------------------------------
|
||||
LLPanel* LLPanel::createFactoryPanel(const std::string& name)
|
||||
{
|
||||
std::deque<const LLCallbackMap::map_t*>::iterator itor;
|
||||
for (itor = sFactoryStack.begin(); itor != sFactoryStack.end(); ++itor)
|
||||
{
|
||||
const LLCallbackMap::map_t* factory_map = *itor;
|
||||
|
||||
// Look up this panel's name in the map.
|
||||
LLCallbackMap::map_const_iter_t iter = factory_map->find( name );
|
||||
if (iter != factory_map->end())
|
||||
{
|
||||
// Use the factory to create the panel, instead of using a default LLPanel.
|
||||
LLPanel *ret = (LLPanel*) iter->second.mCallback( iter->second.mData );
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
LLPanel::Params panel_p;
|
||||
return LLUICtrlFactory::create<LLPanel>(panel_p);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -104,7 +104,10 @@ protected:
|
|||
LLPanel(const LLPanel::Params& params = getDefaultParams());
|
||||
|
||||
public:
|
||||
// LLPanel(const std::string& name, const LLRect& rect = LLRect(), BOOL bordered = TRUE);
|
||||
BOOL buildFromFile(const std::string &filename, LLXMLNodePtr output_node = NULL, const LLPanel::Params&default_params = getDefaultParams());
|
||||
|
||||
static LLPanel* createFactoryPanel(const std::string& name);
|
||||
|
||||
/*virtual*/ ~LLPanel();
|
||||
|
||||
// LLView interface
|
||||
|
|
@ -157,7 +160,7 @@ public:
|
|||
EnableCallbackRegistry::ScopedRegistrar& getEnableCallbackRegistrar() { return mEnableCallbackRegistrar; }
|
||||
|
||||
void initFromParams(const Params& p);
|
||||
BOOL initPanelXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node = NULL);
|
||||
BOOL initPanelXML( LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node, const LLPanel::Params& default_params);
|
||||
|
||||
bool hasString(const std::string& name);
|
||||
std::string getString(const std::string& name, const LLStringUtil::format_map_t& args) const;
|
||||
|
|
@ -256,6 +259,8 @@ protected:
|
|||
commit_signal_t* mVisibleSignal; // Called when visibility changes, passes new visibility as LLSD()
|
||||
|
||||
std::string mHelpTopic; // the name of this panel's help topic to display in the Help Viewer
|
||||
typedef std::deque<const LLCallbackMap::map_t*> factory_stack_t;
|
||||
static factory_stack_t sFactoryStack;
|
||||
|
||||
private:
|
||||
BOOL mBgVisible; // any background at all?
|
||||
|
|
@ -285,4 +290,57 @@ extern template class LLPanel* LLView::getChild<class LLPanel>(
|
|||
const std::string& name, BOOL recurse) const;
|
||||
#endif
|
||||
|
||||
typedef boost::function<LLPanel* (void)> LLPanelClassCreatorFunc;
|
||||
|
||||
// local static instance for registering a particular panel class
|
||||
|
||||
class LLRegisterPanelClass
|
||||
: public LLSingleton< LLRegisterPanelClass >
|
||||
{
|
||||
public:
|
||||
// reigister with either the provided builder, or the generic templated builder
|
||||
void addPanelClass(const std::string& tag,LLPanelClassCreatorFunc func)
|
||||
{
|
||||
mPanelClassesNames[tag] = func;
|
||||
}
|
||||
|
||||
LLPanel* createPanelClass(const std::string& tag)
|
||||
{
|
||||
param_name_map_t::iterator iT = mPanelClassesNames.find(tag);
|
||||
if(iT == mPanelClassesNames.end())
|
||||
return 0;
|
||||
return iT->second();
|
||||
}
|
||||
template<typename T>
|
||||
static T* defaultPanelClassBuilder()
|
||||
{
|
||||
T* pT = new T();
|
||||
return pT;
|
||||
}
|
||||
|
||||
private:
|
||||
typedef std::map< std::string, LLPanelClassCreatorFunc> param_name_map_t;
|
||||
|
||||
param_name_map_t mPanelClassesNames;
|
||||
};
|
||||
|
||||
|
||||
// local static instance for registering a particular panel class
|
||||
template<typename T>
|
||||
class LLRegisterPanelClassWrapper
|
||||
: public LLRegisterPanelClass
|
||||
{
|
||||
public:
|
||||
// reigister with either the provided builder, or the generic templated builder
|
||||
LLRegisterPanelClassWrapper(const std::string& tag);
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
LLRegisterPanelClassWrapper<T>::LLRegisterPanelClassWrapper(const std::string& tag)
|
||||
{
|
||||
LLRegisterPanelClass::instance().addPanelClass(tag,&LLRegisterPanelClass::defaultPanelClassBuilder<T>);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -100,8 +100,8 @@ LLRadioGroup::LLRadioGroup(const LLRadioGroup::Params& p)
|
|||
|
||||
void LLRadioGroup::initFromParams(const Params& p)
|
||||
{
|
||||
for (LLInitParam::ParamIterator<ItemParams>::const_iterator it = p.items().begin();
|
||||
it != p.items().end();
|
||||
for (LLInitParam::ParamIterator<ItemParams>::const_iterator it = p.items.begin();
|
||||
it != p.items.end();
|
||||
++it)
|
||||
{
|
||||
LLRadioGroup::ItemParams item_params(*it);
|
||||
|
|
|
|||
|
|
@ -30,10 +30,15 @@
|
|||
#include "lluicolor.h"
|
||||
#include "lluictrlfactory.h"
|
||||
|
||||
static LLInitParam::Parser::parser_read_func_map_t sReadFuncs;
|
||||
static LLInitParam::Parser::parser_write_func_map_t sWriteFuncs;
|
||||
static LLInitParam::Parser::parser_inspect_func_map_t sInspectFuncs;
|
||||
|
||||
//
|
||||
// LLRNGWriter - writes Relax NG schema files based on a param block
|
||||
//
|
||||
LLRNGWriter::LLRNGWriter()
|
||||
: Parser(sReadFuncs, sWriteFuncs, sInspectFuncs)
|
||||
{
|
||||
// register various callbacks for inspecting the contents of a param block
|
||||
registerInspectFunc<bool>(boost::bind(&LLRNGWriter::writeAttribute, this, "boolean", _1, _2, _3, _4));
|
||||
|
|
|
|||
|
|
@ -259,15 +259,15 @@ LLScrollListCtrl::LLScrollListCtrl(const LLScrollListCtrl::Params& p)
|
|||
}
|
||||
|
||||
|
||||
for (LLInitParam::ParamIterator<LLScrollListColumn::Params>::const_iterator row_it = p.contents.columns().begin();
|
||||
row_it != p.contents.columns().end();
|
||||
for (LLInitParam::ParamIterator<LLScrollListColumn::Params>::const_iterator row_it = p.contents.columns.begin();
|
||||
row_it != p.contents.columns.end();
|
||||
++row_it)
|
||||
{
|
||||
addColumn(*row_it);
|
||||
}
|
||||
|
||||
for (LLInitParam::ParamIterator<LLScrollListItem::Params>::const_iterator row_it = p.contents.rows().begin();
|
||||
row_it != p.contents.rows().end();
|
||||
for (LLInitParam::ParamIterator<LLScrollListItem::Params>::const_iterator row_it = p.contents.rows.begin();
|
||||
row_it != p.contents.rows.end();
|
||||
++row_it)
|
||||
{
|
||||
addRow(*row_it);
|
||||
|
|
@ -537,23 +537,7 @@ BOOL LLScrollListCtrl::addItem( LLScrollListItem* item, EAddPosition pos, BOOL r
|
|||
setNeedsSort();
|
||||
break;
|
||||
|
||||
case ADD_SORTED:
|
||||
{
|
||||
// sort by column 0, in ascending order
|
||||
std::vector<sort_column_t> single_sort_column;
|
||||
single_sort_column.push_back(std::make_pair(0, TRUE));
|
||||
|
||||
mItemList.push_back(item);
|
||||
std::stable_sort(
|
||||
mItemList.begin(),
|
||||
mItemList.end(),
|
||||
SortScrollListItem(single_sort_column,mSortCallback));
|
||||
|
||||
// ADD_SORTED just sorts by first column...
|
||||
// this might not match user sort criteria, so flag list as being in unsorted state
|
||||
setNeedsSort();
|
||||
break;
|
||||
}
|
||||
case ADD_DEFAULT:
|
||||
case ADD_BOTTOM:
|
||||
mItemList.push_back(item);
|
||||
setNeedsSort();
|
||||
|
|
@ -2578,7 +2562,8 @@ BOOL LLScrollListCtrl::canDeselect() const
|
|||
void LLScrollListCtrl::addColumn(const LLSD& column, EAddPosition pos)
|
||||
{
|
||||
LLScrollListColumn::Params p;
|
||||
LLParamSDParser::instance().readSD(column, p);
|
||||
LLParamSDParser parser;
|
||||
parser.readSD(column, p);
|
||||
addColumn(p, pos);
|
||||
}
|
||||
|
||||
|
|
@ -2764,31 +2749,35 @@ LLScrollListColumn* LLScrollListCtrl::getColumn(const std::string& name)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
LLFastTimer::DeclareTimer FTM_ADD_SCROLLLIST_ELEMENT("Add Scroll List Item");
|
||||
LLScrollListItem* LLScrollListCtrl::addElement(const LLSD& element, EAddPosition pos, void* userdata)
|
||||
{
|
||||
LLFastTimer _(FTM_ADD_SCROLLLIST_ELEMENT);
|
||||
LLScrollListItem::Params item_params;
|
||||
LLParamSDParser::instance().readSD(element, item_params);
|
||||
LLParamSDParser parser;
|
||||
parser.readSD(element, item_params);
|
||||
item_params.userdata = userdata;
|
||||
return addRow(item_params, pos);
|
||||
}
|
||||
|
||||
LLScrollListItem* LLScrollListCtrl::addRow(const LLScrollListItem::Params& item_p, EAddPosition pos)
|
||||
{
|
||||
LLFastTimer _(FTM_ADD_SCROLLLIST_ELEMENT);
|
||||
LLScrollListItem *new_item = new LLScrollListItem(item_p);
|
||||
return addRow(new_item, item_p, pos);
|
||||
}
|
||||
|
||||
LLScrollListItem* LLScrollListCtrl::addRow(LLScrollListItem *new_item, const LLScrollListItem::Params& item_p, EAddPosition pos)
|
||||
{
|
||||
LLFastTimer _(FTM_ADD_SCROLLLIST_ELEMENT);
|
||||
if (!item_p.validateBlock() || !new_item) return NULL;
|
||||
new_item->setNumColumns(mColumns.size());
|
||||
|
||||
// Add any columns we don't already have
|
||||
S32 col_index = 0;
|
||||
|
||||
for(LLInitParam::ParamIterator<LLScrollListCell::Params>::const_iterator itor = item_p.columns().begin();
|
||||
itor != item_p.columns().end();
|
||||
for(LLInitParam::ParamIterator<LLScrollListCell::Params>::const_iterator itor = item_p.columns.begin();
|
||||
itor != item_p.columns.end();
|
||||
++itor)
|
||||
{
|
||||
LLScrollListCell::Params cell_p = *itor;
|
||||
|
|
@ -2839,7 +2828,7 @@ LLScrollListItem* LLScrollListCtrl::addRow(LLScrollListItem *new_item, const LLS
|
|||
col_index++;
|
||||
}
|
||||
|
||||
if (item_p.columns().empty())
|
||||
if (item_p.columns.empty())
|
||||
{
|
||||
if (mColumns.empty())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -29,49 +29,42 @@
|
|||
|
||||
// Project includes
|
||||
#include "llsdparam.h"
|
||||
#include "llsdutil.h"
|
||||
|
||||
static LLInitParam::Parser::parser_read_func_map_t sReadFuncs;
|
||||
static LLInitParam::Parser::parser_write_func_map_t sWriteFuncs;
|
||||
static LLInitParam::Parser::parser_inspect_func_map_t sInspectFuncs;
|
||||
|
||||
//
|
||||
// LLParamSDParser
|
||||
//
|
||||
LLParamSDParser::LLParamSDParser()
|
||||
: Parser(sReadFuncs, sWriteFuncs, sInspectFuncs)
|
||||
{
|
||||
using boost::bind;
|
||||
|
||||
registerParserFuncs<S32>(bind(&LLParamSDParser::readTypedValue<S32>, this, _1, &LLSD::asInteger),
|
||||
bind(&LLParamSDParser::writeTypedValue<S32>, this, _1, _2));
|
||||
registerParserFuncs<U32>(bind(&LLParamSDParser::readTypedValue<U32>, this, _1, &LLSD::asInteger),
|
||||
bind(&LLParamSDParser::writeU32Param, this, _1, _2));
|
||||
registerParserFuncs<F32>(bind(&LLParamSDParser::readTypedValue<F32>, this, _1, &LLSD::asReal),
|
||||
bind(&LLParamSDParser::writeTypedValue<F32>, this, _1, _2));
|
||||
registerParserFuncs<F64>(bind(&LLParamSDParser::readTypedValue<F64>, this, _1, &LLSD::asReal),
|
||||
bind(&LLParamSDParser::writeTypedValue<F64>, this, _1, _2));
|
||||
registerParserFuncs<bool>(bind(&LLParamSDParser::readTypedValue<F32>, this, _1, &LLSD::asBoolean),
|
||||
bind(&LLParamSDParser::writeTypedValue<F32>, this, _1, _2));
|
||||
registerParserFuncs<std::string>(bind(&LLParamSDParser::readTypedValue<std::string>, this, _1, &LLSD::asString),
|
||||
bind(&LLParamSDParser::writeTypedValue<std::string>, this, _1, _2));
|
||||
registerParserFuncs<LLUUID>(bind(&LLParamSDParser::readTypedValue<LLUUID>, this, _1, &LLSD::asUUID),
|
||||
bind(&LLParamSDParser::writeTypedValue<LLUUID>, this, _1, _2));
|
||||
registerParserFuncs<LLDate>(bind(&LLParamSDParser::readTypedValue<LLDate>, this, _1, &LLSD::asDate),
|
||||
bind(&LLParamSDParser::writeTypedValue<LLDate>, this, _1, _2));
|
||||
registerParserFuncs<LLURI>(bind(&LLParamSDParser::readTypedValue<LLURI>, this, _1, &LLSD::asURI),
|
||||
bind(&LLParamSDParser::writeTypedValue<LLURI>, this, _1, _2));
|
||||
registerParserFuncs<LLSD>(bind(&LLParamSDParser::readSDParam, this, _1),
|
||||
bind(&LLParamSDParser::writeTypedValue<LLSD>, this, _1, _2));
|
||||
}
|
||||
|
||||
bool LLParamSDParser::readSDParam(void* value_ptr)
|
||||
{
|
||||
if (!mCurReadSD) return false;
|
||||
*((LLSD*)value_ptr) = *mCurReadSD;
|
||||
return true;
|
||||
if (sReadFuncs.empty())
|
||||
{
|
||||
registerParserFuncs<S32>(readS32, &LLParamSDParser::writeTypedValue<S32>);
|
||||
registerParserFuncs<U32>(readU32, &LLParamSDParser::writeU32Param);
|
||||
registerParserFuncs<F32>(readF32, &LLParamSDParser::writeTypedValue<F32>);
|
||||
registerParserFuncs<F64>(readF64, &LLParamSDParser::writeTypedValue<F64>);
|
||||
registerParserFuncs<bool>(readBool, &LLParamSDParser::writeTypedValue<bool>);
|
||||
registerParserFuncs<std::string>(readString, &LLParamSDParser::writeTypedValue<std::string>);
|
||||
registerParserFuncs<LLUUID>(readUUID, &LLParamSDParser::writeTypedValue<LLUUID>);
|
||||
registerParserFuncs<LLDate>(readDate, &LLParamSDParser::writeTypedValue<LLDate>);
|
||||
registerParserFuncs<LLURI>(readURI, &LLParamSDParser::writeTypedValue<LLURI>);
|
||||
registerParserFuncs<LLSD>(readSD, &LLParamSDParser::writeTypedValue<LLSD>);
|
||||
}
|
||||
}
|
||||
|
||||
// special case handling of U32 due to ambiguous LLSD::assign overload
|
||||
bool LLParamSDParser::writeU32Param(const void* val_ptr, const parser_t::name_stack_t& name_stack)
|
||||
bool LLParamSDParser::writeU32Param(LLParamSDParser::parser_t& parser, const void* val_ptr, const parser_t::name_stack_t& name_stack)
|
||||
{
|
||||
if (!mWriteSD) return false;
|
||||
LLParamSDParser& sdparser = static_cast<LLParamSDParser&>(parser);
|
||||
if (!sdparser.mWriteRootSD) return false;
|
||||
|
||||
LLSD* sd_to_write = getSDWriteNode(name_stack);
|
||||
LLSD* sd_to_write = sdparser.getSDWriteNode(name_stack);
|
||||
if (!sd_to_write) return false;
|
||||
|
||||
sd_to_write->assign((S32)*((const U32*)val_ptr));
|
||||
|
|
@ -89,7 +82,8 @@ void LLParamSDParser::readSD(const LLSD& sd, LLInitParam::BaseBlock& block, bool
|
|||
|
||||
void LLParamSDParser::writeSD(LLSD& sd, const LLInitParam::BaseBlock& block)
|
||||
{
|
||||
mWriteSD = &sd;
|
||||
mNameStack.clear();
|
||||
mWriteRootSD = &sd;
|
||||
block.serializeBlock(*this);
|
||||
}
|
||||
|
||||
|
|
@ -139,6 +133,155 @@ void LLParamSDParser::readSDValues(const LLSD& sd, LLInitParam::BaseBlock& block
|
|||
LLSD* LLParamSDParser::getSDWriteNode(const parser_t::name_stack_t& name_stack)
|
||||
{
|
||||
//TODO: implement nested LLSD writing
|
||||
return mWriteSD;
|
||||
LLSD* sd_to_write = mWriteRootSD;
|
||||
bool new_traversal = false;
|
||||
for (name_stack_t::const_iterator it = name_stack.begin(), prev_it = mNameStack.begin();
|
||||
it != name_stack.end();
|
||||
++it)
|
||||
{
|
||||
bool new_array_entry = false;
|
||||
if (prev_it == mNameStack.end())
|
||||
{
|
||||
new_traversal = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!new_traversal // have not diverged yet from previous trace
|
||||
&& prev_it->first == it->first // names match
|
||||
&& prev_it->second != it->second) // versions differ
|
||||
{
|
||||
// name stacks match, but version numbers differ in last place.
|
||||
// create a different entry at this point using an LLSD array
|
||||
new_array_entry = true;
|
||||
}
|
||||
if (prev_it->first != it->first // names differ
|
||||
|| prev_it->second != it->second) // versions differ
|
||||
{
|
||||
// at this point we have diverged from our last trace
|
||||
// so any elements referenced here are new
|
||||
new_traversal = true;
|
||||
}
|
||||
}
|
||||
|
||||
LLSD* child_sd = &(*sd_to_write)[it->first];
|
||||
|
||||
if (child_sd->isArray())
|
||||
{
|
||||
if (new_traversal)
|
||||
{
|
||||
// write to new element at end
|
||||
sd_to_write = &(*child_sd)[child_sd->size()];
|
||||
}
|
||||
else
|
||||
{
|
||||
// write to last of existing elements, or first element if empty
|
||||
sd_to_write = &(*child_sd)[llmax(0, child_sd->size() - 1)];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (new_array_entry && !child_sd->isArray())
|
||||
{
|
||||
// copy child contents into first element of an array
|
||||
LLSD new_array = LLSD::emptyArray();
|
||||
new_array.append(*child_sd);
|
||||
// assign array to slot that previously held the single value
|
||||
*child_sd = new_array;
|
||||
// return next element in that array
|
||||
sd_to_write = &((*child_sd)[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
sd_to_write = child_sd;
|
||||
}
|
||||
}
|
||||
if (prev_it != mNameStack.end())
|
||||
{
|
||||
++prev_it;
|
||||
}
|
||||
}
|
||||
mNameStack = name_stack;
|
||||
|
||||
//llinfos << ll_pretty_print_sd(*mWriteRootSD) << llendl;
|
||||
return sd_to_write;
|
||||
}
|
||||
|
||||
bool LLParamSDParser::readS32(Parser& parser, void* val_ptr)
|
||||
{
|
||||
LLParamSDParser& self = static_cast<LLParamSDParser&>(parser);
|
||||
|
||||
*((S32*)val_ptr) = self.mCurReadSD->asInteger();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LLParamSDParser::readU32(Parser& parser, void* val_ptr)
|
||||
{
|
||||
LLParamSDParser& self = static_cast<LLParamSDParser&>(parser);
|
||||
|
||||
*((U32*)val_ptr) = self.mCurReadSD->asInteger();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LLParamSDParser::readF32(Parser& parser, void* val_ptr)
|
||||
{
|
||||
LLParamSDParser& self = static_cast<LLParamSDParser&>(parser);
|
||||
|
||||
*((F32*)val_ptr) = self.mCurReadSD->asReal();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LLParamSDParser::readF64(Parser& parser, void* val_ptr)
|
||||
{
|
||||
LLParamSDParser& self = static_cast<LLParamSDParser&>(parser);
|
||||
|
||||
*((F64*)val_ptr) = self.mCurReadSD->asReal();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LLParamSDParser::readBool(Parser& parser, void* val_ptr)
|
||||
{
|
||||
LLParamSDParser& self = static_cast<LLParamSDParser&>(parser);
|
||||
|
||||
*((bool*)val_ptr) = self.mCurReadSD->asBoolean();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LLParamSDParser::readString(Parser& parser, void* val_ptr)
|
||||
{
|
||||
LLParamSDParser& self = static_cast<LLParamSDParser&>(parser);
|
||||
|
||||
*((std::string*)val_ptr) = self.mCurReadSD->asString();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LLParamSDParser::readUUID(Parser& parser, void* val_ptr)
|
||||
{
|
||||
LLParamSDParser& self = static_cast<LLParamSDParser&>(parser);
|
||||
|
||||
*((LLUUID*)val_ptr) = self.mCurReadSD->asUUID();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LLParamSDParser::readDate(Parser& parser, void* val_ptr)
|
||||
{
|
||||
LLParamSDParser& self = static_cast<LLParamSDParser&>(parser);
|
||||
|
||||
*((LLDate*)val_ptr) = self.mCurReadSD->asDate();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LLParamSDParser::readURI(Parser& parser, void* val_ptr)
|
||||
{
|
||||
LLParamSDParser& self = static_cast<LLParamSDParser&>(parser);
|
||||
|
||||
*((LLURI*)val_ptr) = self.mCurReadSD->asURI();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LLParamSDParser::readSD(Parser& parser, void* val_ptr)
|
||||
{
|
||||
LLParamSDParser& self = static_cast<LLParamSDParser&>(parser);
|
||||
|
||||
*((LLSD*)val_ptr) = *self.mCurReadSD;
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,17 +31,14 @@
|
|||
#include "llinitparam.h"
|
||||
|
||||
class LLParamSDParser
|
||||
: public LLInitParam::Parser,
|
||||
public LLSingleton<LLParamSDParser>
|
||||
: public LLInitParam::Parser
|
||||
{
|
||||
LOG_CLASS(LLParamSDParser);
|
||||
|
||||
typedef LLInitParam::Parser parser_t;
|
||||
|
||||
protected:
|
||||
LLParamSDParser();
|
||||
friend class LLSingleton<LLParamSDParser>;
|
||||
public:
|
||||
LLParamSDParser();
|
||||
void readSD(const LLSD& sd, LLInitParam::BaseBlock& block, bool silent = false);
|
||||
void writeSD(LLSD& sd, const LLInitParam::BaseBlock& block);
|
||||
|
||||
|
|
@ -51,20 +48,12 @@ private:
|
|||
void readSDValues(const LLSD& sd, LLInitParam::BaseBlock& block);
|
||||
|
||||
template<typename T>
|
||||
bool readTypedValue(void* val_ptr, boost::function<T(const LLSD&)> parser_func)
|
||||
{
|
||||
if (!mCurReadSD) return false;
|
||||
|
||||
*((T*)val_ptr) = parser_func(*mCurReadSD);
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool writeTypedValue(const void* val_ptr, const parser_t::name_stack_t& name_stack)
|
||||
static bool writeTypedValue(Parser& parser, const void* val_ptr, const parser_t::name_stack_t& name_stack)
|
||||
{
|
||||
if (!mWriteSD) return false;
|
||||
LLParamSDParser& sdparser = static_cast<LLParamSDParser&>(parser);
|
||||
if (!sdparser.mWriteRootSD) return false;
|
||||
|
||||
LLSD* sd_to_write = getSDWriteNode(name_stack);
|
||||
LLSD* sd_to_write = sdparser.getSDWriteNode(name_stack);
|
||||
if (!sd_to_write) return false;
|
||||
|
||||
sd_to_write->assign(*((const T*)val_ptr));
|
||||
|
|
@ -73,12 +62,23 @@ private:
|
|||
|
||||
LLSD* getSDWriteNode(const parser_t::name_stack_t& name_stack);
|
||||
|
||||
bool readSDParam(void* value_ptr);
|
||||
bool writeU32Param(const void* value_ptr, const parser_t::name_stack_t& name_stack);
|
||||
static bool writeU32Param(Parser& parser, const void* value_ptr, const parser_t::name_stack_t& name_stack);
|
||||
|
||||
static bool readS32(Parser& parser, void* val_ptr);
|
||||
static bool readU32(Parser& parser, void* val_ptr);
|
||||
static bool readF32(Parser& parser, void* val_ptr);
|
||||
static bool readF64(Parser& parser, void* val_ptr);
|
||||
static bool readBool(Parser& parser, void* val_ptr);
|
||||
static bool readString(Parser& parser, void* val_ptr);
|
||||
static bool readUUID(Parser& parser, void* val_ptr);
|
||||
static bool readDate(Parser& parser, void* val_ptr);
|
||||
static bool readURI(Parser& parser, void* val_ptr);
|
||||
static bool readSD(Parser& parser, void* val_ptr);
|
||||
|
||||
Parser::name_stack_t mNameStack;
|
||||
const LLSD* mCurReadSD;
|
||||
LLSD* mWriteSD;
|
||||
LLSD* mWriteRootSD;
|
||||
LLSD* mCurWriteSD;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
|
|
@ -88,7 +88,8 @@ class LLSDParamAdapter : public T
|
|||
LLSDParamAdapter() {}
|
||||
LLSDParamAdapter(const LLSD& sd)
|
||||
{
|
||||
LLParamSDParser::instance().readSD(sd, *this);
|
||||
LLParamSDParser parser;
|
||||
parser.readSD(sd, *this);
|
||||
}
|
||||
|
||||
LLSDParamAdapter(const T& val)
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ LLSpinCtrl::LLSpinCtrl(const LLSpinCtrl::Params& p)
|
|||
{
|
||||
params.font(p.font);
|
||||
}
|
||||
params.max_length_bytes(MAX_STRING_LENGTH);
|
||||
params.max_length.bytes(MAX_STRING_LENGTH);
|
||||
params.commit_callback.function((boost::bind(&LLSpinCtrl::onEditorCommit, this, _2)));
|
||||
|
||||
if( mPrecision>0 )//should accept float numbers
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@ LLStyle::Params::Params()
|
|||
selected_color("selected_color", LLColor4::black),
|
||||
font("font", LLFontGL::getFontMonospace()),
|
||||
image("image"),
|
||||
link_href("href")
|
||||
link_href("href"),
|
||||
is_link("is_link")
|
||||
{}
|
||||
|
||||
|
||||
|
|
@ -51,6 +52,7 @@ LLStyle::LLStyle(const LLStyle::Params& p)
|
|||
mSelectedColor(p.selected_color),
|
||||
mFont(p.font()),
|
||||
mLink(p.link_href),
|
||||
mIsLink(p.is_link.isProvided() ? p.is_link : !p.link_href().empty()),
|
||||
mDropShadow(p.drop_shadow),
|
||||
mImagep(p.image())
|
||||
{}
|
||||
|
|
@ -73,7 +75,7 @@ void LLStyle::setLinkHREF(const std::string& href)
|
|||
|
||||
BOOL LLStyle::isLink() const
|
||||
{
|
||||
return mLink.size();
|
||||
return mIsLink;
|
||||
}
|
||||
|
||||
BOOL LLStyle::isVisible() const
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ public:
|
|||
Optional<const LLFontGL*> font;
|
||||
Optional<LLUIImage*> image;
|
||||
Optional<std::string> link_href;
|
||||
Optional<bool> is_link;
|
||||
Params();
|
||||
};
|
||||
LLStyle(const Params& p = Params());
|
||||
|
|
@ -106,6 +107,7 @@ private:
|
|||
std::string mFontName;
|
||||
const LLFontGL* mFont;
|
||||
std::string mLink;
|
||||
bool mIsLink;
|
||||
LLUIImagePtr mImagep;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
*
|
||||
* $LicenseInfo:firstyear=2009&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
* Copyright (C) 2009-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
|
||||
|
|
@ -475,8 +475,8 @@ void LLTextBase::drawCursor()
|
|||
{
|
||||
LLColor4 text_color;
|
||||
const LLFontGL* fontp;
|
||||
text_color = segmentp->getColor();
|
||||
fontp = segmentp->getStyle()->getFont();
|
||||
text_color = segmentp->getColor();
|
||||
fontp = segmentp->getStyle()->getFont();
|
||||
fontp->render(text, mCursorPos, cursor_rect,
|
||||
LLColor4(1.f - text_color.mV[VRED], 1.f - text_color.mV[VGREEN], 1.f - text_color.mV[VBLUE], alpha),
|
||||
LLFontGL::LEFT, mVAlign,
|
||||
|
|
@ -1602,6 +1602,20 @@ std::string LLTextBase::getText() const
|
|||
return getViewModel()->getValue().asString();
|
||||
}
|
||||
|
||||
// IDEVO - icons can be UI image names or UUID sent from
|
||||
// server with avatar display name
|
||||
static LLUIImagePtr image_from_icon_name(const std::string& icon_name)
|
||||
{
|
||||
if (LLUUID::validate(icon_name))
|
||||
{
|
||||
return LLUI::getUIImageByID( LLUUID(icon_name) );
|
||||
}
|
||||
else
|
||||
{
|
||||
return LLUI::getUIImage(icon_name);
|
||||
}
|
||||
}
|
||||
|
||||
void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Params& input_params)
|
||||
{
|
||||
LLStyle::Params style_params(input_params);
|
||||
|
|
@ -1614,16 +1628,13 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para
|
|||
LLUrlMatch match;
|
||||
std::string text = new_text;
|
||||
while ( LLUrlRegistry::instance().findUrl(text, match,
|
||||
boost::bind(&LLTextBase::replaceUrlLabel, this, _1, _2)) )
|
||||
boost::bind(&LLTextBase::replaceUrl, this, _1, _2, _3)) )
|
||||
{
|
||||
start = match.getStart();
|
||||
end = match.getEnd()+1;
|
||||
|
||||
LLStyle::Params link_params = style_params;
|
||||
link_params.color = match.getColor();
|
||||
link_params.readonly_color = match.getColor();
|
||||
link_params.font.style("UNDERLINE");
|
||||
link_params.link_href = match.getUrl();
|
||||
LLStyle::Params link_params(style_params);
|
||||
link_params.overwriteFrom(match.getStyle());
|
||||
|
||||
// output the text before the Url
|
||||
if (start > 0)
|
||||
|
|
@ -1644,26 +1655,20 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para
|
|||
// inserts an avatar icon preceding the Url if appropriate
|
||||
LLTextUtil::processUrlMatch(&match,this);
|
||||
|
||||
// output the styled Url (unless we've been asked to suppress hyperlinking)
|
||||
if (match.isLinkDisabled())
|
||||
// output the styled Url
|
||||
appendAndHighlightTextImpl(match.getLabel(), part, link_params, match.underlineOnHoverOnly());
|
||||
|
||||
// set the tooltip for the Url label
|
||||
if (! match.getTooltip().empty())
|
||||
{
|
||||
appendAndHighlightText(match.getLabel(), part, style_params);
|
||||
segment_set_t::iterator it = getSegIterContaining(getLength()-1);
|
||||
if (it != mSegments.end())
|
||||
{
|
||||
LLTextSegmentPtr segment = *it;
|
||||
segment->setToolTip(match.getTooltip());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
appendAndHighlightText(match.getLabel(), part, link_params, match.underlineOnHoverOnly());
|
||||
|
||||
// set the tooltip for the Url label
|
||||
if (! match.getTooltip().empty())
|
||||
{
|
||||
segment_set_t::iterator it = getSegIterContaining(getLength()-1);
|
||||
if (it != mSegments.end())
|
||||
{
|
||||
LLTextSegmentPtr segment = *it;
|
||||
segment->setToolTip(match.getTooltip());
|
||||
}
|
||||
}
|
||||
}
|
||||
// move on to the rest of the text after the Url
|
||||
if (end < (S32)text.length())
|
||||
{
|
||||
|
|
@ -1848,8 +1853,9 @@ void LLTextBase::appendAndHighlightText(const std::string &new_text, S32 highlig
|
|||
}
|
||||
|
||||
|
||||
void LLTextBase::replaceUrlLabel(const std::string &url,
|
||||
const std::string &label)
|
||||
void LLTextBase::replaceUrl(const std::string &url,
|
||||
const std::string &label,
|
||||
const std::string &icon)
|
||||
{
|
||||
// get the full (wide) text for the editor so we can change it
|
||||
LLWString text = getWText();
|
||||
|
|
@ -1870,7 +1876,7 @@ void LLTextBase::replaceUrlLabel(const std::string &url,
|
|||
seg->setEnd(seg_start + seg_length);
|
||||
|
||||
// if we find a link with our Url, then replace the label
|
||||
if (style->isLink() && style->getLinkHREF() == url)
|
||||
if (style->getLinkHREF() == url)
|
||||
{
|
||||
S32 start = seg->getStart();
|
||||
S32 end = seg->getEnd();
|
||||
|
|
@ -1879,6 +1885,21 @@ void LLTextBase::replaceUrlLabel(const std::string &url,
|
|||
modified = true;
|
||||
}
|
||||
|
||||
// Icon might be updated when more avatar or group info
|
||||
// becomes available
|
||||
if (style->isImage() && style->getLinkHREF() == url)
|
||||
{
|
||||
LLUIImagePtr image = image_from_icon_name( icon );
|
||||
if (image)
|
||||
{
|
||||
LLStyle::Params icon_params;
|
||||
icon_params.image = image;
|
||||
LLStyleConstSP new_style(new LLStyle(icon_params));
|
||||
seg->setStyle(new_style);
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
|
||||
// work out the character offset for the next segment
|
||||
seg_start = seg->getEnd();
|
||||
}
|
||||
|
|
@ -1976,8 +1997,8 @@ S32 LLTextBase::getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round,
|
|||
else if (hit_past_end_of_line && segmentp->getEnd() > line_iter->mDocIndexEnd - 1)
|
||||
{
|
||||
// segment wraps to next line, so just set doc pos to the end of the line
|
||||
// segment wraps to next line, so just set doc pos to start of next line (represented by mDocIndexEnd)
|
||||
pos = llmin(getLength(), line_iter->mDocIndexEnd);
|
||||
// segment wraps to next line, so just set doc pos to start of next line (represented by mDocIndexEnd)
|
||||
pos = llmin(getLength(), line_iter->mDocIndexEnd);
|
||||
break;
|
||||
}
|
||||
start_x += text_width;
|
||||
|
|
|
|||
|
|
@ -235,6 +235,7 @@ class LLTextBase
|
|||
public:
|
||||
friend class LLTextSegment;
|
||||
friend class LLNormalTextSegment;
|
||||
friend class LLUICtrlFactory;
|
||||
|
||||
struct LineSpacingParams : public LLInitParam::Choice<LineSpacingParams>
|
||||
{
|
||||
|
|
@ -492,7 +493,11 @@ protected:
|
|||
// misc
|
||||
void updateRects();
|
||||
void needsScroll() { mScrollNeeded = TRUE; }
|
||||
void replaceUrlLabel(const std::string &url, const std::string &label);
|
||||
|
||||
struct URLLabelCallback;
|
||||
// Replace a URL with a new icon and label, for example, when
|
||||
// avatar names are looked up.
|
||||
void replaceUrl(const std::string &url, const std::string &label, const std::string& icon);
|
||||
|
||||
void appendTextImpl(const std::string &new_text, const LLStyle::Params& input_params = LLStyle::Params());
|
||||
void appendAndHighlightTextImpl(const std::string &new_text, S32 highlight_part, const LLStyle::Params& style_params, bool underline_on_hover_only = false);
|
||||
|
|
|
|||
|
|
@ -78,9 +78,9 @@ BOOL LLToolTipView::handleHover(S32 x, S32 y, MASK mask)
|
|||
|
||||
LLToolTipMgr& tooltip_mgr = LLToolTipMgr::instance();
|
||||
|
||||
if (x != last_x && y != last_y)
|
||||
if (x != last_x && y != last_y && !tooltip_mgr.getMouseNearRect().pointInRect(x, y))
|
||||
{
|
||||
// allow new tooltips because mouse moved
|
||||
// allow new tooltips because mouse moved outside of mouse near rect
|
||||
tooltip_mgr.unblockToolTips();
|
||||
}
|
||||
|
||||
|
|
@ -276,8 +276,8 @@ void LLToolTip::initFromParams(const LLToolTip::Params& p)
|
|||
|
||||
if (p.styled_message.isProvided())
|
||||
{
|
||||
for (LLInitParam::ParamIterator<LLToolTip::StyledText>::const_iterator text_it = p.styled_message().begin();
|
||||
text_it != p.styled_message().end();
|
||||
for (LLInitParam::ParamIterator<LLToolTip::StyledText>::const_iterator text_it = p.styled_message.begin();
|
||||
text_it != p.styled_message.end();
|
||||
++text_it)
|
||||
{
|
||||
mTextBox->appendText(text_it->text(), false, text_it->style);
|
||||
|
|
@ -580,6 +580,7 @@ void LLToolTipMgr::updateToolTipVisibility()
|
|||
if (mToolTip->getVisibleTime() > tooltip_timeout)
|
||||
{
|
||||
hideToolTips();
|
||||
unblockToolTips();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1796,7 +1796,8 @@ void LLUI::setupPaths()
|
|||
LLXMLNodePtr root;
|
||||
BOOL success = LLXMLNode::parseFile(filename, root, NULL);
|
||||
Paths paths;
|
||||
LLXUIParser::instance().readXUI(root, paths, filename);
|
||||
LLXUIParser parser;
|
||||
parser.readXUI(root, paths, filename);
|
||||
|
||||
sXUIPaths.clear();
|
||||
|
||||
|
|
@ -1805,14 +1806,14 @@ void LLUI::setupPaths()
|
|||
LLStringUtil::format_map_t path_args;
|
||||
path_args["[LANGUAGE]"] = LLUI::getLanguage();
|
||||
|
||||
for (LLInitParam::ParamIterator<Directory>::const_iterator it = paths.directories().begin(),
|
||||
end_it = paths.directories().end();
|
||||
for (LLInitParam::ParamIterator<Directory>::const_iterator it = paths.directories.begin(),
|
||||
end_it = paths.directories.end();
|
||||
it != end_it;
|
||||
++it)
|
||||
{
|
||||
std::string path_val_ui;
|
||||
for (LLInitParam::ParamIterator<SubDir>::const_iterator subdir_it = it->subdirs().begin(),
|
||||
subdir_end_it = it->subdirs().end();
|
||||
for (LLInitParam::ParamIterator<SubDir>::const_iterator subdir_it = it->subdirs.begin(),
|
||||
subdir_end_it = it->subdirs.end();
|
||||
subdir_it != subdir_end_it;)
|
||||
{
|
||||
path_val_ui += subdir_it->value();
|
||||
|
|
|
|||
|
|
@ -56,8 +56,8 @@ void LLUIColorTable::insertFromParams(const Params& p, string_color_map_t& table
|
|||
typedef std::map<std::string, std::string> string_string_map_t;
|
||||
string_string_map_t unresolved_refs;
|
||||
|
||||
for(LLInitParam::ParamIterator<ColorEntryParams>::const_iterator it = p.color_entries().begin();
|
||||
it != p.color_entries().end();
|
||||
for(LLInitParam::ParamIterator<ColorEntryParams>::const_iterator it = p.color_entries.begin();
|
||||
it != p.color_entries.end();
|
||||
++it)
|
||||
{
|
||||
ColorEntryParams color_entry = *it;
|
||||
|
|
@ -237,7 +237,8 @@ void LLUIColorTable::saveUserSettings() const
|
|||
}
|
||||
|
||||
LLXMLNodePtr output_node = new LLXMLNode("colors", false);
|
||||
LLXUIParser::instance().writeXUI(output_node, params);
|
||||
LLXUIParser parser;
|
||||
parser.writeXUI(output_node, params);
|
||||
|
||||
if(!output_node->isNull())
|
||||
{
|
||||
|
|
@ -303,7 +304,8 @@ bool LLUIColorTable::loadFromFilename(const std::string& filename, string_color_
|
|||
}
|
||||
|
||||
Params params;
|
||||
LLXUIParser::instance().readXUI(root, params, filename);
|
||||
LLXUIParser parser;
|
||||
parser.readXUI(root, params, filename);
|
||||
|
||||
if(params.validateBlock())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@
|
|||
#include "llquaternion.h"
|
||||
|
||||
// this library includes
|
||||
#include "llfloater.h"
|
||||
#include "llpanel.h"
|
||||
|
||||
LLFastTimer::DeclareTimer FTM_WIDGET_CONSTRUCTION("Widget Construction");
|
||||
LLFastTimer::DeclareTimer FTM_INIT_FROM_PARAMS("Widget InitFromParams");
|
||||
|
|
@ -93,10 +93,12 @@ void LLUICtrlFactory::loadWidgetTemplate(const std::string& widget_tag, LLInitPa
|
|||
std::string filename = std::string("widgets") + gDirUtilp->getDirDelimiter() + widget_tag + ".xml";
|
||||
LLXMLNodePtr root_node;
|
||||
|
||||
if (LLUICtrlFactory::getLayeredXMLNode(filename, root_node))
|
||||
std::string full_filename = gDirUtilp->findSkinnedFilename(LLUI::getXUIPaths().front(), filename);
|
||||
if (!full_filename.empty())
|
||||
{
|
||||
LLUICtrlFactory::instance().pushFileName(filename);
|
||||
LLXUIParser::instance().readXUI(root_node, block, filename);
|
||||
LLUICtrlFactory::instance().pushFileName(full_filename);
|
||||
LLSimpleXUIParser parser;
|
||||
parser.readXUI(full_filename, block);
|
||||
LLUICtrlFactory::instance().popFileName();
|
||||
}
|
||||
}
|
||||
|
|
@ -171,70 +173,6 @@ bool LLUICtrlFactory::getLocalizedXMLNode(const std::string &xui_filename, LLXML
|
|||
}
|
||||
}
|
||||
|
||||
static LLFastTimer::DeclareTimer FTM_BUILD_FLOATERS("Build Floaters");
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// buildFloater()
|
||||
//-----------------------------------------------------------------------------
|
||||
bool LLUICtrlFactory::buildFloater(LLFloater* floaterp, const std::string& filename, LLXMLNodePtr output_node)
|
||||
{
|
||||
LLFastTimer timer(FTM_BUILD_FLOATERS);
|
||||
LLXMLNodePtr root;
|
||||
|
||||
//if exporting, only load the language being exported,
|
||||
//instead of layering localized version on top of english
|
||||
if (output_node)
|
||||
{
|
||||
if (!LLUICtrlFactory::getLocalizedXMLNode(filename, root))
|
||||
{
|
||||
llwarns << "Couldn't parse floater from: " << LLUI::getLocalizedSkinPath() + gDirUtilp->getDirDelimiter() + filename << llendl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (!LLUICtrlFactory::getLayeredXMLNode(filename, root))
|
||||
{
|
||||
llwarns << "Couldn't parse floater from: " << LLUI::getSkinPath() + gDirUtilp->getDirDelimiter() + filename << llendl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// root must be called floater
|
||||
if( !(root->hasName("floater") || root->hasName("multi_floater")) )
|
||||
{
|
||||
llwarns << "Root node should be named floater in: " << filename << llendl;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool res = true;
|
||||
|
||||
lldebugs << "Building floater " << filename << llendl;
|
||||
pushFileName(filename);
|
||||
{
|
||||
if (!floaterp->getFactoryMap().empty())
|
||||
{
|
||||
mFactoryStack.push_front(&floaterp->getFactoryMap());
|
||||
}
|
||||
|
||||
// for local registry callbacks; define in constructor, referenced in XUI or postBuild
|
||||
floaterp->getCommitCallbackRegistrar().pushScope();
|
||||
floaterp->getEnableCallbackRegistrar().pushScope();
|
||||
|
||||
res = floaterp->initFloaterXML(root, floaterp->getParent(), filename, output_node);
|
||||
|
||||
floaterp->setXMLFilename(filename);
|
||||
|
||||
floaterp->getCommitCallbackRegistrar().popScope();
|
||||
floaterp->getEnableCallbackRegistrar().popScope();
|
||||
|
||||
if (!floaterp->getFactoryMap().empty())
|
||||
{
|
||||
mFactoryStack.pop_front();
|
||||
}
|
||||
}
|
||||
popFileName();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// saveToXML()
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
@ -243,69 +181,6 @@ S32 LLUICtrlFactory::saveToXML(LLView* viewp, const std::string& filename)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static LLFastTimer::DeclareTimer FTM_BUILD_PANELS("Build Panels");
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// buildPanel()
|
||||
//-----------------------------------------------------------------------------
|
||||
BOOL LLUICtrlFactory::buildPanel(LLPanel* panelp, const std::string& filename, LLXMLNodePtr output_node)
|
||||
{
|
||||
LLFastTimer timer(FTM_BUILD_PANELS);
|
||||
BOOL didPost = FALSE;
|
||||
LLXMLNodePtr root;
|
||||
|
||||
//if exporting, only load the language being exported,
|
||||
//instead of layering localized version on top of english
|
||||
if (output_node)
|
||||
{
|
||||
if (!LLUICtrlFactory::getLocalizedXMLNode(filename, root))
|
||||
{
|
||||
llwarns << "Couldn't parse panel from: " << LLUI::getLocalizedSkinPath() + gDirUtilp->getDirDelimiter() + filename << llendl;
|
||||
return didPost;
|
||||
}
|
||||
}
|
||||
else if (!LLUICtrlFactory::getLayeredXMLNode(filename, root))
|
||||
{
|
||||
llwarns << "Couldn't parse panel from: " << LLUI::getSkinPath() + gDirUtilp->getDirDelimiter() + filename << llendl;
|
||||
return didPost;
|
||||
}
|
||||
|
||||
// root must be called panel
|
||||
if( !root->hasName("panel" ) )
|
||||
{
|
||||
llwarns << "Root node should be named panel in : " << filename << llendl;
|
||||
return didPost;
|
||||
}
|
||||
|
||||
lldebugs << "Building panel " << filename << llendl;
|
||||
|
||||
pushFileName(filename);
|
||||
{
|
||||
if (!panelp->getFactoryMap().empty())
|
||||
{
|
||||
mFactoryStack.push_front(&panelp->getFactoryMap());
|
||||
}
|
||||
|
||||
// for local registry callbacks; define in constructor, referenced in XUI or postBuild
|
||||
panelp->getCommitCallbackRegistrar().pushScope();
|
||||
panelp->getEnableCallbackRegistrar().pushScope();
|
||||
|
||||
didPost = panelp->initPanelXML(root, NULL, output_node);
|
||||
|
||||
panelp->getCommitCallbackRegistrar().popScope();
|
||||
panelp->getEnableCallbackRegistrar().popScope();
|
||||
|
||||
panelp->setXMLFilename(filename);
|
||||
|
||||
if (!panelp->getFactoryMap().empty())
|
||||
{
|
||||
mFactoryStack.pop_front();
|
||||
}
|
||||
}
|
||||
popFileName();
|
||||
return didPost;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
|
@ -337,29 +212,6 @@ LLView *LLUICtrlFactory::createFromXML(LLXMLNodePtr node, LLView* parent, const
|
|||
return view;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// createFactoryPanel()
|
||||
//-----------------------------------------------------------------------------
|
||||
LLPanel* LLUICtrlFactory::createFactoryPanel(const std::string& name)
|
||||
{
|
||||
std::deque<const LLCallbackMap::map_t*>::iterator itor;
|
||||
for (itor = mFactoryStack.begin(); itor != mFactoryStack.end(); ++itor)
|
||||
{
|
||||
const LLCallbackMap::map_t* factory_map = *itor;
|
||||
|
||||
// Look up this panel's name in the map.
|
||||
LLCallbackMap::map_const_iter_t iter = factory_map->find( name );
|
||||
if (iter != factory_map->end())
|
||||
{
|
||||
// Use the factory to create the panel, instead of using a default LLPanel.
|
||||
LLPanel *ret = (LLPanel*) iter->second.mCallback( iter->second.mData );
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
LLPanel::Params panel_p;
|
||||
return create<LLPanel>(panel_p);
|
||||
}
|
||||
|
||||
std::string LLUICtrlFactory::getCurFileName()
|
||||
{
|
||||
return mFileNames.empty() ? "" : gDirUtilp->getWorkingDir() + gDirUtilp->getDirDelimiter() + mFileNames.back();
|
||||
|
|
@ -376,36 +228,6 @@ void LLUICtrlFactory::popFileName()
|
|||
mFileNames.pop_back();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//static
|
||||
BOOL LLUICtrlFactory::getAttributeColor(LLXMLNodePtr node, const std::string& name, LLColor4& color)
|
||||
{
|
||||
std::string colorstring;
|
||||
BOOL res = node->getAttributeString(name.c_str(), colorstring);
|
||||
if (res)
|
||||
{
|
||||
if (LLUIColorTable::instance().colorExists(colorstring))
|
||||
{
|
||||
color.setVec(LLUIColorTable::instance().getColor(colorstring));
|
||||
}
|
||||
else
|
||||
{
|
||||
res = FALSE;
|
||||
}
|
||||
}
|
||||
if (!res)
|
||||
{
|
||||
res = LLColor4::parseColor(colorstring, &color);
|
||||
}
|
||||
if (!res)
|
||||
{
|
||||
res = node->getAttributeColor(name.c_str(), color);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
//static
|
||||
void LLUICtrlFactory::setCtrlParent(LLView* view, LLView* parent, S32 tab_group)
|
||||
{
|
||||
|
|
@ -421,28 +243,22 @@ std::string LLUICtrlFactory::findSkinnedFilename(const std::string& filename)
|
|||
return gDirUtilp->findSkinnedFilename(LLUI::getSkinPath(), filename);
|
||||
}
|
||||
|
||||
void LLUICtrlFactory::pushFactoryFunctions(const LLCallbackMap::map_t* map)
|
||||
{
|
||||
mFactoryStack.push_back(map);
|
||||
}
|
||||
|
||||
void LLUICtrlFactory::popFactoryFunctions()
|
||||
{
|
||||
if (!mFactoryStack.empty())
|
||||
{
|
||||
mFactoryStack.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
void LLUICtrlFactory::copyName(LLXMLNodePtr src, LLXMLNodePtr dest)
|
||||
{
|
||||
dest->setName(src->getName()->mString);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const LLInitParam::BaseBlock& get_empty_param_block()
|
||||
{
|
||||
static typename T::Params params;
|
||||
return params;
|
||||
}
|
||||
|
||||
// adds a widget and its param block to various registries
|
||||
//static
|
||||
void LLUICtrlFactory::registerWidget(const std::type_info* widget_type, const std::type_info* param_block_type, dummy_widget_creator_func_t creator_func, const std::string& tag)
|
||||
void LLUICtrlFactory::registerWidget(const std::type_info* widget_type, const std::type_info* param_block_type, const std::string& tag)
|
||||
{
|
||||
// associate parameter block type with template .xml file
|
||||
std::string* existing_tag = LLWidgetNameRegistry::instance().getValue(param_block_type);
|
||||
|
|
@ -462,17 +278,9 @@ void LLUICtrlFactory::registerWidget(const std::type_info* widget_type, const st
|
|||
}
|
||||
}
|
||||
LLWidgetNameRegistry::instance().defaultRegistrar().add(param_block_type, tag);
|
||||
// associate widget type with factory function
|
||||
LLDefaultWidgetRegistry::instance().defaultRegistrar().add(widget_type, creator_func);
|
||||
//FIXME: comment this in when working on schema generation
|
||||
//LLWidgetTypeRegistry::instance().defaultRegistrar().add(tag, widget_type);
|
||||
//LLDefaultParamBlockRegistry::instance().defaultRegistrar().add(widget_type, &getEmptyParamBlock<T>);
|
||||
}
|
||||
|
||||
//static
|
||||
dummy_widget_creator_func_t* LLUICtrlFactory::getDefaultWidgetFunc(const std::type_info* widget_type)
|
||||
{
|
||||
return LLDefaultWidgetRegistry::instance().getValue(widget_type);
|
||||
//LLDefaultParamBlockRegistry::instance().defaultRegistrar().add(widget_type, &get_empty_param_block<T>);
|
||||
}
|
||||
|
||||
//static
|
||||
|
|
|
|||
|
|
@ -27,24 +27,13 @@
|
|||
#ifndef LLUICTRLFACTORY_H
|
||||
#define LLUICTRLFACTORY_H
|
||||
|
||||
#include "llcallbackmap.h"
|
||||
#include "llfasttimer.h"
|
||||
#include "llinitparam.h"
|
||||
#include "llregistry.h"
|
||||
#include "v4color.h"
|
||||
#include "llfasttimer.h"
|
||||
|
||||
#include "llxuiparser.h"
|
||||
|
||||
#include <boost/function.hpp>
|
||||
#include <iosfwd>
|
||||
#include <stack>
|
||||
#include <set>
|
||||
|
||||
class LLPanel;
|
||||
class LLFloater;
|
||||
class LLView;
|
||||
|
||||
|
||||
// sort functor for typeid maps
|
||||
struct LLCompareTypeID
|
||||
{
|
||||
|
|
@ -85,12 +74,6 @@ class LLWidgetNameRegistry
|
|||
: public LLRegistrySingleton<const std::type_info*, std::string, LLWidgetNameRegistry , LLCompareTypeID>
|
||||
{};
|
||||
|
||||
// lookup factory functions for default widget instances by widget type
|
||||
typedef LLView* (*dummy_widget_creator_func_t)(const std::string&);
|
||||
class LLDefaultWidgetRegistry
|
||||
: public LLRegistrySingleton<const std::type_info*, dummy_widget_creator_func_t, LLDefaultWidgetRegistry, LLCompareTypeID>
|
||||
{};
|
||||
|
||||
// lookup function for generating empty param block by widget type
|
||||
// this is used for schema generation
|
||||
//typedef const LLInitParam::BaseBlock& (*empty_param_block_func_t)();
|
||||
|
|
@ -157,58 +140,21 @@ public:
|
|||
return ParamDefaults<typename T::Params, 0>::instance().get();
|
||||
}
|
||||
|
||||
bool buildFloater(LLFloater* floaterp, const std::string &filename, LLXMLNodePtr output_node);
|
||||
BOOL buildPanel(LLPanel* panelp, const std::string &filename, LLXMLNodePtr output_node = NULL);
|
||||
|
||||
// Does what you want for LLFloaters and LLPanels
|
||||
// Returns 0 on success
|
||||
S32 saveToXML(LLView* viewp, const std::string& filename);
|
||||
|
||||
// filename tracking for debugging info
|
||||
std::string getCurFileName();
|
||||
void pushFileName(const std::string& name);
|
||||
void popFileName();
|
||||
|
||||
static BOOL getAttributeColor(LLXMLNodePtr node, const std::string& name, LLColor4& color);
|
||||
|
||||
LLPanel* createFactoryPanel(const std::string& name);
|
||||
|
||||
void pushFactoryFunctions(const LLCallbackMap::map_t* map);
|
||||
void popFactoryFunctions();
|
||||
|
||||
template<typename T>
|
||||
static T* createWidget(const typename T::Params& params, LLView* parent = NULL)
|
||||
{
|
||||
T* widget = NULL;
|
||||
|
||||
if (!params.validateBlock())
|
||||
{
|
||||
llwarns << getInstance()->getCurFileName() << ": Invalid parameter block for " << typeid(T).name() << llendl;
|
||||
//return NULL;
|
||||
}
|
||||
|
||||
{
|
||||
LLFastTimer timer(FTM_WIDGET_CONSTRUCTION);
|
||||
widget = new T(params);
|
||||
}
|
||||
{
|
||||
LLFastTimer timer(FTM_INIT_FROM_PARAMS);
|
||||
widget->initFromParams(params);
|
||||
}
|
||||
|
||||
if (parent)
|
||||
{
|
||||
S32 tab_group = params.tab_group.isProvided() ? params.tab_group() : S32_MAX;
|
||||
setCtrlParent(widget, parent, tab_group);
|
||||
}
|
||||
return widget;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static T* create(typename T::Params& params, LLView* parent = NULL)
|
||||
{
|
||||
params.fillFrom(ParamDefaults<typename T::Params, 0>::instance().get());
|
||||
|
||||
T* widget = createWidget<T>(params, parent);
|
||||
T* widget = createWidgetImpl<T>(params, parent);
|
||||
if (widget)
|
||||
{
|
||||
widget->postBuild();
|
||||
|
|
@ -266,21 +212,54 @@ fail:
|
|||
template<class T>
|
||||
static T* getDefaultWidget(const std::string& name)
|
||||
{
|
||||
dummy_widget_creator_func_t* dummy_func = getDefaultWidgetFunc(&typeid(T));
|
||||
return dummy_func ? dynamic_cast<T*>((*dummy_func)(name)) : NULL;
|
||||
typename T::Params widget_params;
|
||||
widget_params.name = name;
|
||||
return create<T>(widget_params);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static LLView* createDefaultWidget(const std::string& name)
|
||||
{
|
||||
typename T::Params params;
|
||||
params.name(name);
|
||||
|
||||
return create<T>(params);
|
||||
}
|
||||
static void createChildren(LLView* viewp, LLXMLNodePtr node, const widget_registry_t&, LLXMLNodePtr output_node = NULL);
|
||||
|
||||
static bool getLayeredXMLNode(const std::string &filename, LLXMLNodePtr& root);
|
||||
static bool getLocalizedXMLNode(const std::string &xui_filename, LLXMLNodePtr& root);
|
||||
|
||||
private:
|
||||
//NOTE: both friend declarations are necessary to keep both gcc and msvc happy
|
||||
template <typename T> friend class LLChildRegistry;
|
||||
template <typename T> template <typename U> friend class LLChildRegistry<T>::Register;
|
||||
|
||||
static void copyName(LLXMLNodePtr src, LLXMLNodePtr dest);
|
||||
|
||||
// helper function for adding widget type info to various registries
|
||||
static void registerWidget(const std::type_info* widget_type, const std::type_info* param_block_type, const std::string& tag);
|
||||
|
||||
static void loadWidgetTemplate(const std::string& widget_tag, LLInitParam::BaseBlock& block);
|
||||
|
||||
template<typename T>
|
||||
static T* createWidgetImpl(const typename T::Params& params, LLView* parent = NULL)
|
||||
{
|
||||
T* widget = NULL;
|
||||
|
||||
if (!params.validateBlock())
|
||||
{
|
||||
llwarns << getInstance()->getCurFileName() << ": Invalid parameter block for " << typeid(T).name() << llendl;
|
||||
//return NULL;
|
||||
}
|
||||
|
||||
{ LLFastTimer _(FTM_WIDGET_CONSTRUCTION);
|
||||
widget = new T(params);
|
||||
}
|
||||
{ LLFastTimer _(FTM_INIT_FROM_PARAMS);
|
||||
widget->initFromParams(params);
|
||||
}
|
||||
|
||||
if (parent)
|
||||
{
|
||||
S32 tab_group = params.tab_group.isProvided() ? params.tab_group() : S32_MAX;
|
||||
setCtrlParent(widget, parent, tab_group);
|
||||
}
|
||||
return widget;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static T* defaultBuilder(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node)
|
||||
{
|
||||
|
|
@ -288,7 +267,8 @@ fail:
|
|||
|
||||
typename T::Params params(getDefaultParams<T>());
|
||||
|
||||
LLXUIParser::instance().readXUI(node, params, LLUICtrlFactory::getInstance()->getCurFileName());
|
||||
LLXUIParser parser;
|
||||
parser.readXUI(node, params, LLUICtrlFactory::getInstance()->getCurFileName());
|
||||
|
||||
if (output_node)
|
||||
{
|
||||
|
|
@ -298,14 +278,13 @@ fail:
|
|||
// Export only the differences between this any default params
|
||||
typename T::Params default_params(getDefaultParams<T>());
|
||||
copyName(node, output_node);
|
||||
LLXUIParser::instance().writeXUI(
|
||||
output_node, output_params, &default_params);
|
||||
parser.writeXUI(output_node, output_params, &default_params);
|
||||
}
|
||||
|
||||
// Apply layout transformations, usually munging rect
|
||||
params.from_xui = true;
|
||||
T::applyXUILayout(params, parent);
|
||||
T* widget = createWidget<T>(params, parent);
|
||||
T* widget = createWidgetImpl<T>(params, parent);
|
||||
|
||||
typedef typename T::child_registry_t registry_t;
|
||||
|
||||
|
|
@ -320,20 +299,6 @@ fail:
|
|||
return widget;
|
||||
}
|
||||
|
||||
static void createChildren(LLView* viewp, LLXMLNodePtr node, const widget_registry_t&, LLXMLNodePtr output_node = NULL);
|
||||
|
||||
static bool getLayeredXMLNode(const std::string &filename, LLXMLNodePtr& root);
|
||||
|
||||
static bool getLocalizedXMLNode(const std::string &xui_filename, LLXMLNodePtr& root);
|
||||
|
||||
static void loadWidgetTemplate(const std::string& widget_tag, LLInitParam::BaseBlock& block);
|
||||
|
||||
// helper function for adding widget type info to various registries
|
||||
static void registerWidget(const std::type_info* widget_type, const std::type_info* param_block_type, dummy_widget_creator_func_t creator_func, const std::string& tag);
|
||||
|
||||
private:
|
||||
// return default widget instance factory func for a given type
|
||||
static dummy_widget_creator_func_t* getDefaultWidgetFunc(const std::type_info* widget_type);
|
||||
|
||||
static const std::string* getWidgetTag(const std::type_info* widget_type);
|
||||
|
||||
|
|
@ -343,20 +308,10 @@ private:
|
|||
// Avoid directly using LLUI and LLDir in the template code
|
||||
static std::string findSkinnedFilename(const std::string& filename);
|
||||
|
||||
typedef std::deque<const LLCallbackMap::map_t*> factory_stack_t;
|
||||
factory_stack_t mFactoryStack;
|
||||
|
||||
LLPanel* mDummyPanel;
|
||||
class LLPanel* mDummyPanel;
|
||||
std::vector<std::string> mFileNames;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
const LLInitParam::BaseBlock& getEmptyParamBlock()
|
||||
{
|
||||
static typename T::Params params;
|
||||
return params;
|
||||
}
|
||||
|
||||
// this is here to make gcc happy with reference to LLUICtrlFactory
|
||||
template<typename DERIVED>
|
||||
template<typename T>
|
||||
|
|
@ -364,7 +319,7 @@ LLChildRegistry<DERIVED>::Register<T>::Register(const char* tag, LLWidgetCreator
|
|||
: LLChildRegistry<DERIVED>::StaticRegistrar(tag, func.empty() ? (LLWidgetCreatorFunc)&LLUICtrlFactory::defaultBuilder<T> : func)
|
||||
{
|
||||
// add this widget to various registries
|
||||
LLUICtrlFactory::instance().registerWidget(&typeid(T), &typeid(typename T::Params), &LLUICtrlFactory::createDefaultWidget<T>, tag);
|
||||
LLUICtrlFactory::instance().registerWidget(&typeid(T), &typeid(typename T::Params), tag);
|
||||
|
||||
// since registry_t depends on T, do this in line here
|
||||
// TODO: uncomment this for schema generation
|
||||
|
|
@ -372,58 +327,4 @@ LLChildRegistry<DERIVED>::Register<T>::Register(const char* tag, LLWidgetCreator
|
|||
//LLChildRegistryRegistry::instance().defaultRegistrar().add(&typeid(T), registry_t::instance());
|
||||
}
|
||||
|
||||
|
||||
typedef boost::function<LLPanel* (void)> LLPanelClassCreatorFunc;
|
||||
|
||||
// local static instance for registering a particular panel class
|
||||
|
||||
class LLRegisterPanelClass
|
||||
: public LLSingleton< LLRegisterPanelClass >
|
||||
{
|
||||
public:
|
||||
// reigister with either the provided builder, or the generic templated builder
|
||||
void addPanelClass(const std::string& tag,LLPanelClassCreatorFunc func)
|
||||
{
|
||||
mPanelClassesNames[tag] = func;
|
||||
}
|
||||
|
||||
LLPanel* createPanelClass(const std::string& tag)
|
||||
{
|
||||
param_name_map_t::iterator iT = mPanelClassesNames.find(tag);
|
||||
if(iT == mPanelClassesNames.end())
|
||||
return 0;
|
||||
return iT->second();
|
||||
}
|
||||
template<typename T>
|
||||
static T* defaultPanelClassBuilder()
|
||||
{
|
||||
T* pT = new T();
|
||||
return pT;
|
||||
}
|
||||
|
||||
private:
|
||||
typedef std::map< std::string, LLPanelClassCreatorFunc> param_name_map_t;
|
||||
|
||||
param_name_map_t mPanelClassesNames;
|
||||
};
|
||||
|
||||
|
||||
// local static instance for registering a particular panel class
|
||||
template<typename T>
|
||||
class LLRegisterPanelClassWrapper
|
||||
: public LLRegisterPanelClass
|
||||
{
|
||||
public:
|
||||
// reigister with either the provided builder, or the generic templated builder
|
||||
LLRegisterPanelClassWrapper(const std::string& tag);
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
LLRegisterPanelClassWrapper<T>::LLRegisterPanelClassWrapper(const std::string& tag)
|
||||
{
|
||||
LLRegisterPanelClass::instance().addPanelClass(tag,&LLRegisterPanelClass::defaultPanelClassBuilder<T>);
|
||||
}
|
||||
|
||||
|
||||
#endif //LLUICTRLFACTORY_H
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ LLFastTimer::DeclareTimer FTM_UI_STRING("UI String");
|
|||
|
||||
LLUIString::LLUIString(const std::string& instring, const LLStringUtil::format_map_t& args)
|
||||
: mOrig(instring),
|
||||
mArgs(args)
|
||||
mArgs(new LLStringUtil::format_map_t(args))
|
||||
{
|
||||
dirty();
|
||||
}
|
||||
|
|
@ -48,7 +48,7 @@ void LLUIString::assign(const std::string& s)
|
|||
void LLUIString::setArgList(const LLStringUtil::format_map_t& args)
|
||||
|
||||
{
|
||||
mArgs = args;
|
||||
getArgs() = args;
|
||||
dirty();
|
||||
}
|
||||
|
||||
|
|
@ -68,7 +68,7 @@ void LLUIString::setArgs(const LLSD& sd)
|
|||
|
||||
void LLUIString::setArg(const std::string& key, const std::string& replacement)
|
||||
{
|
||||
mArgs[key] = replacement;
|
||||
getArgs()[key] = replacement;
|
||||
dirty();
|
||||
}
|
||||
|
||||
|
|
@ -129,14 +129,14 @@ void LLUIString::updateResult() const
|
|||
mResult = mOrig;
|
||||
|
||||
// get the defailt args + local args
|
||||
if (mArgs.empty())
|
||||
if (!mArgs || mArgs->empty())
|
||||
{
|
||||
LLStringUtil::format(mResult, LLTrans::getDefaultArgs());
|
||||
}
|
||||
else
|
||||
{
|
||||
LLStringUtil::format_map_t combined_args = LLTrans::getDefaultArgs();
|
||||
combined_args.insert(mArgs.begin(), mArgs.end());
|
||||
combined_args.insert(mArgs->begin(), mArgs->end());
|
||||
LLStringUtil::format(mResult, combined_args);
|
||||
}
|
||||
}
|
||||
|
|
@ -147,3 +147,12 @@ void LLUIString::updateWResult() const
|
|||
|
||||
mWResult = utf8str_to_wstring(getUpdatedResult());
|
||||
}
|
||||
|
||||
LLStringUtil::format_map_t& LLUIString::getArgs()
|
||||
{
|
||||
if (!mArgs)
|
||||
{
|
||||
mArgs = new LLStringUtil::format_map_t;
|
||||
}
|
||||
return *mArgs;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,9 +58,9 @@ class LLUIString
|
|||
public:
|
||||
// These methods all perform appropriate argument substitution
|
||||
// and modify mOrig where appropriate
|
||||
LLUIString() : mNeedsResult(false), mNeedsWResult(false) {}
|
||||
LLUIString() : mArgs(NULL), mNeedsResult(false), mNeedsWResult(false) {}
|
||||
LLUIString(const std::string& instring, const LLStringUtil::format_map_t& args);
|
||||
LLUIString(const std::string& instring) { assign(instring); }
|
||||
LLUIString(const std::string& instring) : mArgs(NULL) { assign(instring); }
|
||||
|
||||
void assign(const std::string& instring);
|
||||
LLUIString& operator=(const std::string& s) { assign(s); return *this; }
|
||||
|
|
@ -80,7 +80,7 @@ public:
|
|||
S32 length() const { return getUpdatedWResult().size(); }
|
||||
|
||||
void clear();
|
||||
void clearArgs() { mArgs.clear(); }
|
||||
void clearArgs() { if (mArgs) mArgs->clear(); }
|
||||
|
||||
// These utility functions are included for text editing.
|
||||
// They do not affect mOrig and do not perform argument substitution
|
||||
|
|
@ -99,11 +99,12 @@ private:
|
|||
// do actual work of updating strings (non-inlined)
|
||||
void updateResult() const;
|
||||
void updateWResult() const;
|
||||
LLStringUtil::format_map_t& getArgs();
|
||||
|
||||
std::string mOrig;
|
||||
mutable std::string mResult;
|
||||
mutable LLWString mWResult; // for displaying
|
||||
LLStringUtil::format_map_t mArgs;
|
||||
LLStringUtil::format_map_t* mArgs;
|
||||
|
||||
// controls lazy evaluation
|
||||
mutable bool mNeedsResult;
|
||||
|
|
|
|||
|
|
@ -31,18 +31,19 @@
|
|||
#include "llurlmatch.h"
|
||||
#include "llurlregistry.h"
|
||||
|
||||
#include "llavatarnamecache.h"
|
||||
#include "llcachename.h"
|
||||
#include "lltrans.h"
|
||||
#include "lluicolortable.h"
|
||||
|
||||
#define APP_HEADER_REGEX "((x-grid-location-info://[-\\w\\.]+/app)|(secondlife:///app))"
|
||||
|
||||
// Utility functions
|
||||
std::string localize_slapp_label(const std::string& url, const std::string& full_name);
|
||||
|
||||
LLUrlEntryBase::LLUrlEntryBase() :
|
||||
mColor(LLUIColorTable::instance().getColor("HTMLLinkColor")),
|
||||
mDisabledLink(false)
|
||||
{
|
||||
}
|
||||
|
||||
LLUrlEntryBase::LLUrlEntryBase()
|
||||
{}
|
||||
|
||||
LLUrlEntryBase::~LLUrlEntryBase()
|
||||
{
|
||||
|
|
@ -53,6 +54,22 @@ std::string LLUrlEntryBase::getUrl(const std::string &string) const
|
|||
return escapeUrl(string);
|
||||
}
|
||||
|
||||
//virtual
|
||||
std::string LLUrlEntryBase::getIcon(const std::string &url)
|
||||
{
|
||||
return mIcon;
|
||||
}
|
||||
|
||||
LLStyle::Params LLUrlEntryBase::getStyle() const
|
||||
{
|
||||
LLStyle::Params style_params;
|
||||
style_params.color = LLUIColorTable::instance().getColor("HTMLLinkColor");
|
||||
style_params.readonly_color = LLUIColorTable::instance().getColor("HTMLLinkColor");
|
||||
style_params.font.style = "UNDERLINE";
|
||||
return style_params;
|
||||
}
|
||||
|
||||
|
||||
std::string LLUrlEntryBase::getIDStringFromUrl(const std::string &url) const
|
||||
{
|
||||
// return the id from a SLURL in the format /app/{cmd}/{id}/about
|
||||
|
|
@ -130,16 +147,20 @@ void LLUrlEntryBase::addObserver(const std::string &id,
|
|||
mObservers.insert(std::pair<std::string, LLUrlEntryObserver>(id, observer));
|
||||
}
|
||||
}
|
||||
|
||||
void LLUrlEntryBase::callObservers(const std::string &id, const std::string &label)
|
||||
|
||||
// *NOTE: See also LLUrlEntryAgent::callObservers()
|
||||
void LLUrlEntryBase::callObservers(const std::string &id,
|
||||
const std::string &label,
|
||||
const std::string &icon)
|
||||
{
|
||||
// notify all callbacks waiting on the given uuid
|
||||
std::multimap<std::string, LLUrlEntryObserver>::iterator it;
|
||||
for (it = mObservers.find(id); it != mObservers.end();)
|
||||
typedef std::multimap<std::string, LLUrlEntryObserver>::iterator observer_it;
|
||||
std::pair<observer_it, observer_it> matching_range = mObservers.equal_range(id);
|
||||
for (observer_it it = matching_range.first; it != matching_range.second;)
|
||||
{
|
||||
// call the callback - give it the new label
|
||||
LLUrlEntryObserver &observer = it->second;
|
||||
(*observer.signal)(it->second.url, label);
|
||||
(*observer.signal)(it->second.url, label, icon);
|
||||
// then remove the signal - we only need to call it once
|
||||
delete observer.signal;
|
||||
mObservers.erase(it++);
|
||||
|
|
@ -188,7 +209,13 @@ LLUrlEntryHTTPLabel::LLUrlEntryHTTPLabel()
|
|||
|
||||
std::string LLUrlEntryHTTPLabel::getLabel(const std::string &url, const LLUrlLabelCallback &cb)
|
||||
{
|
||||
return getLabelFromWikiLink(url);
|
||||
std::string label = getLabelFromWikiLink(url);
|
||||
return (!LLUrlRegistry::instance().hasUrl(label)) ? label : getUrl(url);
|
||||
}
|
||||
|
||||
std::string LLUrlEntryHTTPLabel::getTooltip(const std::string &string) const
|
||||
{
|
||||
return getUrl(string);
|
||||
}
|
||||
|
||||
std::string LLUrlEntryHTTPLabel::getUrl(const std::string &string) const
|
||||
|
|
@ -308,16 +335,35 @@ LLUrlEntryAgent::LLUrlEntryAgent()
|
|||
boost::regex::perl|boost::regex::icase);
|
||||
mMenuName = "menu_url_agent.xml";
|
||||
mIcon = "Generic_Person";
|
||||
mColor = LLUIColorTable::instance().getColor("AgentLinkColor");
|
||||
}
|
||||
|
||||
void LLUrlEntryAgent::onAgentNameReceived(const LLUUID& id,
|
||||
const std::string& first,
|
||||
const std::string& last,
|
||||
BOOL is_group)
|
||||
// virtual
|
||||
void LLUrlEntryAgent::callObservers(const std::string &id,
|
||||
const std::string &label,
|
||||
const std::string &icon)
|
||||
{
|
||||
// notify all callbacks waiting on the given uuid
|
||||
typedef std::multimap<std::string, LLUrlEntryObserver>::iterator observer_it;
|
||||
std::pair<observer_it, observer_it> matching_range = mObservers.equal_range(id);
|
||||
for (observer_it it = matching_range.first; it != matching_range.second;)
|
||||
{
|
||||
// call the callback - give it the new label
|
||||
LLUrlEntryObserver &observer = it->second;
|
||||
std::string final_label = localize_slapp_label(observer.url, label);
|
||||
(*observer.signal)(observer.url, final_label, icon);
|
||||
// then remove the signal - we only need to call it once
|
||||
delete observer.signal;
|
||||
mObservers.erase(it++);
|
||||
}
|
||||
}
|
||||
|
||||
void LLUrlEntryAgent::onAvatarNameCache(const LLUUID& id,
|
||||
const LLAvatarName& av_name)
|
||||
{
|
||||
std::string label = av_name.getCompleteName();
|
||||
|
||||
// received the agent name from the server - tell our observers
|
||||
callObservers(id.asString(), first + " " + last);
|
||||
callObservers(id.asString(), label, mIcon);
|
||||
}
|
||||
|
||||
LLUUID LLUrlEntryAgent::getID(const std::string &string) const
|
||||
|
|
@ -330,6 +376,10 @@ std::string LLUrlEntryAgent::getTooltip(const std::string &string) const
|
|||
// return a tooltip corresponding to the URL type instead of the generic one
|
||||
std::string url = getUrl(string);
|
||||
|
||||
if (LLStringUtil::endsWith(url, "/inspect"))
|
||||
{
|
||||
return LLTrans::getString("TooltipAgentInspect");
|
||||
}
|
||||
if (LLStringUtil::endsWith(url, "/mute"))
|
||||
{
|
||||
return LLTrans::getString("TooltipAgentMute");
|
||||
|
|
@ -379,50 +429,182 @@ std::string LLUrlEntryAgent::getLabel(const std::string &url, const LLUrlLabelCa
|
|||
}
|
||||
|
||||
LLUUID agent_id(agent_id_string);
|
||||
std::string full_name;
|
||||
if (agent_id.isNull())
|
||||
{
|
||||
return LLTrans::getString("AvatarNameNobody");
|
||||
}
|
||||
else if (gCacheName->getFullName(agent_id, full_name))
|
||||
|
||||
LLAvatarName av_name;
|
||||
if (LLAvatarNameCache::get(agent_id, &av_name))
|
||||
{
|
||||
// customize label string based on agent SLapp suffix
|
||||
if (LLStringUtil::endsWith(url, "/mute"))
|
||||
{
|
||||
return LLTrans::getString("SLappAgentMute") + " " + full_name;
|
||||
}
|
||||
if (LLStringUtil::endsWith(url, "/unmute"))
|
||||
{
|
||||
return LLTrans::getString("SLappAgentUnmute") + " " + full_name;
|
||||
}
|
||||
if (LLStringUtil::endsWith(url, "/im"))
|
||||
{
|
||||
return LLTrans::getString("SLappAgentIM") + " " + full_name;
|
||||
}
|
||||
if (LLStringUtil::endsWith(url, "/pay"))
|
||||
{
|
||||
return LLTrans::getString("SLappAgentPay") + " " + full_name;
|
||||
}
|
||||
if (LLStringUtil::endsWith(url, "/offerteleport"))
|
||||
{
|
||||
return LLTrans::getString("SLappAgentOfferTeleport") + " " + full_name;
|
||||
}
|
||||
if (LLStringUtil::endsWith(url, "/requestfriend"))
|
||||
{
|
||||
return LLTrans::getString("SLappAgentRequestFriend") + " " + full_name;
|
||||
}
|
||||
return full_name;
|
||||
std::string label = av_name.getCompleteName();
|
||||
|
||||
// handle suffixes like /mute or /offerteleport
|
||||
label = localize_slapp_label(url, label);
|
||||
return label;
|
||||
}
|
||||
else
|
||||
{
|
||||
gCacheName->get(agent_id, FALSE,
|
||||
boost::bind(&LLUrlEntryAgent::onAgentNameReceived,
|
||||
this, _1, _2, _3, _4));
|
||||
LLAvatarNameCache::get(agent_id,
|
||||
boost::bind(&LLUrlEntryAgent::onAvatarNameCache,
|
||||
this, _1, _2));
|
||||
addObserver(agent_id_string, url, cb);
|
||||
return LLTrans::getString("LoadingData");
|
||||
}
|
||||
}
|
||||
|
||||
LLStyle::Params LLUrlEntryAgent::getStyle() const
|
||||
{
|
||||
LLStyle::Params style_params = LLUrlEntryBase::getStyle();
|
||||
style_params.color = LLUIColorTable::instance().getColor("AgentLinkColor");
|
||||
style_params.readonly_color = LLUIColorTable::instance().getColor("AgentLinkColor");
|
||||
return style_params;
|
||||
}
|
||||
|
||||
std::string localize_slapp_label(const std::string& url, const std::string& full_name)
|
||||
{
|
||||
// customize label string based on agent SLapp suffix
|
||||
if (LLStringUtil::endsWith(url, "/mute"))
|
||||
{
|
||||
return LLTrans::getString("SLappAgentMute") + " " + full_name;
|
||||
}
|
||||
if (LLStringUtil::endsWith(url, "/unmute"))
|
||||
{
|
||||
return LLTrans::getString("SLappAgentUnmute") + " " + full_name;
|
||||
}
|
||||
if (LLStringUtil::endsWith(url, "/im"))
|
||||
{
|
||||
return LLTrans::getString("SLappAgentIM") + " " + full_name;
|
||||
}
|
||||
if (LLStringUtil::endsWith(url, "/pay"))
|
||||
{
|
||||
return LLTrans::getString("SLappAgentPay") + " " + full_name;
|
||||
}
|
||||
if (LLStringUtil::endsWith(url, "/offerteleport"))
|
||||
{
|
||||
return LLTrans::getString("SLappAgentOfferTeleport") + " " + full_name;
|
||||
}
|
||||
if (LLStringUtil::endsWith(url, "/requestfriend"))
|
||||
{
|
||||
return LLTrans::getString("SLappAgentRequestFriend") + " " + full_name;
|
||||
}
|
||||
return full_name;
|
||||
}
|
||||
|
||||
|
||||
std::string LLUrlEntryAgent::getIcon(const std::string &url)
|
||||
{
|
||||
// *NOTE: Could look up a badge here by calling getIDStringFromUrl()
|
||||
// and looking up the badge for the agent.
|
||||
return mIcon;
|
||||
}
|
||||
|
||||
//
|
||||
// LLUrlEntryAgentName describes a Second Life agent name Url, e.g.,
|
||||
// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/(completename|displayname|username)
|
||||
// x-grid-location-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/(completename|displayname|username)
|
||||
//
|
||||
LLUrlEntryAgentName::LLUrlEntryAgentName()
|
||||
{}
|
||||
|
||||
void LLUrlEntryAgentName::onAvatarNameCache(const LLUUID& id,
|
||||
const LLAvatarName& av_name)
|
||||
{
|
||||
std::string label = getName(av_name);
|
||||
// received the agent name from the server - tell our observers
|
||||
callObservers(id.asString(), label, mIcon);
|
||||
}
|
||||
|
||||
std::string LLUrlEntryAgentName::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 agent_id_string = getIDStringFromUrl(url);
|
||||
if (agent_id_string.empty())
|
||||
{
|
||||
// something went wrong, just give raw url
|
||||
return unescapeUrl(url);
|
||||
}
|
||||
|
||||
LLUUID agent_id(agent_id_string);
|
||||
if (agent_id.isNull())
|
||||
{
|
||||
return LLTrans::getString("AvatarNameNobody");
|
||||
}
|
||||
|
||||
LLAvatarName av_name;
|
||||
if (LLAvatarNameCache::get(agent_id, &av_name))
|
||||
{
|
||||
return getName(av_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
LLAvatarNameCache::get(agent_id,
|
||||
boost::bind(&LLUrlEntryAgentCompleteName::onAvatarNameCache,
|
||||
this, _1, _2));
|
||||
addObserver(agent_id_string, url, cb);
|
||||
return LLTrans::getString("LoadingData");
|
||||
}
|
||||
}
|
||||
|
||||
LLStyle::Params LLUrlEntryAgentName::getStyle() const
|
||||
{
|
||||
// don't override default colors
|
||||
return LLStyle::Params().is_link(false);
|
||||
}
|
||||
|
||||
//
|
||||
// LLUrlEntryAgentCompleteName describes a Second Life agent complete name Url, e.g.,
|
||||
// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/completename
|
||||
// x-grid-location-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/completename
|
||||
//
|
||||
LLUrlEntryAgentCompleteName::LLUrlEntryAgentCompleteName()
|
||||
{
|
||||
mPattern = boost::regex(APP_HEADER_REGEX "/agent/[\\da-f-]+/completename",
|
||||
boost::regex::perl|boost::regex::icase);
|
||||
}
|
||||
|
||||
std::string LLUrlEntryAgentCompleteName::getName(const LLAvatarName& avatar_name)
|
||||
{
|
||||
return avatar_name.getCompleteName();
|
||||
}
|
||||
|
||||
//
|
||||
// LLUrlEntryAgentDisplayName describes a Second Life agent display name Url, e.g.,
|
||||
// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/displayname
|
||||
// x-grid-location-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/displayname
|
||||
//
|
||||
LLUrlEntryAgentDisplayName::LLUrlEntryAgentDisplayName()
|
||||
{
|
||||
mPattern = boost::regex(APP_HEADER_REGEX "/agent/[\\da-f-]+/displayname",
|
||||
boost::regex::perl|boost::regex::icase);
|
||||
}
|
||||
|
||||
std::string LLUrlEntryAgentDisplayName::getName(const LLAvatarName& avatar_name)
|
||||
{
|
||||
return avatar_name.mDisplayName;
|
||||
}
|
||||
|
||||
//
|
||||
// LLUrlEntryAgentUserName describes a Second Life agent user name Url, e.g.,
|
||||
// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/username
|
||||
// x-grid-location-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/username
|
||||
//
|
||||
LLUrlEntryAgentUserName::LLUrlEntryAgentUserName()
|
||||
{
|
||||
mPattern = boost::regex(APP_HEADER_REGEX "/agent/[\\da-f-]+/username",
|
||||
boost::regex::perl|boost::regex::icase);
|
||||
}
|
||||
|
||||
std::string LLUrlEntryAgentUserName::getName(const LLAvatarName& avatar_name)
|
||||
{
|
||||
return avatar_name.mUsername.empty() ? avatar_name.getLegacyName() : avatar_name.mUsername;
|
||||
}
|
||||
|
||||
//
|
||||
// LLUrlEntryGroup Describes a Second Life group Url, e.g.,
|
||||
// secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/about
|
||||
|
|
@ -436,18 +618,16 @@ LLUrlEntryGroup::LLUrlEntryGroup()
|
|||
mMenuName = "menu_url_group.xml";
|
||||
mIcon = "Generic_Group";
|
||||
mTooltip = LLTrans::getString("TooltipGroupUrl");
|
||||
mColor = LLUIColorTable::instance().getColor("GroupLinkColor");
|
||||
}
|
||||
|
||||
|
||||
|
||||
void LLUrlEntryGroup::onGroupNameReceived(const LLUUID& id,
|
||||
const std::string& first,
|
||||
const std::string& last,
|
||||
BOOL is_group)
|
||||
const std::string& name,
|
||||
bool is_group)
|
||||
{
|
||||
// received the group name from the server - tell our observers
|
||||
callObservers(id.asString(), first);
|
||||
callObservers(id.asString(), name, mIcon);
|
||||
}
|
||||
|
||||
LLUUID LLUrlEntryGroup::getID(const std::string &string) const
|
||||
|
|
@ -483,14 +663,23 @@ std::string LLUrlEntryGroup::getLabel(const std::string &url, const LLUrlLabelCa
|
|||
}
|
||||
else
|
||||
{
|
||||
gCacheName->get(group_id, TRUE,
|
||||
gCacheName->getGroup(group_id,
|
||||
boost::bind(&LLUrlEntryGroup::onGroupNameReceived,
|
||||
this, _1, _2, _3, _4));
|
||||
this, _1, _2, _3));
|
||||
addObserver(group_id_string, url, cb);
|
||||
return LLTrans::getString("LoadingData");
|
||||
}
|
||||
}
|
||||
|
||||
LLStyle::Params LLUrlEntryGroup::getStyle() const
|
||||
{
|
||||
LLStyle::Params style_params = LLUrlEntryBase::getStyle();
|
||||
style_params.color = LLUIColorTable::instance().getColor("GroupLinkColor");
|
||||
style_params.readonly_color = LLUIColorTable::instance().getColor("GroupLinkColor");
|
||||
return style_params;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// LLUrlEntryInventory Describes a Second Life inventory Url, e.g.,
|
||||
// secondlife:///app/inventory/0e346d8b-4433-4d66-a6b0-fd37083abc4c/select
|
||||
|
|
@ -791,7 +980,6 @@ LLUrlEntryNoLink::LLUrlEntryNoLink()
|
|||
{
|
||||
mPattern = boost::regex("<nolink>[^<]*</nolink>",
|
||||
boost::regex::perl|boost::regex::icase);
|
||||
mDisabledLink = true;
|
||||
}
|
||||
|
||||
std::string LLUrlEntryNoLink::getUrl(const std::string &url) const
|
||||
|
|
@ -805,6 +993,12 @@ std::string LLUrlEntryNoLink::getLabel(const std::string &url, const LLUrlLabelC
|
|||
return getUrl(url);
|
||||
}
|
||||
|
||||
LLStyle::Params LLUrlEntryNoLink::getStyle() const
|
||||
{
|
||||
return LLStyle::Params();
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// LLUrlEntryIcon describes an icon with <icon>...</icon> tags
|
||||
//
|
||||
|
|
@ -812,7 +1006,6 @@ LLUrlEntryIcon::LLUrlEntryIcon()
|
|||
{
|
||||
mPattern = boost::regex("<icon\\s*>\\s*([^<]*)?\\s*</icon\\s*>",
|
||||
boost::regex::perl|boost::regex::icase);
|
||||
mDisabledLink = true;
|
||||
}
|
||||
|
||||
std::string LLUrlEntryIcon::getUrl(const std::string &url) const
|
||||
|
|
|
|||
|
|
@ -30,13 +30,17 @@
|
|||
|
||||
#include "lluuid.h"
|
||||
#include "lluicolor.h"
|
||||
#include "llstyle.h"
|
||||
#include <boost/signals2.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
class LLAvatarName;
|
||||
|
||||
typedef boost::signals2::signal<void (const std::string& url,
|
||||
const std::string& label)> LLUrlLabelSignal;
|
||||
const std::string& label,
|
||||
const std::string& icon)> LLUrlLabelSignal;
|
||||
typedef LLUrlLabelSignal::slot_type LLUrlLabelCallback;
|
||||
|
||||
///
|
||||
|
|
@ -71,10 +75,10 @@ public:
|
|||
virtual std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) { return url; }
|
||||
|
||||
/// Return an icon that can be displayed next to Urls of this type
|
||||
virtual std::string getIcon(const std::string &url) { return mIcon; }
|
||||
virtual std::string getIcon(const std::string &url);
|
||||
|
||||
/// Return the color to render the displayed text
|
||||
LLUIColor getColor() const { return mColor; }
|
||||
/// Return the style to render the displayed text
|
||||
virtual LLStyle::Params getStyle() const;
|
||||
|
||||
/// Given a matched Url, return a tooltip string for the hyperlink
|
||||
virtual std::string getTooltip(const std::string &string) const { return mTooltip; }
|
||||
|
|
@ -85,9 +89,6 @@ public:
|
|||
/// Return the name of a SL location described by this Url, if any
|
||||
virtual std::string getLocation(const std::string &url) const { return ""; }
|
||||
|
||||
/// is this a match for a URL that should not be hyperlinked?
|
||||
bool isLinkDisabled() const { return mDisabledLink; }
|
||||
|
||||
/// Should this link text be underlined only when mouse is hovered over it?
|
||||
virtual bool underlineOnHoverOnly(const std::string &string) const { return false; }
|
||||
|
||||
|
|
@ -100,7 +101,7 @@ protected:
|
|||
std::string getLabelFromWikiLink(const std::string &url) const;
|
||||
std::string getUrlFromWikiLink(const std::string &string) const;
|
||||
void addObserver(const std::string &id, const std::string &url, const LLUrlLabelCallback &cb);
|
||||
void callObservers(const std::string &id, const std::string &label);
|
||||
virtual void callObservers(const std::string &id, const std::string &label, const std::string& icon);
|
||||
|
||||
typedef struct {
|
||||
std::string url;
|
||||
|
|
@ -111,9 +112,7 @@ protected:
|
|||
std::string mIcon;
|
||||
std::string mMenuName;
|
||||
std::string mTooltip;
|
||||
LLUIColor mColor;
|
||||
std::multimap<std::string, LLUrlEntryObserver> mObservers;
|
||||
bool mDisabledLink;
|
||||
};
|
||||
|
||||
///
|
||||
|
|
@ -134,6 +133,7 @@ class LLUrlEntryHTTPLabel : public LLUrlEntryBase
|
|||
public:
|
||||
LLUrlEntryHTTPLabel();
|
||||
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
|
||||
/*virtual*/ std::string getTooltip(const std::string &string) const;
|
||||
/*virtual*/ std::string getUrl(const std::string &string) const;
|
||||
};
|
||||
|
||||
|
|
@ -162,18 +162,78 @@ public:
|
|||
///
|
||||
/// LLUrlEntryAgent Describes a Second Life agent Url, e.g.,
|
||||
/// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about
|
||||
///
|
||||
class LLUrlEntryAgent : public LLUrlEntryBase
|
||||
{
|
||||
public:
|
||||
LLUrlEntryAgent();
|
||||
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
|
||||
/*virtual*/ std::string getIcon(const std::string &url);
|
||||
/*virtual*/ std::string getTooltip(const std::string &string) const;
|
||||
/*virtual*/ LLStyle::Params getStyle() const;
|
||||
/*virtual*/ LLUUID getID(const std::string &string) const;
|
||||
/*virtual*/ bool underlineOnHoverOnly(const std::string &string) const;
|
||||
protected:
|
||||
/*virtual*/ void callObservers(const std::string &id, const std::string &label, const std::string& icon);
|
||||
private:
|
||||
void onAgentNameReceived(const LLUUID& id, const std::string& first,
|
||||
const std::string& last, BOOL is_group);
|
||||
void onAvatarNameCache(const LLUUID& id, const LLAvatarName& av_name);
|
||||
};
|
||||
|
||||
///
|
||||
/// LLUrlEntryAgentName Describes a Second Life agent name Url, e.g.,
|
||||
/// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/(completename|displayname|username)
|
||||
/// that displays various forms of user name
|
||||
/// This is a base class for the various implementations of name display
|
||||
class LLUrlEntryAgentName : public LLUrlEntryBase
|
||||
{
|
||||
public:
|
||||
LLUrlEntryAgentName();
|
||||
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
|
||||
/*virtual*/ LLStyle::Params getStyle() const;
|
||||
protected:
|
||||
// override this to pull out relevant name fields
|
||||
virtual std::string getName(const LLAvatarName& avatar_name) = 0;
|
||||
private:
|
||||
void onAvatarNameCache(const LLUUID& id, const LLAvatarName& av_name);
|
||||
};
|
||||
|
||||
|
||||
///
|
||||
/// LLUrlEntryAgentCompleteName Describes a Second Life agent name Url, e.g.,
|
||||
/// 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
|
||||
{
|
||||
public:
|
||||
LLUrlEntryAgentCompleteName();
|
||||
private:
|
||||
/*virtual*/ std::string getName(const LLAvatarName& avatar_name);
|
||||
};
|
||||
|
||||
///
|
||||
/// LLUrlEntryAgentDisplayName Describes a Second Life agent display name Url, e.g.,
|
||||
/// 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
|
||||
{
|
||||
public:
|
||||
LLUrlEntryAgentDisplayName();
|
||||
private:
|
||||
/*virtual*/ std::string getName(const LLAvatarName& avatar_name);
|
||||
};
|
||||
|
||||
///
|
||||
/// LLUrlEntryAgentUserName Describes a Second Life agent username Url, e.g.,
|
||||
/// 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
|
||||
{
|
||||
public:
|
||||
LLUrlEntryAgentUserName();
|
||||
private:
|
||||
/*virtual*/ std::string getName(const LLAvatarName& avatar_name);
|
||||
};
|
||||
|
||||
///
|
||||
|
|
@ -185,10 +245,10 @@ class LLUrlEntryGroup : public LLUrlEntryBase
|
|||
public:
|
||||
LLUrlEntryGroup();
|
||||
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
|
||||
/*virtual*/ LLStyle::Params getStyle() const;
|
||||
/*virtual*/ LLUUID getID(const std::string &string) const;
|
||||
private:
|
||||
void onGroupNameReceived(const LLUUID& id, const std::string& first,
|
||||
const std::string& last, BOOL is_group);
|
||||
void onGroupNameReceived(const LLUUID& id, const std::string& name, bool is_group);
|
||||
};
|
||||
|
||||
///
|
||||
|
|
@ -297,6 +357,7 @@ public:
|
|||
LLUrlEntryNoLink();
|
||||
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
|
||||
/*virtual*/ std::string getUrl(const std::string &string) const;
|
||||
/*virtual*/ LLStyle::Params getStyle() const;
|
||||
};
|
||||
|
||||
///
|
||||
|
|
|
|||
|
|
@ -37,16 +37,15 @@ LLUrlMatch::LLUrlMatch() :
|
|||
mIcon(""),
|
||||
mMenuName(""),
|
||||
mLocation(""),
|
||||
mDisabledLink(false),
|
||||
mUnderlineOnHoverOnly(false)
|
||||
{
|
||||
}
|
||||
|
||||
void LLUrlMatch::setValues(U32 start, U32 end, const std::string &url,
|
||||
const std::string &label, const std::string &tooltip,
|
||||
const std::string &icon, const LLUIColor& color,
|
||||
const std::string &icon, const LLStyle::Params& style,
|
||||
const std::string &menu, const std::string &location,
|
||||
bool disabled_link, const LLUUID& id, bool underline_on_hover_only)
|
||||
const LLUUID& id, bool underline_on_hover_only)
|
||||
{
|
||||
mStart = start;
|
||||
mEnd = end;
|
||||
|
|
@ -54,10 +53,10 @@ void LLUrlMatch::setValues(U32 start, U32 end, const std::string &url,
|
|||
mLabel = label;
|
||||
mTooltip = tooltip;
|
||||
mIcon = icon;
|
||||
mColor = color;
|
||||
mStyle = style;
|
||||
mStyle.link_href = url;
|
||||
mMenuName = menu;
|
||||
mLocation = location;
|
||||
mDisabledLink = disabled_link;
|
||||
mID = id;
|
||||
mUnderlineOnHoverOnly = underline_on_hover_only;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,11 +28,11 @@
|
|||
#ifndef LL_LLURLMATCH_H
|
||||
#define LL_LLURLMATCH_H
|
||||
|
||||
#include "linden_common.h"
|
||||
//#include "linden_common.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "lluicolor.h"
|
||||
#include "llstyle.h"
|
||||
|
||||
///
|
||||
/// LLUrlMatch describes a single Url that was matched within a string by
|
||||
|
|
@ -69,7 +69,7 @@ public:
|
|||
std::string getIcon() const { return mIcon; }
|
||||
|
||||
/// Return the color to render the displayed text
|
||||
LLUIColor getColor() const { return mColor; }
|
||||
LLStyle::Params getStyle() const { return mStyle; }
|
||||
|
||||
/// Return the name of a XUI file containing the context menu items
|
||||
std::string getMenuName() const { return mMenuName; }
|
||||
|
|
@ -77,21 +77,17 @@ public:
|
|||
/// return the SL location that this Url describes, or "" if none.
|
||||
std::string getLocation() const { return mLocation; }
|
||||
|
||||
/// is this a match for a URL that should not be hyperlinked?
|
||||
bool isLinkDisabled() const { return mDisabledLink; }
|
||||
|
||||
/// Should this link text be underlined only when mouse is hovered over it?
|
||||
bool underlineOnHoverOnly() const { return mUnderlineOnHoverOnly; }
|
||||
|
||||
/// Change the contents of this match object (used by LLUrlRegistry)
|
||||
void setValues(U32 start, U32 end, const std::string &url, const std::string &label,
|
||||
const std::string &tooltip, const std::string &icon,
|
||||
const LLUIColor& color, const std::string &menu,
|
||||
const std::string &location, bool disabled_link
|
||||
, const LLUUID& id, bool underline_on_hover_only = false );
|
||||
|
||||
const LLUUID& getID() const { return mID;}
|
||||
const LLStyle::Params& style, const std::string &menu,
|
||||
const std::string &location, const LLUUID& id,
|
||||
bool underline_on_hover_only = false );
|
||||
|
||||
const LLUUID& getID() const { return mID; }
|
||||
private:
|
||||
U32 mStart;
|
||||
U32 mEnd;
|
||||
|
|
@ -101,10 +97,8 @@ private:
|
|||
std::string mIcon;
|
||||
std::string mMenuName;
|
||||
std::string mLocation;
|
||||
|
||||
LLUUID mID;
|
||||
LLUIColor mColor;
|
||||
bool mDisabledLink;
|
||||
LLStyle::Params mStyle;
|
||||
bool mUnderlineOnHoverOnly;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -31,18 +31,25 @@
|
|||
#include <boost/regex.hpp>
|
||||
|
||||
// default dummy callback that ignores any label updates from the server
|
||||
void LLUrlRegistryNullCallback(const std::string &url, const std::string &label)
|
||||
void LLUrlRegistryNullCallback(const std::string &url, const std::string &label, const std::string& icon)
|
||||
{
|
||||
}
|
||||
|
||||
LLUrlRegistry::LLUrlRegistry()
|
||||
{
|
||||
mUrlEntry.reserve(20);
|
||||
|
||||
// Urls are matched in the order that they were registered
|
||||
registerUrl(new LLUrlEntryNoLink());
|
||||
registerUrl(new LLUrlEntryIcon());
|
||||
registerUrl(new LLUrlEntrySLURL());
|
||||
registerUrl(new LLUrlEntryHTTP());
|
||||
registerUrl(new LLUrlEntryHTTPLabel());
|
||||
registerUrl(new LLUrlEntryAgentCompleteName());
|
||||
registerUrl(new LLUrlEntryAgentDisplayName());
|
||||
registerUrl(new LLUrlEntryAgentUserName());
|
||||
// LLUrlEntryAgent*Name must appear before LLUrlEntryAgent since
|
||||
// LLUrlEntryAgent is a less specific (catchall for agent urls)
|
||||
registerUrl(new LLUrlEntryAgent());
|
||||
registerUrl(new LLUrlEntryGroup());
|
||||
registerUrl(new LLUrlEntryParcel());
|
||||
|
|
@ -71,10 +78,13 @@ LLUrlRegistry::~LLUrlRegistry()
|
|||
}
|
||||
}
|
||||
|
||||
void LLUrlRegistry::registerUrl(LLUrlEntryBase *url)
|
||||
void LLUrlRegistry::registerUrl(LLUrlEntryBase *url, bool force_front)
|
||||
{
|
||||
if (url)
|
||||
{
|
||||
if (force_front) // IDEVO
|
||||
mUrlEntry.insert(mUrlEntry.begin(), url);
|
||||
else
|
||||
mUrlEntry.push_back(url);
|
||||
}
|
||||
}
|
||||
|
|
@ -174,10 +184,9 @@ bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LL
|
|||
match_entry->getLabel(url, cb),
|
||||
match_entry->getTooltip(url),
|
||||
match_entry->getIcon(url),
|
||||
match_entry->getColor(),
|
||||
match_entry->getStyle(),
|
||||
match_entry->getMenuName(),
|
||||
match_entry->getLocation(url),
|
||||
match_entry->isLinkDisabled(),
|
||||
match_entry->getID(url),
|
||||
match_entry->underlineOnHoverOnly(url));
|
||||
return true;
|
||||
|
|
@ -210,10 +219,9 @@ bool LLUrlRegistry::findUrl(const LLWString &text, LLUrlMatch &match, const LLUr
|
|||
match.getLabel(),
|
||||
match.getTooltip(),
|
||||
match.getIcon(),
|
||||
match.getColor(),
|
||||
match.getStyle(),
|
||||
match.getMenuName(),
|
||||
match.getLocation(),
|
||||
match.isLinkDisabled(),
|
||||
match.getID(),
|
||||
match.underlineOnHoverOnly());
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -37,7 +37,9 @@
|
|||
#include <vector>
|
||||
|
||||
/// This default callback for findUrl() simply ignores any label updates
|
||||
void LLUrlRegistryNullCallback(const std::string &url, const std::string &label);
|
||||
void LLUrlRegistryNullCallback(const std::string &url,
|
||||
const std::string &label,
|
||||
const std::string &icon);
|
||||
|
||||
///
|
||||
/// LLUrlRegistry is a singleton that contains a set of Url types that
|
||||
|
|
@ -64,7 +66,9 @@ public:
|
|||
~LLUrlRegistry();
|
||||
|
||||
/// add a new Url handler to the registry (will be freed on destruction)
|
||||
void registerUrl(LLUrlEntryBase *url);
|
||||
/// optionally force it to the front of the list, making it take
|
||||
/// priority over other regular expression matches for URLs
|
||||
void registerUrl(LLUrlEntryBase *url, bool force_front = false);
|
||||
|
||||
/// get the next Url in an input string, starting at a given character offset
|
||||
/// your callback is invoked if the matched Url's label changes in the future
|
||||
|
|
|
|||
|
|
@ -102,11 +102,7 @@ LLView::Params::Params()
|
|||
left_pad("left_pad"),
|
||||
left_delta("left_delta", S32_MAX),
|
||||
from_xui("from_xui", false),
|
||||
user_resize("user_resize"),
|
||||
auto_resize("auto_resize"),
|
||||
needs_translate("translate"),
|
||||
min_width("min_width"),
|
||||
max_width("max_width"),
|
||||
xmlns("xmlns"),
|
||||
xmlns_xsi("xmlns:xsi"),
|
||||
xsi_schemaLocation("xsi:schemaLocation"),
|
||||
|
|
@ -218,7 +214,7 @@ void LLView::setUseBoundingRect( BOOL use_bounding_rect )
|
|||
}
|
||||
}
|
||||
|
||||
BOOL LLView::getUseBoundingRect()
|
||||
BOOL LLView::getUseBoundingRect() const
|
||||
{
|
||||
return mUseBoundingRect;
|
||||
}
|
||||
|
|
@ -1370,12 +1366,12 @@ void LLView::drawDebugRect()
|
|||
// drawing solids requires texturing be disabled
|
||||
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
|
||||
|
||||
if (mUseBoundingRect)
|
||||
if (getUseBoundingRect())
|
||||
{
|
||||
LLUI::translate((F32)mBoundingRect.mLeft - (F32)mRect.mLeft, (F32)mBoundingRect.mBottom - (F32)mRect.mBottom, 0.f);
|
||||
}
|
||||
|
||||
LLRect debug_rect = mUseBoundingRect ? mBoundingRect : mRect;
|
||||
LLRect debug_rect = getUseBoundingRect() ? mBoundingRect : mRect;
|
||||
|
||||
// draw red rectangle for the border
|
||||
LLColor4 border_color(0.25f, 0.25f, 0.25f, 1.f);
|
||||
|
|
@ -1573,7 +1569,7 @@ void LLView::updateBoundingRect()
|
|||
|
||||
LLRect cur_rect = mBoundingRect;
|
||||
|
||||
if (mUseBoundingRect)
|
||||
if (getUseBoundingRect())
|
||||
{
|
||||
mBoundingRect = calcBoundingRect();
|
||||
}
|
||||
|
|
@ -1583,7 +1579,7 @@ void LLView::updateBoundingRect()
|
|||
}
|
||||
|
||||
// give parent view a chance to resize, in case we just moved, for example
|
||||
if (getParent() && getParent()->mUseBoundingRect)
|
||||
if (getParent() && getParent()->getUseBoundingRect())
|
||||
{
|
||||
getParent()->updateBoundingRect();
|
||||
}
|
||||
|
|
@ -1607,7 +1603,7 @@ LLRect LLView::calcScreenBoundingRect() const
|
|||
{
|
||||
LLRect screen_rect;
|
||||
// get bounding rect, if used
|
||||
LLRect bounding_rect = mUseBoundingRect ? mBoundingRect : mRect;
|
||||
LLRect bounding_rect = getUseBoundingRect() ? mBoundingRect : mRect;
|
||||
|
||||
// convert to local coordinates, as defined by mRect
|
||||
bounding_rect.translate(-mRect.mLeft, -mRect.mBottom);
|
||||
|
|
@ -1692,7 +1688,9 @@ LLView* LLView::getChildView(const std::string& name, BOOL recurse) const
|
|||
child = getDefaultWidget<LLView>(name);
|
||||
if (!child)
|
||||
{
|
||||
child = LLUICtrlFactory::createDefaultWidget<LLView>(name);
|
||||
LLView::Params view_params;
|
||||
view_params.name = name;
|
||||
child = LLUICtrlFactory::create<LLView>(view_params);
|
||||
}
|
||||
}
|
||||
return child;
|
||||
|
|
@ -1736,14 +1734,14 @@ LLView* LLView::findChildView(const std::string& name, BOOL recurse) const
|
|||
|
||||
BOOL LLView::parentPointInView(S32 x, S32 y, EHitTestType type) const
|
||||
{
|
||||
return (mUseBoundingRect && type == HIT_TEST_USE_BOUNDING_RECT)
|
||||
return (getUseBoundingRect() && type == HIT_TEST_USE_BOUNDING_RECT)
|
||||
? mBoundingRect.pointInRect( x, y )
|
||||
: mRect.pointInRect( x, y );
|
||||
}
|
||||
|
||||
BOOL LLView::pointInView(S32 x, S32 y, EHitTestType type) const
|
||||
{
|
||||
return (mUseBoundingRect && type == HIT_TEST_USE_BOUNDING_RECT)
|
||||
return (getUseBoundingRect() && type == HIT_TEST_USE_BOUNDING_RECT)
|
||||
? mBoundingRect.pointInRect( x + mRect.mLeft, y + mRect.mBottom )
|
||||
: mRect.localPointInRect( x, y );
|
||||
}
|
||||
|
|
|
|||
|
|
@ -128,26 +128,22 @@ public:
|
|||
|
||||
Optional<std::string> layout;
|
||||
Optional<LLRect> rect;
|
||||
|
||||
// Historical bottom-left layout used bottom_delta and left_delta
|
||||
// for relative positioning. New layout "topleft" prefers specifying
|
||||
// based on top edge.
|
||||
Optional<S32> bottom_delta, // deprecated
|
||||
top_pad, // from last bottom to my top
|
||||
top_delta, // from last top to my top
|
||||
left_pad, // from last right to my left
|
||||
left_delta; // from last left to my left
|
||||
|
||||
// these are nested attributes for LLLayoutPanel
|
||||
Optional<S32> bottom_delta, // from last bottom to my bottom
|
||||
top_pad, // from last bottom to my top
|
||||
top_delta, // from last top to my top
|
||||
left_pad, // from last right to my left
|
||||
left_delta; // from last left to my left
|
||||
|
||||
//FIXME: get parent context involved in parsing traversal
|
||||
Ignored user_resize,
|
||||
auto_resize,
|
||||
needs_translate,
|
||||
min_width,
|
||||
max_width,
|
||||
xmlns,
|
||||
xmlns_xsi,
|
||||
xsi_schemaLocation,
|
||||
xsi_type;
|
||||
Ignored needs_translate, // cue for translation tools
|
||||
xmlns, // xml namespace
|
||||
xmlns_xsi, // xml namespace
|
||||
xsi_schemaLocation, // xml schema
|
||||
xsi_type; // xml schema type
|
||||
|
||||
Params();
|
||||
};
|
||||
|
|
@ -238,7 +234,7 @@ public:
|
|||
void setSoundFlags(U8 flags) { mSoundFlags = flags; }
|
||||
void setName(std::string name) { mName = name; }
|
||||
void setUseBoundingRect( BOOL use_bounding_rect );
|
||||
BOOL getUseBoundingRect();
|
||||
BOOL getUseBoundingRect() const;
|
||||
|
||||
ECursorType getHoverCursor() { return mHoverCursor; }
|
||||
|
||||
|
|
|
|||
|
|
@ -27,11 +27,28 @@
|
|||
|
||||
#include "llstring.h"
|
||||
#include "llfile.h"
|
||||
#include "llavatarnamecache.h"
|
||||
#include "llcachename.h"
|
||||
#include "lluuid.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
// Stub for LLAvatarNameCache
|
||||
bool LLAvatarNameCache::get(const LLUUID& agent_id, LLAvatarName *av_name)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void LLAvatarNameCache::get(const LLUUID& agent_id, callback_slot_t slot)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool LLAvatarNameCache::useDisplayNames()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// Stub implementation for LLCacheName
|
||||
//
|
||||
|
|
@ -47,7 +64,12 @@ BOOL LLCacheName::getGroupName(const LLUUID& id, std::string& group)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
boost::signals2::connection LLCacheName::get(const LLUUID& id, BOOL is_group, const LLCacheNameCallback& callback)
|
||||
boost::signals2::connection LLCacheName::get(const LLUUID& id, bool is_group, const LLCacheNameCallback& callback)
|
||||
{
|
||||
return boost::signals2::connection();
|
||||
}
|
||||
|
||||
boost::signals2::connection LLCacheName::getGroup(const LLUUID& id, const LLCacheNameCallback& callback)
|
||||
{
|
||||
return boost::signals2::connection();
|
||||
}
|
||||
|
|
@ -67,3 +89,105 @@ std::string LLTrans::getString(const std::string &xml_desc, const LLStringUtil::
|
|||
{
|
||||
return std::string();
|
||||
}
|
||||
|
||||
//
|
||||
// Stub implementation for LLStyle::Params::Params
|
||||
//
|
||||
|
||||
LLStyle::Params::Params()
|
||||
{
|
||||
}
|
||||
|
||||
//
|
||||
// Stub implementations for various LLInitParam classes
|
||||
//
|
||||
|
||||
namespace LLInitParam
|
||||
{
|
||||
BaseBlock::BaseBlock() {}
|
||||
BaseBlock::~BaseBlock() {}
|
||||
Param::Param(BaseBlock* enclosing_block)
|
||||
: mIsProvided(false)
|
||||
{
|
||||
const U8* my_addr = reinterpret_cast<const U8*>(this);
|
||||
const U8* block_addr = reinterpret_cast<const U8*>(enclosing_block);
|
||||
mEnclosingBlockOffset = (U16)(my_addr - block_addr);
|
||||
}
|
||||
void BaseBlock::setLastChangedParam(const Param& last_param, bool user_provided) {}
|
||||
|
||||
void BaseBlock::addParam(BlockDescriptor& block_data, const ParamDescriptor& in_param, const char* char_name){}
|
||||
param_handle_t BaseBlock::getHandleFromParam(const Param* param) const {return 0;}
|
||||
|
||||
void BaseBlock::init(BlockDescriptor& descriptor, BlockDescriptor& base_descriptor, size_t block_size)
|
||||
{
|
||||
descriptor.mCurrentBlockPtr = this;
|
||||
}
|
||||
bool BaseBlock::deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack){ return true; }
|
||||
bool BaseBlock::serializeBlock(Parser& parser, Parser::name_stack_t name_stack, const LLInitParam::BaseBlock* diff_block) const { return true; }
|
||||
bool BaseBlock::inspectBlock(Parser& parser, Parser::name_stack_t name_stack) const { return true; }
|
||||
bool BaseBlock::merge(BlockDescriptor& block_data, const BaseBlock& other, bool overwrite) { return true; }
|
||||
bool BaseBlock::validateBlock(bool emit_errors) const { return true; }
|
||||
|
||||
TypedParam<LLUIColor >::TypedParam(BlockDescriptor& descriptor, const char* name, const LLUIColor& value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count)
|
||||
: super_t(descriptor, name, value, func, min_count, max_count)
|
||||
{}
|
||||
|
||||
void TypedParam<LLUIColor>::setValueFromBlock() const
|
||||
{}
|
||||
|
||||
void TypedParam<LLUIColor>::setBlockFromValue()
|
||||
{}
|
||||
|
||||
void TypeValues<LLUIColor>::declareValues()
|
||||
{}
|
||||
|
||||
bool ParamCompare<const LLFontGL*, false>::equals(const LLFontGL* a, const LLFontGL* b)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
TypedParam<const LLFontGL*>::TypedParam(BlockDescriptor& descriptor, const char* _name, const LLFontGL*const value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count)
|
||||
: super_t(descriptor, _name, value, func, min_count, max_count)
|
||||
{}
|
||||
|
||||
void TypedParam<const LLFontGL*>::setValueFromBlock() const
|
||||
{}
|
||||
|
||||
void TypedParam<const LLFontGL*>::setBlockFromValue()
|
||||
{}
|
||||
|
||||
void TypeValues<LLFontGL::HAlign>::declareValues()
|
||||
{}
|
||||
|
||||
void TypeValues<LLFontGL::VAlign>::declareValues()
|
||||
{}
|
||||
|
||||
void TypeValues<LLFontGL::ShadowType>::declareValues()
|
||||
{}
|
||||
|
||||
void TypedParam<LLUIImage*>::setValueFromBlock() const
|
||||
{}
|
||||
|
||||
void TypedParam<LLUIImage*>::setBlockFromValue()
|
||||
{}
|
||||
|
||||
|
||||
bool ParamCompare<LLUIImage*, false>::equals(
|
||||
LLUIImage* const &a,
|
||||
LLUIImage* const &b)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ParamCompare<LLUIColor, false>::equals(const LLUIColor &a, const LLUIColor &b)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//static
|
||||
LLFontGL* LLFontGL::getFontDefault()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue